Invoice PDF to JSON API: extract line items

One request and one response: an invoice PDF in, line items out as typed JSON, plus the check that catches a bad row before it reaches your books.

3 min readUpdated 17 October 2026

To turn an invoice PDF into JSON, send the PDF and a JSON Schema to one endpoint and read typed line items from the result. Veralens is a document extraction API (OCR plus schema-typed JSON): numbers arrive as numbers even when the invoice printed 1.234,56, and a field that is not on the page comes back null.

VeralensVeryfi (checked 2026-10-18)
Invoice priceVeralensPer token, cost reported on each jobVeryfi (checked 2026-10-18)$0.16 per invoice, $500 a month minimum
Output shapeVeralensYour schemaVeryfi (checked 2026-10-18)Fixed invoice model
StrengthVeralensAny layout or field set, no minimumVeryfi (checked 2026-10-18)Ready made models, mobile SDKs, SOC 2 and HIPAA listed
Line itemsVeralensWeakest part of any extraction, check the sumVeryfi (checked 2026-10-18)Not checked by us

Veryfi source: pricing page. Updated 2026-10-17.

This is one request and one response: an invoice PDF in, line items out as JSON. For the full field-by-field schema design, read the invoice walkthrough. For the general case, see PDF to JSON. Here the goal is only the line items.

The request

bash
curl -X POST https://veralens.ai/api/v1/jobs/create \
  -H "Authorization: Bearer vl_your_secret_key" \
  -H "Content-Type: application/json" \
  -d '{
    "sources": [{ "type": "document", "data": "data:application/pdf;base64,JVBERi0..." }],
    "schema": {
      "type": "object",
      "properties": {
        "invoice_number": { "type": "string" },
        "currency": { "type": "string", "format": "currency" },
        "total": { "type": "number" },
        "line_items": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "description": { "type": "string" },
              "quantity": { "type": "number" },
              "unit_price": { "type": "number" },
              "amount": { "type": "number" }
            },
            "required": ["description", "amount"]
          }
        }
      },
      "required": ["total", "currency"]
    }
  }'

Swap the data URL for your own base64 PDF. You get 201 with the job in pending. Add a webhook_url to be called on completion, or poll GET /jobs/:jobId/get every 2 to 3 seconds (Jobs and queue).

The response

On completed, output is a JSON string:

json
{
  "invoice_number": "INV-2041",
  "currency": "EUR",
  "total": 1234.56,
  "line_items": [
    { "description": "Design work, September", "quantity": 10, "unit_price": 100, "amount": 1000 },
    { "description": "Hosting", "quantity": 1, "unit_price": 234.56, "amount": 234.56 }
  ]
}

The values are illustrative. The shape is what the schema fixes: numbers arrive as numbers even when the invoice printed 1.234,56, and the field names are the ones you wrote. The job also reports its own usage.cost, so you see what each invoice cost.

Check the line items

Line items are the weakest part of any invoice extraction, ours included. Check them in your own code:

ts
const invoice = JSON.parse(job.output)
const sum = invoice.line_items.reduce((n: number, l: { amount: number }) => n + l.amount, 0)
// compare with subtotal, or with total when there is no tax line

If the sum is off, flag the invoice for review. Keep required small so an absent field comes back null rather than guessed.

Try it

  1. Create an account and an API key.
  2. Add funds in Billing. There is no free balance, so top up before your first job. Billing is prepaid per token, you can add from $5, and a failed job refunds its hold in full. See pricing.
  3. Run the request above on one of your own invoices.

Get your API key and extract your first invoice.

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.

Add $5, get an API key

Keep reading