DocumentationAPI v1

Zerodoc Documentation

Private, zero-retention document processing. Extract structured fields, classify document types, split batches and crop multi-document scans — all with confidence scores, processed in memory in the EU and discarded immediately. Never stored, never used to train a third-party model.

Quickstart

Three steps to your first structured response.

  1. 1
    Create an API key

    Create a free account and generate a key from your dashboard.

  2. 2
    Send a document

    POST a file (or URL) to /v1/extract with your key.

  3. 3
    Read the response

    Get structured fields, full text and a retention proof block.

curl -X POST "https://api.zerodoc.io/v1/extract" \
  -H "X-API-Key: zk_your_api_key" \
  -F "[email protected];type=application/pdf"

Authentication

Authenticate every request with your API key in the X-API-Key header. Keys are scoped to your account, created and revoked from your dashboard.

X-API-Key: zk_your_api_key

API reference

POSThttps://api.zerodoc.io/v1/extract

Extract text and structured fields from a document. Send a file or a url to fetch (if both are sent, the file wins). Supported types: PDF, PNG, JPEG, TIFF, WebP.

Parameters

NameTypeRequiredDescription
filefileConditionalMultipart file upload. Provide file or url; if both are sent, the file wins.
urlstringConditionalPublic URL to fetch the document from (SSRF-guarded). Used when no file is attached.
doc_typestringOptionalDocument type to extract. Defaults to invoice — currently the only extraction type.

Request example

curl -X POST "https://api.zerodoc.io/v1/extract" \
  -H "X-API-Key: zk_your_api_key" \
  -F "[email protected];type=application/pdf"

Response

A successful call returns 200 with the extraction result. The document is discarded the moment this response is sent.

{
  "request_id": "req_3abc...",
  "status": "ok",
  "processing_time_ms": 412,
  "doc_type": "invoice",
  "document": { "mime_type": "application/pdf", "page_count": 1, "size_bytes": 24872 },
  "text": "ACME Trading Ltd\nInvoice Number: INV-2026-0042\n...",
  "blocks": [
    { "text": "Total Due: 1200.00", "confidence": 0.99, "page": 0,
      "bbox": { "x": 0.05, "y": 0.82, "width": 0.30, "height": 0.03 } }
  ],
  "fields": {
    "invoice_number": { "value": "INV-2026-0042", "confidence": 0.9 },
    "total_amount": { "value": 1200.0, "confidence": 0.85 },
    "taxes": [ { "amount": 200.0, "rate": 20.0, "base": 1000.0 } ],
    "locale": { "country": "GB", "currency": "GBP" }
  },
  "extraction_warnings": [],
  "mean_confidence": 0.97,
  "extraction_confidence": 0.88,
  "retention": { "stored": false, "policy": "zero-retention" }
}

Response fields

FieldTypeDescription
request_idstringUnique identifier for the request.
statusstring"ok" on success.
processing_time_msnumberServer-side processing time in milliseconds.
doc_typestringDocument type extracted (echoes the request).
documentobjectmime_type, page_count and size_bytes of the input.
textstringFull extracted text.
blocksarrayText blocks, each with confidence and a normalized bounding box.
fieldsobjectStructured fields (invoice number, total, VAT, …), each with a value and confidence, plus derived composites like taxes[] and locale.
extraction_warningsarraySanity-check notes (e.g. a totals mismatch). Empty when all checks pass.
mean_confidencenumberHow well the page could be read: average OCR text confidence. 1.0 on any born-digital PDF — says nothing about field quality.
extraction_confidencenumberHow confident the extraction is: mean of the per-field confidences, after validation. null when no fields were found.
retentionobjectAlways { stored: false, policy: "zero-retention" } — proof nothing was persisted.

/v1/classify

POSThttps://api.zerodoc.io/v1/classify

Detect a document’s type so you can route it automatically. Returns the best match from invoice, credit_note, receipt, purchase_order, bank_statement, delivery_note — or an honest other when the evidence is too weak, rather than a guess.

Takes the same file / url input as /v1/extract, and shares the response envelope (request_id, status, document, retention, …). The response is deliberately lean — no document text or blocks — so it stays cheap to route on.

Request example

curl -X POST "https://api.zerodoc.io/v1/classify" \
  -H "X-API-Key: zk_your_api_key" \
  -F "[email protected];type=application/pdf"

Response

{
  "request_id": "req_9fe2...",
  "status": "ok",
  "processing_time_ms": 241,
  "document": { "mime_type": "application/pdf", "page_count": 1, "size_bytes": 18240 },
  "doc_type": "invoice",
  "confidence": 0.7,
  "candidates": [
    { "doc_type": "invoice", "score": 0.7 },
    { "doc_type": "receipt", "score": 0.3 }
  ],
  "retention": { "stored": false, "policy": "zero-retention" }
}
FieldTypeDescription
doc_typestringBest-matching type, or other when the evidence is too weak to name one.
confidencenumberEvidence share (0–1) behind the top type. A routing signal, not a calibrated probability.
candidatesarrayEvery type with any evidence, best first, each with doc_type and score.

/v1/split

POSThttps://api.zerodoc.io/v1/split

Detect document boundaries in a multi-page upload — one PDF containing several documents comes back as segments, each with its page range and type. Boundaries are found from page markers (“Page 1 of 3”), document numbers changing between pages, and per-page type changes; ties keep pages together rather than cutting a document in half.

Takes the same file / url input as /v1/extract, and shares the response envelope (request_id, status, document, retention, …). Feed each segment’s pages to /v1/extract to get its fields.

Request example

curl -X POST "https://api.zerodoc.io/v1/split" \
  -H "X-API-Key: zk_your_api_key" \
  -F "[email protected];type=application/pdf"

Response

{
  "request_id": "req_41bd...",
  "status": "ok",
  "processing_time_ms": 690,
  "document": { "mime_type": "application/pdf", "page_count": 5, "size_bytes": 88410 },
  "segments": [
    { "segment": 0, "pages": [0, 1], "page_count": 2, "doc_type": "invoice", "confidence": 0.82 },
    { "segment": 1, "pages": [2], "page_count": 1, "doc_type": "receipt", "confidence": 1.0 },
    { "segment": 2, "pages": [3, 4], "page_count": 2, "doc_type": "invoice", "confidence": 0.9 }
  ],
  "retention": { "stored": false, "policy": "zero-retention" }
}
FieldTypeDescription
segmentsarrayOne entry per detected document, in page order.
segments[].pagesarray0-indexed page numbers belonging to this document (matches blocks[].page on /v1/extract).
segments[].doc_typestringClassification of the segment’s own text (same types as /v1/classify, or other).
segments[].confidencenumberEvidence share behind the segment’s doc_type.

/v1/crop

POSThttps://api.zerodoc.io/v1/crop

Digitize several documents scanned on a single page — e.g. three receipts on one flatbed A4. Each detected item is returned as its own image, positioned and classified, ready to process individually.

Takes the same file / url input as /v1/extract, and shares the response envelope (request_id, status, document, retention, …). Accepts images and PDFs only (text/plain is rejected — there are no pixels to crop). Items need readable text and whitespace between them to be detected.

Request example

curl -X POST "https://api.zerodoc.io/v1/crop" \
  -H "X-API-Key: zk_your_api_key" \
  -F "[email protected];type=image/png"

Response

{
  "request_id": "req_efb3...",
  "status": "ok",
  "processing_time_ms": 14356,
  "document": { "mime_type": "image/png", "page_count": 1, "size_bytes": 402133 },
  "items": [
    { "item": 0, "page": 0,
      "bbox": { "x": 0.04, "y": 0.03, "width": 0.38, "height": 0.21 },
      "doc_type": "receipt", "confidence": 1.0,
      "image_mime_type": "image/png", "image_base64": "iVBORw0KGgo..." },
    { "item": 1, "page": 0,
      "bbox": { "x": 0.04, "y": 0.67, "width": 0.33, "height": 0.17 },
      "doc_type": "invoice", "confidence": 1.0,
      "image_mime_type": "image/png", "image_base64": "iVBORw0KGgo..." }
  ],
  "retention": { "stored": false, "policy": "zero-retention" }
}
FieldTypeDescription
itemsarrayOne entry per document found, in reading order.
items[].bboxobjectWhere the item sits on its source page (normalized 0–1).
items[].doc_typestringClassification of the item’s own text (same types as /v1/classify).
items[].image_base64stringThe cropped item as a base64-encoded PNG — returned inline, never stored.

Errors

Errors use standard HTTP status codes and return a JSON body with a detail field explaining what went wrong. Processing failures (500) include a request_id you can quote to support.

StatusMeaning
400No document provided, or the URL could not be fetched / was rejected.
401Missing or invalid API key.
413Document exceeds the maximum size (15 MB).
415Unsupported media type.
422Unsupported doc_type.
429Rate limit or monthly page quota exceeded — retry after the Retry-After header.
500Processing failed. The body carries a request_id — quote it to support.

Supported documents

Field extraction currently supports UK & EU invoices; more extraction types are on the roadmap. Classification (/v1/classify) already recognises receipts, purchase orders, bank statements, credit notes and delivery notes for routing.

File types
PDFPNGJPEGTIFFWebP
Extraction models (structured fields)
Invoice (UK & EU)Available
ReceiptSoon
Purchase orderSoon
Bank statementSoon

Zero-retention guarantee

Documents are received only by our EU processing service, held in memory for the duration of the request, and discarded immediately afterwards. No document or extracted content is written to disk or logged. Every response carries a retention block as proof. See the Security page for the full data flow and sub-processors.

Questions? Email support.