Public API
API documentation
Integrate SotaOCR into your AI agents and LLM pipelines. The API is asynchronous: upload a document, poll job status, then fetch the final result and, when needed, the page preview image used for OCR bbox coordinates.
Base URL
All public OCR endpoints are served from this host.
https://sotaocr.comAuthentication
All API requests require Bearer token authentication. You can create an API key in your dashboard.
Header
Authorization: Bearer YOUR_API_KEYAvailable routes
The OCR service exposes JSON API routes only: /v1/balance, /v1/extract, /v1/jobs/{job_id}, /v1/jobs/{job_id}/result, and /v1/jobs/{job_id}/pages/{page_number}/preview. Use GET /api/v1/info to read model_profiles before sending model_profile, so clients only use models enabled for the current service configuration. JSON results may include doc_preprocessor_res with angle plus page_preview metadata for bbox binding.
OCR preprocessing
Before the main OCR pass, the service automatically detects page orientation, rotates the page, and conditionally applies document unwarping. The detected angle is returned in doc_preprocessor_res.angle, and the preview endpoint returns the exact page image object whose coordinate space matches OCR bbox coordinates.
Polling and readiness
Poll at most once per second. Until OCR finishes, GET /v1/jobs/{job_id}/result returns 202 Accepted with error code result_not_ready.
Check page balance
/v1/balance Returns the authenticated account's current scan page balance. Use remaining_pages or total_affordable_pages to decide how many pages can still be processed.
curl -X GET https://sotaocr.com/v1/balance \ -H "Authorization: Bearer YOUR_API_KEY"
{
"entity_code": "scan_page",
"remaining_pages": 63,
"total_affordable_pages": 63,
"monthly_pages": {"total": 40, "allocated": 5, "remaining": 35},
"lifetime_pages": {"total": 20, "allocated": 2, "remaining": 18},
"tokens": {"total": 120, "allocated": 20, "remaining": 100, "affordable_pages": 10},
"token_price": 10
}1. Upload document
/v1/extract Uploads a PDF or image for OCR. On success returns 202 Accepted with job metadata including account_id, upstream_job_id, created_at, and updated_at.
- file: Document file (PDF, PNG, JPG, JPEG, WEBP, BMP, TIF, TIFF).
- page_ranges: (Optional) JSON string with an array of page ranges. Example: '[{"start":1,"end":3}]'
- model_profile: Optional OCR model profile. Omit the field to use the service default, or send one of the values returned in model_profiles by GET /api/v1/info.
curl -X POST https://sotaocr.com/v1/extract \
-H "Authorization: Bearer YOUR_API_KEY" \
-F "file=@document.pdf" \
-F 'page_ranges=[{"start":1,"end":5}]'{
"id": "job_123456789",
"account_id": "acct_123456789",
"status": "pending",
"page_count": 5,
"pages_completed": 0,
"model_profile": "fast",
"upstream_job_id": "up_job_987654321",
"created_at": "2026-03-24T12:00:00Z",
"updated_at": "2026-03-24T12:00:00Z"
}2. Check status
/v1/jobs/{job_id} Returns 200 OK with the current processing status plus account_id, upstream_job_id, page_count, pages_completed, created_at, and updated_at.
curl -X GET https://sotaocr.com/v1/jobs/job_123456789 \ -H "Authorization: Bearer YOUR_API_KEY"
{
"id": "job_123456789",
"account_id": "acct_123456789",
"status": "completed",
"page_count": 5,
"pages_completed": 5,
"upstream_job_id": "up_job_987654321",
"created_at": "2026-03-24T12:00:00Z",
"updated_at": "2026-03-24T12:00:08Z"
}3. Fetch result
/v1/jobs/{job_id}/result?format=markdown Returns 200 OK with extracted content when the job is completed. For format=json, each page may include doc_preprocessor_res with angle and page_preview metadata describing the bbox coordinate space. Before that, the endpoint returns 202 Accepted with error code result_not_ready.
- format: (Optional) Response format: json, markdown, or text. Defaults to json.
curl -X GET "https://sotaocr.com/v1/jobs/job_123456789/result?format=markdown" \ -H "Authorization: Bearer YOUR_API_KEY"
{
"job_id": "job_123456789",
"format": "json",
"page_count": 1,
"content": "{\"job_id\":\"job_123456789\",\"page_count\":1,\"pages\":[{\"page_number\":1,\"status\":\"completed\",\"text\":\"Ivan Matveev\",\"doc_preprocessor_res\":{\"angle\":0,\"model_settings\":{\"use_doc_orientation_classify\":true,\"use_doc_unwarping\":false}},\"page_preview\":{\"coordinate_space\":\"doc_preprocessed\",\"content_type\":\"image/png\",\"width\":1192,\"height\":1684},\"raw_result\":{}}]}"
}4. Fetch page preview for bbox overlays
/v1/jobs/{job_id}/pages/{page_number}/preview Returns the PNG page image after automatic rotation and optional unwarping. This is the exact image object you should render behind OCR bbox overlays.
curl -X GET https://sotaocr.com/v1/jobs/job_123456789/pages/1/preview \ -H "Authorization: Bearer YOUR_API_KEY" \ --output page_0001_preview.png
HTTP/1.1 200 OK Content-Type: image/png Content-Disposition: inline; filename="page_0001_preview.png" (binary PNG bytes in the same coordinate space as OCR bbox)
API errors
Most error responses use {"error":{"code":"...","message":"..."}}. insufficient_balance also includes entity_code, requested_units, and available_units.
- 400 Bad Request: Invalid multipart payload, missing file, invalid page_ranges, or invalid document. Error code: bad_request.
- 401 Unauthorized: Missing or invalid Bearer token. Error code: unauthorized.
- 403 Forbidden: API access required or insufficient balance. Error codes: api_access_required or insufficient_balance.
- 404 Not Found: Unknown job ID or cross-account access. Error code: job_not_found.
- 415 Unsupported Media Type: Unsupported uploaded file type. Error code: unsupported_media.
- 502 Bad Gateway: OCR upstream is unavailable or job sync failed. Error code: upstream_unavailable.
Ready to integrate?
Create an API key in the dashboard and get free pages for testing.