# Invoice extraction

Source: https://docs.temprl.org/examples/invoice-extraction

> Extract invoice numbers, dates, totals and line items with Simo, check each value with self_check, and send only uncertain fields for review.

Pull the fields you need out of an invoice (text or a scanned image), typed and validated, with a calibrated check on each value. Only the uncertain fields go to a person.

**Python**

```python
from simoai import Client, Extract, Fill, Noul, image

c = Client()

FIELDS = {
    "invoice_no": Extract("the invoice number, exactly as written", max_tokens=16),
    "date":       Extract("the invoice date, exactly as written", max_tokens=16),
    "vendor":     Extract("the name of the company that issued the invoice", max_tokens=24),
    "total":      Fill("the total amount due, in the invoice's currency", kind="number"),
    "currency":   Fill("the currency code, e.g. USD or EUR", pattern=r"[A-Z]{3}", max_tokens=4),
    "items":      Extract("every line item description", many=True, max_tokens=256),
    "paid":       Noul("The invoice is marked as paid"),
}

def read_invoice(path: str) -> dict:
    r = c.ask({"invoice": "<image:1>"}, FIELDS, media=[image(path)], self_check=True)
    out, review = {}, []
    for name, a in r.answers.items():
        out[name] = a.result
        check = a.raw.get("check")                       # set on Fill / Extract with self_check
        if (check is not None and check < 0.9) or a.raw.get("valid") is False:
            review.append(name)
    return {"fields": out, "review": review, "cost": r.cost_usd}

print(read_invoice("invoice-0193.png"))
# {'fields': {'invoice_no': 'INV-0193', 'date': '3 Oct 2026', 'total': 1240.5, 'currency': 'EUR',
#             'items': ['Design review (8h)', 'Hosting, October'], 'paid': False, ...},
#  'review': [], 'cost': 4.1e-05}
```

**HTTP body**

```json
{
  "model": "simo-1-pro",
  "state": {"invoice": "<image:1>"},
  "media": [{"type": "image", "data": "data:image/png;base64,..."}],
  "questions": {
    "invoice_no": {"type": "extract", "instructions": "the invoice number, exactly as written", "kind": "text", "many": false, "max_tokens": 16},
    "date": {"type": "extract", "instructions": "the invoice date, exactly as written", "kind": "text", "many": false, "max_tokens": 16},
    "total": {"type": "fill", "instructions": "the total amount due, in the invoice's currency", "kind": "number", "max_tokens": 16},
    "currency": {"type": "fill", "instructions": "the currency code, e.g. USD or EUR", "kind": "text", "pattern": "[A-Z]{3}", "max_tokens": 4},
    "items": {"type": "extract", "instructions": "every line item description", "kind": "text", "many": true, "max_tokens": 256},
    "paid": {"type": "noul", "instructions": "The invoice is marked as paid"}
  },
  "options": {"self_check": 1}
}
```

## Why it works

- **Typed output.** `kind="number"` always parses to a number and `pattern` forces a three-letter code, so there is no cleanup step.
- **A calibrated check per field.** `self_check` adds `check`, the probability the value is right. Unlike `confidence`, you can threshold it.
- **Text works too.** For a text invoice, put the text in the state instead of `<image:1>` and drop `media`.
