Extraction that verifies: numbers, codes and IDs

Reading a page is a model job. Computing, decoding, validating and formatting are not, and Veralens does them in code afterwards. What that changes, field by field.

5 min read

Every extraction API can hand you a field called total with a number in it. The question nobody asks in a demo is where that number came from, and whether anything checked it.

If a language model read a page, decided which figure was the total, and wrote it into JSON, then the value is a judgement with no receipt. It is usually right. When it is wrong, it is wrong in a way that looks exactly like being right, which is the expensive kind.

Veralens splits that problem in two. Reading the page is a model job, and it stays one. Computing, decoding, validating and formatting are not model jobs, and we do not leave them to a model. They run afterwards, in code, on the values the model read.

What that changes, field by field

Field kindWhat most pipelines returnWhat you get
A number that is a calculationA figure the model worked out in its headThe calculation performed in code, rounded to the decimal step you declared
A QR code or barcodeCharacters a model tried to read off the pixelsThe payload from a real decoder, or null when there is no code
A dateWhatever format the document usedISO 8601, built by rearranging the parts the model actually saw
A country, currency, IBAN, phone numberThe raw string, or a guess at a codeThe ISO form when it resolves, the original text when it does not
A signature, stamp, watermark or redactionSilently dropped, or invented as textMarked explicitly, so you know it was on the page

Most of it is default behaviour. The parts that must be guaranteed rather than judged, a decoded code, a checksum-verified IBAN, a date built mechanically from the parts, are switched on with one format keyword on the field. Full table in Schemas and formats.

The rule underneath all of it

Resolve or leave alone. Never fabricate.

An IBAN that fails its checksum comes back as the original text, not as a corrected IBAN. A currency word that maps to no ISO code stays the word. A QR field on a page with no QR code comes back null rather than filled with something that looks like a payload. A date whose parts are ambiguous is not rewritten into a confident wrong ISO string.

That sounds modest. In production it is the whole difference, because a value that quietly changed is undetectable and a value that stayed raw is obvious.

One post per guarantee

Each of these is a specific thing that goes wrong in document pipelines, and what we do about it:

Why this is not just polish

Two things follow from it that matter more than they sound.

You can check our work. A decoded barcode either matches the sticker or it does not. A total either equals the sum of the line items or it does not. A validated IBAN either passes mod-97 or it does not. These are verifiable claims, unlike an accuracy percentage on a vendor page.

Your application gets smaller. The date parsing, the currency mapping, the checksum library, the rounding helper and the per country special cases stop being your code. That is usually a few hundred lines and a permanent maintenance surface.

Try one field

The fastest way to see the difference is to send a document you already know the answer for, and ask for a calculated number and a code:

json
{
  "type": "object",
  "properties": {
    "total":    { "type": "number", "multipleOf": 0.01 },
    "tax":      { "type": "number", "multipleOf": 0.01 },
    "qr_code":  { "type": "string", "format": "qrcode" },
    "issue_date": { "type": "string", "format": "date" },
    "supplier_country": { "type": "string", "format": "country" }
  },
  "required": ["total"]
}

The quickstart has you sending that in a few minutes, and every job comes back with exactly what it cost.

Try it on your own documents

Add funds from $5, create a key, and send your first document. Every job reports exactly what it cost.

Start extracting

Keep reading