Documentation menu

API · Documents

Submit a document

POST /api/v1/documents $0.025/page (layout) or $0.004/page (read), + tokens for what you switch on

Send multipart/form-data with file (or several files[]) and an optional options field containing a JSON DocumentOptions object, or a JSON body with a url to fetch. Poll poll_url until status is completed or failed.

With no options the document is read (text, tables, key/value pairs and layout for every page) and its figures and picture-heavy pages are turned into images. That is all: no AI model runs, result is null, and you pay for the pages. Everything else is opt-in: embeddings makes vectors, extraction has the model fill result.data (built-in fields and/or your own schema), and queries has it answer questions.

Body

Send the document one of 2 ways. Pick one: each has its own fields, and "required" means required for that way.

multipart/form-data

The file comes from your computer or server. Send it as file (or several as files[]); there is no url. Options go in their own options part, as a JSON string.

  • file string optional

    The document: a PDF, image or Office file. Send file or files[].

  • files array of string optional

    Up to 10 documents at once, as repeated files[] parts. Each becomes its own document.

  • options string optional

    Processing options, as a JSON string in its own form part. Every option is optional.

    8 properties
    • analysis layout | read optional default layout

      How the pages are read. layout ($0.025/page) also finds tables, key/value pairs, figures and reading order. read ($0.004/page) is OCR only, about six times cheaper: pages come back without tables, key/value pairs or figures, and markdown: true with it is a 422. Example: "analysis": "read".

    • embeddings true | EmbeddingOptions optional

      Make a vector for every page, for your own search or model. Off unless you send it: true for the defaults (one 1,024-number vector per page), or an object to choose the settings. Billed as compass.input. Read them from GET /documents/{id}/pages?include=embeddings. Example: "embeddings": true.

      2 properties
      • dimensions 1024 | 512 | 256 optional default 1024

        Vector length. Compass is trained so shorter vectors stay usable: 512 and 256 cut storage and index size at a small accuracy cost. Pick one per corpus — you cannot compare vectors of different lengths. Example: "dimensions": 256.

      • granularity page optional default page

        page embeds each page as one vector (from up to its first 20,000 bytes of text), returned by GET /documents/{id}/pages?include=embeddings.

    • extraction ExtractionOptions optional

      Have the model fill result.data: any of Northdoc's built-in fields (summary, parties, dates and more), your own JSON schema, or both. Off unless you send it. Name at least one field or give a schema. Example: "extraction": {"fields": ["summary", "parties"]}.

      4 properties
      • fields array of title | document_type | summary | dates | parties | amounts | key_facts optional

        Built-in fields, each with a fixed shape in result.data:

        • title — the title or heading, a string.
        • document_type — what kind of document it is (invoice, contract, letter…), a string.
        • summary — two or three sentences on what it says.
        • dates — [{label, date}], dates in ISO 8601 where possible.
        • parties — [{name, role}], the people and organisations involved.
        • amounts — [{label, amount, currency}], the money in it.
        • key_facts — the most important facts, one short sentence each.

        Only the fields you name come back. A value the document does not confirm is left out, never guessed. Example: "fields": ["summary", "parties", "dates"].

      • instructions string optional

        Free-text guidance for ambiguous fields — which of two totals to take, what to do when a field is missing, how to normalise dates. Example: "instructions": "Use the invoice date, not the print date."

        at most 4000 characters

      • per_page boolean optional default false

        Run the extraction separately on every page instead of once over the whole document. Each page's result appears on that page (result in GET /documents/{id}/pages) as well as under result.pages. Costs roughly one extraction per page — use it for documents that are a stack of independent records, not for one contract spanning pages. Up to 200 pages; a longer document fails with error.type: document_too_large.

      • schema object optional

        Your own JSON Schema (type: object) for result.data to follow. Nested objects and arrays work, so line items and tables come back structured. Mark the fields you depend on as required.

    • images boolean optional default true

      Take pictures of the document: figures (charts, diagrams, photos) are cropped from their pages, and a whole page is kept when pictures cover at least half of it or it has fewer than 25 words (scans, signature and stamp pages, handwriting). Tiny figures (under 1.5% of the page, like logos) and blank pages are skipped. Download them with GET /documents/{id}/images, or with each page from GET /documents/{id}/pages?include=image_data. Covered by the page price.

      When the model runs it reads the pictures where they sit in the text. They are billed as input tokens then (about width × height / 750 each, at most ~1,600); one request carries at most 20 images and 10 MB, and past that the largest are kept and result.warnings says how many were left out.

      Works on PDFs, and on PNG and JPEG uploads (under 3.75 MB and 8000px, kept as the page image). TIFF, BMP, HEIF and Office files have no pictures taken. false takes none. Example: "images": false.

    • markdown boolean optional default false

      Also produce a markdown rendering of the whole document, read with GET /documents/{id}?include=markdown. Needs analysis: layout. Same page price. Example: "markdown": true.

    • model auto | swift | summit optional default auto

      Which Northdoc model reads the document, when one runs (for an extraction or queries).

      • swift — fast and economical, for everyday documents up to about 180k tokens (roughly 300 pages of dense text).
      • summit — the most capable, for long or dense legal and financial documents, up to about 900k tokens.
      • auto (the default) — swift up to about 150k tokens, summit beyond that.

      Pin summit when accuracy on hard documents matters most; pin swift to cap cost. A document too long for swift is accepted, read and charged for its pages, then fails at extracting with error.type: document_too_large; auto moves to summit instead. model.used on the document says which one ran (northdoc-swift-1 or northdoc-summit-1).

      Swift and Summit are kept current: when a better model becomes available the name moves to it and the version in model.used goes up (northdoc-swift-2), with no change to the API. Example: "model": "summit".

    • queries array of string optional

      Questions the model answers while the document is processed, returned in order under result.answers. Each question once: the same question twice is a 422. Cheaper than one POST /documents/{id}/queries per question because the document is read once for all of them. Use the queries endpoint for follow-ups you only think of later. Example: "queries": ["What is the total?", "When is it due?"].

      at most 50 items

    • retention_seconds integer optional default 86400

      How long results are kept once the document completes: expires_at is completed_at plus this many seconds. A result you have never fetched is kept for at least 24 hours after it completes, however short this is, so a short retention never deletes a result nobody has read. Reading a result does not move expires_at.

      0 means keep indefinitely, which only plans with limits.max_retention_seconds == 0 may do; on capped plans 0 is clamped to the plan limit and anything larger is a 422. Read the ceiling from GET /account. After it lapses the document returns 410 document_expired. Example: "retention_seconds": 3600.

      at least 0

Returns 202

Accepted for processing. A single file or url returns the document itself; a batch returns {"documents": [...]} with one entry per file, in order. Batch entries are independent — a file that is rejected comes back as {"error": {...}} in its slot while the others are still accepted, so check each one.

  • id string

    The document's id. Keep it: every other call needs it.

  • object string

    Always document.

  • estimated_cost_micro integer

    Credit held while it runs, in micro-USD. You are charged the real cost at the end. null for a URL until it has been downloaded.

  • poll_url string

    Where to check on it: GET /documents/{id}.

  • status string

    queued: it has not started yet.

Errors

  • 401

    Missing, revoked or expired key

  • 402

    No credits left, or (for an upload) not enough for its estimated cost. A URL document or a question whose estimate the credit cannot cover is accepted and then fails with error.type: insufficient_credits.

  • 413

    The file is over the plan's upload limit (or the request body over the server limit)

  • 415

    Not a PDF, PNG, JPEG, TIFF, BMP, HEIF, DOCX, XLSX or PPTX

  • 422

    Body or options failed validation (details lists the fields), or the document is too large (document_too_large)

  • 429

    Per-second burst limit for the plan exceeded; retry after Retry-After seconds

Every error has the same shape. See Errors.