# Document extraction

> Extract the fields you define in a JSON Schema from a PDF or an image.

Canonical: https://platform.uprelic.com/docs/document-extraction

---

Apart from `POST /v1/systemone`, you can use the extraction API, `POST /v1/extract`, which is built to extract structured data from PDFs and images. You don’t write the questions yourself: you describe the fields you want, and the API finds each one in the document and returns it in the type you asked for.

## Extracting fields from a document

Send a PDF or an image together with a JSON Schema that lists the fields you want. For each field, Strom finds the line in the document that contains it. Scanned pages and images are converted to text using OCR automatically.

```bash Request
curl https://api.uprelic.com/v1/extract \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "strom-1.0.7",
    "schema": {
      "properties": {
        "invoice_number": {"type": "string"},
        "invoice_date": {"type": "string", "format": "date"},
        "total": {"type": "number", "format": "amount", "description": "The total including tax"},
        "paid": {"type": "boolean"}
      }
    },
    "document": {"url": "data:application/pdf;base64,JVBERi0xLjQK..."}
  }'
```

`document.url` can be a public URL or a base64 `data:` URL. PDFs can have at most 8 pages. `model` can be `strom-fast` or `strom-base` (beta), or their versioned names; `strom-base` is much slower and costs more.

Each field can have a `description`. Use it to tell the model what to look for when the name alone is ambiguous, for example whether `total` includes tax.

## API Response

For each field, the response contains:

- `text`: the line of the document the field was found on, exactly as it appears.
- `value`: that line converted to the field’s type, for example a date as `1988-12-16` or an amount as `14982.0`. See the table below.
- `confidence`: how sure the model is that it picked the right line, from 0 to 1.
- `page` and `box`: where the line is. `box` is `[left, top, right, bottom]` as fractions of the page’s width and height.

If the document doesn’t contain a field, that field is `null`.

```json Response · illustrative
{
  "model": "strom-1.0.7",
  "fields": {
    "invoice_number": {
      "text": "17795", "value": "17795", "confidence": 0.98,
      "page": 1, "box": [0.7731, 0.1286, 0.8225, 0.1424]
    },
    "invoice_date": {
      "text": "12/16/88", "value": "1988-12-16", "confidence": 0.94,
      "page": 1, "box": [0.7731, 0.1552, 0.85, 0.1705]
    },
    "total": {
      "text": "$14,982.00", "value": 14982.0, "confidence": 0.55,
      "page": 1, "box": [0.8306, 0.3529, 0.9256, 0.3662]
    },
    "paid": {"text": null, "value": false, "confidence": 0.58, "page": null, "box": null}
  },
  "usage": {
    "input_tokens": 20060, "output_tokens": 5, "cached_input_tokens": 25344,
    "cost": 0.00084252, "currency": "usd"
  },
  "metadata": {"server_processing_time_ms": 3405}
}
```

## Field types

The field’s type in the schema decides how `text` is converted into `value`:

| Type in the schema | Line in the document | `value` |
|---|---|---|
| `{"type": "string"}` | Invoice no. 17795 | `"Invoice no. 17795"` |
| `{"type": "string", "format": "date"}` | Date: 12/16/88 | `"1988-12-16"` |
| `{"type": "number"}` | Quantity 12 | `12` |
| `{"type": "number", "format": "amount"}` | Total EUR 1.234,50 | `1234.5` |
| `{"type": "number", "format": "percent"}` | VAT 19% | `19` |
| `{"type": "boolean"}` | (answered without a line) | `true` or `false` |
| `{"enum": ["EUR", "USD"]}` | (answered without a line) | `"EUR"` |

If the line contains more than one date, number or percentage, we don’t guess which one you meant: `value` is then the whole line, the same as `text`.

## Cost and errors

- You pay for input tokens at the same price as `POST /v1/systemone`. The cost of each extraction is in `usage.cost`. For example, a 2-page PDF invoice with a 10-field schema used about 28,000 input tokens.
- The “Improve document extraction” switch under Billing comes with the paid plans. Each run that improves your extraction is charged to your balance for the AI processing it uses, at twice our provider's price, about €2 to €3 a run.
- Documents that can’t be read are not charged. You get a `422` with the reason in `detail`, for example when the file isn’t a PDF or image, has no text, or has more than 8 pages.
