Document OCR
Upload a PDF, run OCR, and get extracted text or a searchable PDF back. Five requests from file to result.
Quickstart
Create a job, upload the PDF, start processing, poll for completion, and download the result.
FASTOCR_KEY="your-api-key"
# 1. Create a document job
curl -s -X POST https://api.fastocr.org/v1/documents \
-H "Authorization: Bearer $FASTOCR_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"filename":"scan.pdf","size_bytes":'$(wc -c < scan.pdf | tr -d ' ')'}'
# 2. Upload the file to the presigned URL (from step 1 response)
curl -s -X PUT "<upload_url>" \
-H "Content-Type: application/pdf" \
-T scan.pdf
# 3. Start processing
curl -s -X POST https://api.fastocr.org/v1/documents/<id>/start \
-H "Authorization: Bearer $FASTOCR_KEY"
# 4. Poll until ready (status: completed, partial, or failed)
curl -s https://api.fastocr.org/v1/documents/<id> \
-H "Authorization: Bearer $FASTOCR_KEY"
# 5. Download the result
curl -s https://api.fastocr.org/v1/documents/<id>/output?format=text \
-H "Authorization: Bearer $FASTOCR_KEY"Accepted files: PDF only, up to 1 GB.
Output formats: ?format=text for plain text, ?format=pdf for a searchable PDF.
Statuses: awaiting_upload → processing → completed or failed. Large documents may finish as partial with is_truncated: true.
/v1/documentsCreate a new document job and get a presigned upload URL.
Required headers
Idempotency-Key — a unique value per job. See Idempotency.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
| filename | string | Yes | Must end with .pdf. |
| size_bytes | integer | Yes | File size. Max 1,073,741,824 (1 GB). |
| sha256 | string | No | Hex-encoded SHA-256 checksum. |
| external_id | string | No | Your own correlation ID. |
Response 201
{
"id": "doc_a1b2c3d4e5f6",
"status": "awaiting_upload",
"upload_url": "https://s3.amazonaws.com/...",
"expires_at": "2025-01-15T13:00:00Z"
}/v1/documentsList your documents with optional filtering. See Pagination for query parameters.
Response 200
{
"documents": [
{
"id": "doc_a1b2c3d4e5f6",
"status": "completed",
"external_id": null,
"pages_billed": 5,
"pages_total": 10,
"pages_processed": 10,
"is_truncated": false,
"outputs": {
"text": { "available": true },
"pdf": { "available": true }
}
}
],
"next_cursor": null
}/v1/documents/{id}Get the current status and metadata for a single document.
Response 200
{
"id": "doc_a1b2c3d4e5f6",
"status": "completed",
"external_id": null,
"pages_billed": 5,
"pages_total": 10,
"pages_processed": 10,
"is_truncated": false,
"outputs": {
"text": { "available": true },
"pdf": { "available": true }
}
}Response fields
| Field | Type | Required | Description |
|---|---|---|---|
| id | string | Yes | Document job ID. |
| status | string | Yes | awaiting_upload, processing, completed, partial, or failed. |
| external_id | string? | No | Your correlation ID, if set on create. |
| pages_billed | integer | No | Pages charged against your quota. |
| pages_total | integer | No | Total pages in the document. |
| pages_processed | integer | No | Pages processed so far. |
| is_truncated | boolean | No | True if processing stopped before all pages. |
| outputs | object | No | Available output formats (text, pdf). |
| error | object | No | Present when status is failed. See Errors. |
/v1/documents/{id}/startStart OCR processing after the file has been uploaded. No request body required.
Response 202
{
"status": "processing"
}409 document_not_startable— the job is not in a startable state.400 upload_not_found— the file has not been uploaded yet.400 size_mismatch— uploaded file size does not matchsize_bytes.429 concurrency_limit— too many jobs in flight. Retry after theRetry-Afterheader (30s).
/v1/documents/{id}/outputGet a presigned download URL for the processed result.
Query parameters
| Field | Type | Required | Description |
|---|---|---|---|
| format | string | Yes | text or pdf. |
Response 200
{
"format": "text",
"url": "https://s3.amazonaws.com/...",
"expires_at": "2025-01-15T13:00:00Z",
"pages_billed": 5,
"pages_total": 10
}The presigned URL expires in 1 hour. If the job is not yet complete, a 409 document_not_ready error is returned.
/v1/documents/{id}Delete a document and its files. Deletion is asynchronous — the job transitions to deleting and is cleaned up in the background.
Response 202
{
"status": "deleting"
}Returns 409 document_processing if the document is currently being processed.