- Sync —
POST /v1/extractandPOST /v1/extract/file. One document in, results back in seconds. Best for real-time agent loops, screenshots, and small batches. - Async batch —
POST /v1/files+POST /v1/batches. Upload many files, submit them as one batch, poll for results. Best for bulk classification workloads where you don’t want to manage thousands of synchronous requests. See Batch processing.
Sync quickstart
Create an API key at extract.page/dashboard, then pick the ingress path that matches where your document lives:- By URL
- By upload
POST /v1/extract — JSON body with a url. Use this when the document is already reachable over HTTP (S3 presigned URL, public doc, CDN).Response shape
chunks is a flat array in reading order. Each chunk is one of:
text— a contiguous run of glyphs with the same font and size. Not a paragraph; a single paragraph typically spans several text chunks.table— a table.cellsis the structured representation (0-basedrow/col, withrow_span/col_spanfor merged cells);page_contentcarries a markdown rendering so plain-text consumers still get readable output.image— a figure extracted from the page, delivered as a URL or inline base64.
bbox—[x0, y0, x1, y1]in PDF user-space points.confidence— 0–100, present on OCR’d content (text chunks and table cells); native-text spans omit it.cells/n_rows/n_cols— populated on table chunks. Each cell is{ text, row, col, row_span, col_span, bbox, confidence, page_no }.merged_from_pages— present when a table spanning a page break was assembled into one chunk (1-based page numbers, ascending); each cell’spage_nocarries its own source page.image_url/image_mime— populated on image chunks (URL backend).image_b64— populated on image chunks (inline backend).
/v1/extract, /v1/extract/file), and $12 per 1,000 pages for schema extraction (/v1/extract/schema). Schema extraction is a single all-in charge that includes the parse — it is $12 total, not billed on top of the $3 parse. Remaining balance is visible in your dashboard.
Request options
For the URL route (POST /v1/extract), url is required; everything else is optional. For the upload route (POST /v1/extract/file), file is required and the remaining fields arrive as individual form fields instead of JSON.
| Field | Type | Default | Description |
|---|---|---|---|
url | string | — | URL route only. HTTP(S) URL to a PDF, PPTX, or DOCX. Input type is auto-detected from the extension. |
file | binary | — | Upload route only. Multipart file field. Input type is auto-detected from the first few bytes; the filename is advisory. |
extract_text | boolean | true | Set false to skip text spans (image chunks still returned if extract_images is true). |
extract_images | boolean | true | Set false to skip figure extraction; the response contains only text chunks. |
ocr | "auto" | "never" | "auto" | Deprecated — accepted but ignored. This field no longer changes behavior. |
- Max 1,000 pages per document. Larger docs fail with 413.
- Max 150 MB per document. Larger downloads fail with 413.
How pages are counted
Billing is per page. What counts as a page depends on the input type:- PDF: one page per PDF page.
- PPTX: one page per slide.
- DOCX: paginated on render; typically 250–400 words per page.
Large documents and bulk workloads
For documents over 1,000 pages or 150 MB, split client-side and concatenate thechunks arrays. The page_no field lets you offset page numbers across splits.
For bulk workloads (thousands of documents), use the async batch endpoints instead of looping POST /v1/extract/file — you upload each file once with a presigned PUT URL (bytes go straight to S3, never through our API), submit the whole set as one batch, and poll for completion. Same response schema, no per-doc HTTP round-trip overhead.
Need support for larger individual documents than 1,000 pages? Email hello@extract.page.
Authentication
Every request needs anX-API-KEY header. Keys are created and revoked from the dashboard. Each key:
- is bound to one customer account
- carries a quota expressed in pages (default 1,000 pages on the Free plan)
- is decremented atomically per request — the cost equals the number of pages in the extracted document
Errors
| Status | Meaning | What to do |
|---|---|---|
400 | Unsupported input or extraction failed | Check the url points to a supported format (PDF, PPTX, or DOCX) and that the document isn’t corrupted |
401 | Missing or invalid X-API-KEY | Check the header is set; re-create the key if revoked |
402 | Quota exceeded | Top up from the dashboard or wait for plan refresh |
404 | File or batch not found (async batch only) | Verify the file_id / batch_id is correct and not expired (3-day TTL) |
409 | File not uploaded, or result not ready (async batch only) | See Batch errors |
413 | Page limit or size limit exceeded | Split the document client-side |
422 | Request body invalid | Read detail[*].loc + detail[*].msg (FastAPI validation error shape); usually a missing url or a bad value for ocr |
429 | Rate limit exceeded | Back off and retry |
500 | Server error | Retry with exponential backoff; contact support if persistent |
503 | Billing service unavailable | Retry; we fail closed on billing to avoid silent overspend |
/v1/files, /v1/batches) return machine-readable error codes in the response body — see Batch errors for the full list, response shapes, and fixes.
Pass your own X-Request-Id header if you want to correlate logs with us; it shows up on our side too.
See the API Reference in the sidebar for a live playground and the full request/response schema.