---
title: "Invoices as fields"
url: https://recursiveai.org/oneocr/cookbook/invoices/
description: "Read an invoice image into typed fields with their EN 16931 business-term ids, line items included, and see which words and box each value came from."
version: "1.0.0"
---

# Invoices as fields

Read an invoice image into typed fields with their EN 16931 business-term ids, line items included, and see which words and box each value came from.

Extraction needs the extraction model, which ships in its own package:

```shell
dotnet add package RecursiveAI.OneOcr --version 1.0.0
dotnet add package RecursiveAI.OneOcr.Models.Documents --version 1.0.0
```

A small layout-aware model tags the words of the page, and deterministic code assembles the fields from the tagged words, so a value is always text that is on the page. The image is `invoice.png` from [the sample images](https://recursiveai.org/oneocr/docs/getting-started/#the-sample-images):

```csharp
using OneImage;
using OneOcr;
using OneOcr.Documents;
using OneOcr.Models.Documents;

OcrEngine engine = OcrEngine.LoadBundled();
DocumentModels.Configure();                      // the extraction model from RecursiveAI.OneOcr.Models.Documents, once

Invoice invoice = Image.Load("invoice.png").ExtractInvoice(engine);

Console.WriteLine($"{invoice.Number?.Value}, issued {invoice.IssueDate?.Value}, total {invoice.Total?.Value}");
Console.WriteLine($"{invoice.SellerName?.Value} -> {invoice.BuyerName?.Value}, IBAN {invoice.Iban?.Value}");
foreach (InvoiceLine line in invoice.Lines)
    Console.WriteLine($"  {line.Description?.Text}: {line.Quantity?.Value} {line.Unit?.Text} x {line.UnitPrice?.Value} = {line.Amount?.Value}");

ExtractedField total = invoice.Extraction.Get("BT-112")!;
Console.WriteLine($"BT-112 \"{total.Text}\" -> {total.Number}, words [{string.Join(", ", total.WordIndices)}], " +
                  $"box ({total.Box.Left:F0}, {total.Box.Top:F0}), confidence {total.Confidence:F2}");
Console.WriteLine($"Due date: {invoice.DueDate?.Value ?? "null"}, delivery date: {invoice.DeliveryDate?.Value ?? "null"}");
```

```text
INV-2041, issued 2026-10-14, total 215.78
Northwind Supply Ltd -> Blue Heron Bakery, IBAN GB33 BUKB 2020 1555 5555 55
  Flour, 25 kg bag: 4 pcs x 31.50 = 126
  Cane sugar, 10 kg: 2 pcs x 18.25 = 36.50
  Baking parchment roll: 6 pcs x 7.40 = 44.40
BT-112 "£215.78" -> 215.78, words [83], box (2072, 1474), confidence 1.00
Due date: null, delivery date: 2026-11-13
```

## What came back

- Each `ExtractedField` has the exact `Text`, a normalized `Value` (an ISO date, a plain decimal amount), typed `Number` or `Date` where it applies, the indices of its words in the page and their box.
- `invoice.Extraction.Get("BT-112")` looks any field up by its business term: `BT-1` number, `BT-2` issue date, `BT-27` seller, `BT-44` buyer, `BT-84` IBAN, `BT-106` subtotal, `BT-110` tax, `BT-112` total, and line items from `BT-126` to `BT-153`.
- A field the model didn’t find is `null`, never a guess. Here the model tagged the second date as the delivery date (`BT-72`) rather than the due date (`BT-9`), so `DueDate` is `null`: read the fields you depend on, and look at `Confidence`, which is the mean probability of the field’s word tags (not a calibrated probability like a word’s).
- Amounts are normalized to plain decimals: `126.00` came back as `126`.

## Good to know

- `ExtractInvoice` and `ExtractReceipt` take a `DocumentExtractionOptions` (`MaxDegreeOfParallelism`, `Strict`) and have `Async` twins.
- For your own document type, `Extract<T>` takes a source-generated `JsonTypeInfo<T>` and a model you fine-tuned; the [extraction model spec](https://recursiveai.org/oneocr/docs/docextract/) describes the model and the [overview](https://recursiveai.org/oneocr/docs/overview/#invoices-receipts-and-your-own-document-types) the API.
- Receipts work the same way: see [Receipts](https://recursiveai.org/oneocr/cookbook/receipts/).
