Document extraction API quickstart

The docRefinery document extraction API takes a PDF or image and returns structured fields with confidence scores. It works in two calls: submit the file, which gives you a trace_id, then poll that trace_id until the run finishes. You need an API key and at least one document type chosen; requests go to https://api.docrefinery.com.

Updated

Before you start

Three things have to be in place before the first request. The second is not self-serve yet, so ask for it first.

  1. A docRefinery account. Sign up if you don't have one.
  2. API keys switched on for your account. docRefinery turns them on per account, separately from your plan, so contact us to ask. Until then, Settings has no API keys tab.
  3. Your document types chosen in the dashboard under Schemas & thresholds. You don't send a field list with each request: the API reads the fields your account has set for that type of document.

Create an API key

Open Settings, then API keys, and choose Create key. Give it a name and an expiry. The secret starts with dbk_live_ and is shown once, so copy it before you close the dialog. Organisation owners and admins can create keys; authentication has the details.

Set these once in your shell
export DOCREFINERY_API="https://api.docrefinery.com"
export DOCREFINERY_API_KEY="dbk_live_your_secret"

Submit a document

Send the file as multipart form data in a part called file, with your key as a bearer token. The response comes back as soon as the document is queued, and the value you need from it is trace_id.

Submit with curl
curl -X POST "$DOCREFINERY_API/v1/runway/async" \
  -H "Authorization: Bearer $DOCREFINERY_API_KEY" \
  -F "[email protected]"
Response (excerpt, fictional values)
{
  "trace_id": "9f1c0a7e",
  "status": "queued",
  "wait_time_ms": 1800,
  "estimated_execution_time_utc": "2026-11-04T10:31:04Z"
}

Poll for the result

There are no webhooks, so you ask until the run settles. Call the poll endpoint every 2 seconds, which is the interval our own dashboard uses, and stop when status is fulfilled or completed (the result is ready), failed or error (it stopped), or awaiting_review (a person has to look at it first). Anything else means keep polling.

Poll with curl
curl "$DOCREFINERY_API/v1/runway/9f1c0a7e" \
  -H "Authorization: Bearer $DOCREFINERY_API_KEY"
Finished run (excerpt, fictional values)
{
  "status": "fulfilled",
  "files": ["invoice.pdf"],
  "document_type": "invoice",
  "document_confidence": 0.97,
  "result": {
    "fields": [
      { "text": "INV-2291", "alias": "invoice_number", "field_confidence": 0.97 }
    ],
    "extraction_approval": "auto",
    "low_confidence_fields": []
  }
}

This is an excerpt: real responses carry other keys. Build only on the keys described in these docs. Extract a document explains each one, including tables and flagged fields.

Field names and result shape

alias is a name you control. Each field has a Return as alias, set in the dashboard under Schemas & thresholds, and it comes back as the alias on that value. In the excerpt above, invoice_number is that name. Changing it relabels the value and leaves what is extracted alone.

The result shape is identical across document types: fields carry text, alias and field_confidence, and tables carry rows of the same cells. Code that reads an invoice also reads a bank statement or a passport. Return as has the rules and an excerpt.

The whole flow in Python

This script submits a file, polls until the run settles and prints what came back. It uses the requests library: docRefinery has no official SDK. The values are illustrative, and you should add your own error handling and an overall timeout.

extract.py
import os
import time

import requests

API = os.environ["DOCREFINERY_API"]
HEADERS = {"Authorization": f"Bearer {os.environ['DOCREFINERY_API_KEY']}"}
SETTLED = {"fulfilled", "completed", "failed", "error", "awaiting_review"}

with open("invoice.pdf", "rb") as document:
    submitted = requests.post(
        f"{API}/v1/runway/async",
        headers=HEADERS,
        files={"file": document},
        timeout=120,
    )
submitted.raise_for_status()
trace_id = submitted.json()["trace_id"]

while True:
    poll = requests.get(f"{API}/v1/runway/{trace_id}", headers=HEADERS, timeout=30)
    poll.raise_for_status()
    run = poll.json()
    if run["status"] in SETTLED:
        break
    time.sleep(2)

print(run["status"])
print((run.get("result") or {}).get("fields"))

The whole flow in JavaScript

The same flow for Node.js 20 or later, using the built-in fetch. Run it from your server, never from a web page: a browser would expose your key, and the API doesn't accept browser requests from other sites.

extract.mjs
import { openAsBlob } from "node:fs";

const API = process.env.DOCREFINERY_API;
const headers = { Authorization: "Bearer " + process.env.DOCREFINERY_API_KEY };
const SETTLED = ["fulfilled", "completed", "failed", "error", "awaiting_review"];

const form = new FormData();
form.append("file", await openAsBlob("invoice.pdf"), "invoice.pdf");

const submitted = await fetch(API + "/v1/runway/async", {
  method: "POST",
  headers,
  body: form,
});
if (!submitted.ok) throw new Error("Submit failed: " + submitted.status);
const { trace_id } = await submitted.json();

let run;
do {
  await new Promise((resolve) => setTimeout(resolve, 2000));
  const poll = await fetch(API + "/v1/runway/" + trace_id, { headers });
  if (!poll.ok) throw new Error("Poll failed: " + poll.status);
  run = await poll.json();
} while (!SETTLED.includes(run.status));

console.log(run.status);
console.log(run.result?.fields);

What to read next

Common questions

Is the docRefinery extraction API synchronous?

No. Submitting a document returns a trace_id straight away, and you poll for the result. There are no webhooks or websockets, so your code asks until the run settles. Polling every 2 seconds matches what the docRefinery dashboard does.

Do I send the list of fields with each request?

No. docRefinery has no per-request field list. Fields are set once per document type in the dashboard under Schemas & thresholds, including each field's Return as alias, so every system that uses your account gets the same fields back under the same names.

Is there an official docRefinery SDK?

No. The API is plain HTTPS with multipart uploads and JSON responses, so curl, the Python requests library or the fetch built into Node.js are all you need.

Related

Send your first document.

Make a free account and try the API on a file of your own.

100 pages a month free. No credit card, no sales call.