# Hanji Turn complex documents into AI-ready data Text, tables, and figures in one call. Best text accuracy, 2x faster than most parsers. Simple credit pricing: 1 credit/page for Parse, 4 for Parse + Extract, at $0.003/credit. ## Base URL `https://api.extract.page` ## Auth Send your key on every request: ``` X-API-KEY: ``` Grab one from the dashboard at https://hanji.dev/dashboard after signup. Free tier is 1,000 credits on signup (a parsed page costs 1 credit) with no card required. ## Endpoints Sync parse is `POST /v1/parse` and `POST /v1/parse/file`. Compatibility aliases `POST /v1/extract` and `POST /v1/extract/file` still work and return the same responses; prefer `/v1/parse` for new integrations. ### POST /v1/parse (hosted URL) JSON body with a `url` pointing at a document already on the public internet. ```bash $ curl https://api.extract.page/v1/parse \ -H "X-API-KEY: $EXTRACT_KEY" \ -H "Content-Type: application/json" \ -d '{"url": "https://cdn.extract.page/demo/overview-of-computer-science.pdf"}' { "chunks": [ { "page_content": "Attention Is All You Need", "page_no": 1, "bbox": [90.0, 94.0, 505.2, 118.4] }, { "page_content": "Ashish Vaswani", "page_no": 1, "bbox": [108.0, 132.0, 198.3, 143.1] }, { "page_content": "Noam Shazeer", "page_no": 1, "bbox": [210.0, 132.0, 292.1, 143.1] } ] } ``` ### POST /v1/parse/file (upload) Multipart upload when the bytes are in memory or on disk. ```bash $ curl https://api.extract.page/v1/parse/file \ -H "X-API-KEY: $EXTRACT_KEY" \ -F "file=@paper.pdf" { "chunks": [ { "page_content": "Attention Is All You Need", "page_no": 1, "bbox": [90.0, 94.0, 505.2, 118.4] }, { "page_content": "Ashish Vaswani", "page_no": 1, "bbox": [108.0, 132.0, 198.3, 143.1] }, { "page_content": "Noam Shazeer", "page_no": 1, "bbox": [210.0, 132.0, 292.1, 143.1] } ] } ``` ### POST /v1/extract/schema (structured fields) Pass a JSON schema alongside a `url` (or use `POST /v1/extract/schema/file` for uploads) to pull typed fields — invoice totals, claim numbers, form values — straight out of a document instead of post-processing chunks yourself. See the schema-extraction guide at https://docs.hanji.dev. Set `include_ocr_text: true` and the response additionally carries `ocr_text`: the whole document as a single text string in reading order — the same text `POST /v1/parse` returns as `content`. Fields and full text arrive from one call, so you can cross-check any extracted value against the raw read. The default response is unchanged. ### Async batch (large jobs) For bulk workloads, reserve file slots with `POST /v1/files`, submit them as one job with `POST /v1/batches`, then poll `GET /v1/batches/{id}`. Handles up to 1,000,000 pages. See the batch guide at https://docs.hanji.dev. In production, prefer webhooks over polling: pass `webhook: {"mode": "svix"}` on `POST /v1/batches` to get a signed `batch.update` event (Svix-wire-compatible) when the batch finishes. Terminal statuses are `completed`, `partially_failed`, `failed`, `cancelled` — treat `partially_failed` as done-with-some-failures, not a failure. Register endpoints in the dashboard. Polling is rate-limited to 200 req/s per org. ## Quickstart ### Python (URL) ```python import requests res = requests.post( "https://api.extract.page/v1/parse", headers={"X-API-KEY": EXTRACT_KEY}, json={"url": "https://cdn.extract.page/demo/overview-of-computer-science.pdf"}, ).json() # res["chunks"][0] # { "page_content": "Attention Is All You Need", "page_no": 1, "bbox": [90.0, 94.0, 505.2, 118.4] } ``` ### Python (upload) ```python import requests with open("paper.pdf", "rb") as f: res = requests.post( "https://api.extract.page/v1/parse/file", headers={"X-API-KEY": EXTRACT_KEY}, files={"file": f}, ).json() # res["chunks"][0] # { "page_content": "Attention Is All You Need", "page_no": 1, "bbox": [90.0, 94.0, 505.2, 118.4] } ``` ### TypeScript (URL) ```ts const res = await fetch("https://api.extract.page/v1/parse", { method: "POST", headers: { "X-API-KEY": process.env.EXTRACT_KEY!, "Content-Type": "application/json", }, body: JSON.stringify({ url: "https://cdn.extract.page/demo/overview-of-computer-science.pdf" }), }).then((r) => r.json()); // res.chunks[0] // { page_content: "Attention Is All You Need", page_no: 1, bbox: [90.0, 94.0, 505.2, 118.4] } ``` ### TypeScript (upload) ```ts import { readFile } from "node:fs/promises"; const form = new FormData(); form.append("file", new Blob([await readFile("paper.pdf")]), "paper.pdf"); const res = await fetch("https://api.extract.page/v1/parse/file", { method: "POST", headers: { "X-API-KEY": process.env.EXTRACT_KEY! }, body: form, }).then((r) => r.json()); // res.chunks[0] // { page_content: "Attention Is All You Need", page_no: 1, bbox: [90.0, 94.0, 505.2, 118.4] } ``` ## Response shape A list of chunks. Each chunk carries: - `page_content` — the extracted text span - `page_no` — 1-indexed page number - `bbox` — [x0, y0, x1, y1] in PDF points - `image_url` — present on image chunks, points at our object store - `pdf_rendition_url` — DOCX/PPTX only: expiring URL of the PDF we paginated. Overlay `bbox` on this file, not on a Word/PowerPoint render of the original. Omitted for PDFs and images. Copy it to your own storage before the link expires. Table chunks additionally carry `cells` (structured `{text, row, col, row_span, col_span, bbox}` records) plus `n_rows`/`n_cols`, with `page_content` holding a markdown render. Pass `table_output_format: "cell_grid"` on the request to upgrade table chunks to true per-cell bounding boxes (`cells` becomes the primary representation; the default `"markdown"` keeps today's markdown-derived cells). A table whose cells cannot be localized keeps its markdown-derived cells and echoes `table_output_format: "markdown"` on that chunk only — the rest of the document is unaffected, and you can tell per table which representation you got. ## Whole-document content Pass `include_content: true` and the response additionally carries `content`: the entire parsed document as a single text string, concatenated in reading order (tables rendered as markdown in place, figures omitted). It is the document's own text end to end — not reformatted with markdown headings or page markers. Sync only; the default response without `include_content` is unchanged. ## RAG chunking Pass `chunking: "semantic"` (plus optional `chunk_size`, characters, default 1000, ±25% band) and the response additionally carries `segments`: groups of chunks ready to embed, split at semantic boundaries (headings, figures with captions, page breaks). Each segment has `content` (markdown; tables included as markdown tables, images not included), `char_count`, `pages`, and member records with `page_no`, `bbox`, and `source_index` into the flat `chunks` list. A table too large for one segment splits at row boundaries and every part remains a valid table (`table_part` records the covered rows). `page_dimensions` gives each page's size in the same units as every `bbox`. The default response without `chunking` is unchanged. ## Limits (synchronous) - 500 pages per request - 150 MB per request For larger jobs, the async endpoint handles batch jobs up to 1M pages. ## Typical latency Median latency on our public benchmark — 156 business PDFs, 13,671 pages — is 10.7s per document, the fastest of the eight providers measured. Single-page documents return in about 1.3s. Scanned pages take longer because OCR runs inline. See the Benchmarks section for the full suite. ## Trust and data handling | category | answer | |------------|---------------------| | compliance | HIPAA + BAA | | SOC 2 | Type II audit in progress; observation window closes 2026-09-15 (no report held yet) | | training | Never | | retention | Sync: never stored. Async: deleted after 3 days | | region | Core infrastructure: AWS us-east-1 (US) | We never train on customer data. Sync source documents are processed in memory and never stored. DOCX/PPTX parses additionally return a short-lived `pdf_rendition_url` (the PDF those bboxes refer to); copy it to your storage — the object is deleted after 3 days. Async batch uploads and results are stored for pickup and deleted automatically after 3 days. Extracted images (only created on request) are stored so `image_url` links keep working and are deleted on request. Full security page (retention by lane, encryption, subprocessors, PHI mode, responsible disclosure): https://hanji.dev/security ## Proven at scale 70,000,000+ pages processed. Built from [YouLearn](https://youlearn.ai)'s production document pipeline before becoming an API. ## Errors Every error returns JSON in the shape `{ "detail": "" }`. Correlate with support via the `X-Request-Id` response header. | status | meaning | retry? | |--------|--------------------------------------------|----------------| | 400 | malformed request body, or an unreadable file | no, fix input | | 401 | missing or invalid API key | no | | 402 | balance exhausted — top up in dashboard | no, top up | | 413 | payload exceeds 150 MB | no, split | | 422 | invalid request or schema JSON | no | | 429 | rate limited | yes, backoff | | 500 | server error | yes, backoff | | 503 | temporarily unavailable | yes, backoff | Retries are safe because extraction is stateless — but note that a successful request is billable usage, and a retry after a 5xx may double-bill if the first request actually succeeded server-side. Check your usage dashboard if retries surprise you. ## Pricing Full pricing page: https://hanji.dev/pricing ### Free — $0 1,000 credits · no card · lifetime. - Full API access from day one - Self-serve dashboard with usage - Email support - Parse 1 credit/page ($0.003/page), Parse + Extract 4 credits/page ($0.012/page), after the free tier ### Pay as you go — Parse 1 credit/page · Parse + Extract 4 credits/page ($0.003/credit) Simple credit pricing: Parse is 1 credit per page and Parse + Extract is 4 credits per page, at a flat $0.003/credit. No seat fees, no monthly minimums, no automatic complexity surcharges — plain text, dense tables, or a scanned form all bill the same, and OCR runs inline at no surcharge. - Schema extraction (`/v1/extract/schema`) is $0.012/page (4 credits/page), parse included - Top up from $9 ($9, $30, $99, $300 presets or any custom amount in $3 steps) — or set auto-recharge - Unlimited team seats at no extra cost - Async batch jobs up to 1M pages Keys keep working the moment a top-up lands. ### Custom — Enterprise For teams with higher workloads · volume discounts · SLAs. - Dedicated region + private networking - HIPAA + BAA available - Slack channel with engineering - Production SLAs and priority queues Email hello@hanji.dev. ## Benchmarks The landing page presents three benchmark views: a capability matrix, an accuracy benchmark, and a speed benchmark. ### Capability matrix The completeness win — source-grounded spans, bounding boxes, and mixed-format input in one call. | capability | Hanji | aws textract | llamaparse | reducto | |---------------------|---------|--------------|--------------|---------| | text extraction | yes | yes | yes | yes | | text accuracy | 87.5% | 74.1% | 67.6% | 75.2% | | per-span bbox | yes | yes | no | yes | | OCR | yes | yes | premium only | yes | | pptx / docx input | yes | no | no | no | | markdown output | no | no | yes | yes | LlamaParse OCR caveat: only in premium mode, with higher latency and credit cost than fast mode. ### Accuracy benchmark 87.5% text accuracy on 400 human-labeled gold pages across 7 document types, scored character-level — the highest of seven providers. Hanji also leads on word F1 (90.2%). | provider | text accuracy | word F1 | |--------------|---------------|---------| | Hanji | 87.5% | 90.2% | | pulse | 82.7% | 83.6% | | reducto | 75.2% | 77.1% | | aws textract | 74.1% | 76.3% | | docling | 72.5% | 77.7% | | llamaparse | 67.6% | 69.7% | | unstructured | 66.8% | 63.9% | ### Speed benchmark Lowest median per-document latency of every hosted provider tested, measured across the speed & coverage corpus (median of three runs each). Tested on born-digital papers, financial reports, scanned forms, image-heavy decks, multi-column layouts, large technical specs, and adversarial layouts. See "Typical latency" above for concrete per-document numbers. ## Custom benchmark Send us your docs. We'll show you how it performs on yours, not ours. Book a benchmark call to run the same eval on a representative corpus. ## FAQ **Do you have a BAA / HIPAA compliance?** Yes. HIPAA + BAA is available on request, and PHI runs in production under a signed BAA today. Talk to us about your compliance requirements. **Do you store my documents?** Sync documents are processed in memory and never stored. Async batch uploads and results are deleted automatically after 3 days. Extracted images are stored so your `image_url` links keep working. We never train on your data. The custom tier supports customer-managed encryption, configurable retention, and dedicated regions. **What file types can I send?** PDF, PPTX, DOCX, and images (PNG, JPEG, WebP, TIFF, HEIC/HEIF, BMP). Scanned PDFs and images are handled automatically. OCR runs inline with no separate surcharge. **Can I run a benchmark on my own documents?** Yes. Send us 20-50 representative documents, or bring them to your benchmark call and we'll run the eval live. Results will be back within a few days. Healthcare and other regulated docs are handled under BAA on a private pipeline. Book a benchmark call. **How does your pricing compare to AWS Textract or Reducto?** Simple credit pricing: parse is 1 credit per page and extract is 4 credits per page, at a flat $0.003 per credit — $0.003/page for Parse, $0.012/page for Parse + Extract, all-in. No seat fees, no monthly minimums, no hidden multipliers, no automatic complexity surcharges. Compared to providers whose per-page credit cost varies with page complexity (Reducto, LlamaParse) or by operation type (Textract, Azure DI), most teams find we're cheaper in total spend once you account for tables, forms, and OCR. We're happy to scope your monthly volume on a benchmark call. **What are the hard limits per request?** 500 pages and 150 MB per synchronous request. For larger jobs, we have an async endpoint that handles batch jobs up to 1M pages. **What throughput can you handle? Is there a rate limit?** Pages within a request are parsed concurrently. On our public benchmark — 156 business PDFs, 13,671 pages — median latency is 10.7s per document, the fastest of the eight providers measured. Across requests the platform autoscales to absorb bursts. Standard accounts have a default request rate that we raise for high-volume customers; the custom tier adds dedicated capacity with committed throughput and an uptime SLA. We'll size your target throughput on a benchmark call. **Can I self-host or deploy in a VPC?** Available on the custom tier. Dedicated regions, private networking, and on-prem options are available for teams with strict security or data residency requirements. Contact us at hello@hanji.dev. **Do you offer SLAs or dedicated capacity?** Yes. Available on the custom tier: negotiated rate per page, dedicated regions, private networking, production SLAs, and a Slack channel with the engineering team. Contact us at hello@hanji.dev. **What happens when I run out of balance?** The API returns 402 when your balance is exhausted. Top up your balance from the dashboard — $9, $30, $99, or $300 presets, or any custom amount in $3 steps (from $9) — or set auto-recharge so it never lapses. Keys keep working the moment a top-up lands. ## Contact - General: hello@hanji.dev - Docs: https://docs.hanji.dev - Dashboard: https://hanji.dev/dashboard