Reamline

API reference

Three endpoints. Post a fixed-width document, get JSON back.

Base URL https://reamline.com. Authenticate with an API key in the x-api-key header, or a session token as Authorization: Bearer.

Requests and responses are JSON throughout. Every request sends the document either as text (a plain string) or textB64 (base64 of the original bytes). Prefer textB64, for the reasons in encoding.

POST /v1/extract

Turn a document into JSON.

curl -s -X POST https://reamline.com/v1/extract \
  -H "Content-Type: application/json" -H "x-api-key: $KEY" \
  -d '{"templateId":"tpl_...","textB64":"..."}'
Field
textB64 or textThe document. Required.
templateIdWhich document type to use. Omit it and the service works it out from your recognition rules.
revisionPin to a specific published version. Defaults to the live one.
templateAn inline template object, instead of a stored one. Useful for testing without publishing.

The response carries one entry per document found:

{
  "template": "Austen Statement@3",
  "summary": { "documents": 63, "ok": 62, "warned": 1, "failed": 0 },
  "routed": "tpl_...",
  "documents": [
    {
      "index": 0,
      "status": "ok",
      "data": { "accountNumber": "A2R755", "totalOutstanding": "5059.68",
                "transactions": [ { "date": "14/04/2026", "outstandingValue": "2071.30" } ] },
      "issues": [],
      "diagnostics": { "pages": 1, "coverage": 0.97 }
    }
  ],
  "usage": { "transforms": 78, "limit": 100, "remaining": 22 }
}

routed appears only when the template was chosen rather than named.

Status
200Processed. Check summary, because a partly-bad batch still returns the good documents.
401Missing or rejected credentials.
404No published revision for that templateId.
422NO_TEMPLATE_MATCH. No recognition rule claimed the file; the body lists what was tried.
429LIMIT_REACHED. Monthly allowance used up.

Per-document status

ok, warned or failed, with issues explaining any that are not ok. A warning means the data is there but something did not add up; a failure means a declared check could not be evaluated at all.

This is why the response is a 200 with per-document status rather than an error for the whole batch: fifty-four good statements should not be held back by one bad page.

POST /v1/route

Ask which document type a file is, without processing it. Not charged.

curl -f -s -X POST https://reamline.com/v1/route \
  -H "Content-Type: application/json" -H "x-api-key: $KEY" \
  -d @payload.json
{
  "template": { "id": "tpl_...", "name": "Austen Statement", "revision": 3 },
  "priority": 100,
  "candidates": [
    { "template": "tpl_...", "name": "Austen Statement", "matched": true,  "priority": 100 },
    { "template": "tpl_...", "name": "Austen Invoice",   "matched": false, "priority": 100 }
  ]
}

A file nothing recognises is a 422, not a 200 with an empty answer. That way curl -f fails and a script working through a folder can set the file aside rather than silently doing nothing.

candidates lists every rule that was tried and whether it matched, which is what makes “no template matched” actionable rather than infuriating.

Only published versions are considered. A recognition rule you just added is in your draft until you press Publish.

If two document types match at the same priority, the response includes ambiguous naming both. The winner in that case is not meaningful, so give the more specific rule a higher priority.

GET /v1/health

No authentication. Useful for a monitor.

{ "ok": true, "engine": { "version": "0.1.0", "schemaVersion": "1.0" } }

GET /v1/usage

Your allowance this month.

{ "period": "2026-08", "transforms": 78, "requests": 80,
  "limit": 100, "remaining": 22, "plan": "free" }

Values in the output

Declared asYou get
stringTrimmed text.
moneyA decimal string such as "5059.68", never a JSON number.
decimalThe same, without currency conventions.
dateThe raw text by default; a normalised form if the template asks.

Money is a JSON string on purpose. The JSON spec does not fix a precision for numbers, and in practice almost every parser reads them into IEEE-754 doubles, so summing two hundred line values accumulates error. That is not acceptable in accounting data. Sent as a string, every figure survives the round trip exactly as printed, and the service does its own arithmetic in decimal.

If a value cannot be interpreted, such as a two-digit year or a field of ##### where a number overflowed its column, you get the raw characters plus a warning, never a silent null. Losing data quietly is worse than handing back something you can see is wrong.