← Blog

Claude API for Invoice Data Extraction

2026-10-28 · 5 min read · SubToAPI Team

Can Claude actually extract invoice data reliably?

Yes. Claude reads invoice images and PDFs, understands the layout even when fields move around, and returns structured JSON with vendor name, invoice number, dates, line items, tax, and totals. It's a strong fit for invoice data extraction because it doesn't need a fixed template the way older OCR-plus-rules pipelines do — it reasons about the document rather than matching coordinates.

The practical question isn't whether Claude can do this, but how to set it up so the output is consistent, machine-readable, and cheap enough to run on every invoice that comes through your accounting pipeline. This guide covers the request structure, the schema you should enforce, how to deal with messy scans, and how to scale it beyond a prototype.

Why Claude fits invoice extraction better than template OCR

Traditional invoice OCR tools rely on zonal templates or trained models per vendor. They break the moment a supplier changes their invoice layout. Claude instead reads the document holistically:

The tradeoff is cost per call and the need for careful prompt and schema design — Claude will happily return prose summaries unless you constrain it.

Designing the extraction request

The core pattern is: send the document, ask for a fixed JSON schema, and nothing else. Loose prompts ("extract the invoice data") produce inconsistent field names and extra commentary. Be explicit.

{
  "model": "claude-sonnet",
  "max_tokens": 1024,
  "messages": [
    {
      "role": "user",
      "content": [
        {
          "type": "document",
          "source": { "type": "base64", "media_type": "application/pdf", "data": "<base64>" }
        },
        {
          "type": "text",
          "text": "Extract the following fields from this invoice and return ONLY valid JSON matching this schema, with no extra text:\n\n{\n  \"vendor_name\": string,\n  \"invoice_number\": string,\n  \"invoice_date\": string (ISO 8601),\n  \"due_date\": string or null,\n  \"currency\": string,\n  \"subtotal\": number,\n  \"tax_amount\": number,\n  \"total_amount\": number,\n  \"line_items\": [\n    { \"description\": string, \"quantity\": number, \"unit_price\": number, \"line_total\": number }\n  ],\n  \"confidence_notes\": string or null\n}\n\nIf a field is missing or illegible, use null. Do not guess numbers."
        }
      ]
    }
  ]
}

Key points that make this reliable in production:

Handling scans, photos, and multi-page PDFs

Real-world invoices aren't clean PDFs exported from accounting software — they're phone photos of receipts, faxed documents, and multi-page statements with the invoice on page 2.

A few practical rules:

Scaling from prototype to production pipeline

A single curl call against the raw Anthropic API works fine for testing. Once you're running this against hundreds or thousands of invoices a day — from an accounts-payable queue, an email inbox parser, or a vendor portal — you run into the same problems every team hits: rotating raw API keys across services, no per-team usage visibility, and no easy way to let a finance ops team call the extraction endpoint without touching infrastructure code.

This is where putting SubToAPI in front of your invoice pipeline helps. It turns your existing Claude access into a standard HTTPS API with sub_live_... application keys, so your invoice-processing service, your internal finance tool, and a contractor's integration script can each have their own scoped key instead of sharing one Anthropic credential. You get streaming support if you want partial results on large batch jobs, structured usage metadata per key so you know exactly which integration is driving cost, and team seats so finance and engineering share one dashboard instead of passing secrets around in Slack.

A minimal extraction call through SubToAPI looks like this:

curl https://api.subtoapi.app/v1/messages \
  -H "Authorization: Bearer $SUBTOAPI_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-sonnet",
    "max_tokens": 1024,
    "messages": [
      {
        "role": "user",
        "content": [
          { "type": "document", "source": { "type": "base64", "media_type": "application/pdf", "data": "<base64>" } },
          { "type": "text", "text": "Extract invoice fields as JSON matching schema: ..." }
        ]
      }
    ]
  }'

Everything else — the schema, the prompt discipline, the validation logic — stays the same. Check the quickstart and messages docs for request details, and pricing for plan comparisons if you're deciding between Solo, Team, and Scale tiers as your invoice volume grows.

questions

Does Claude need a separate OCR engine for scanned invoices? No. Claude accepts images and PDFs directly and reads them without a pre-processing OCR step in most cases. Feeding it raw OCR text instead of the image usually reduces accuracy rather than improving it.

How do I stop Claude from returning extra text around the JSON? Put the exact schema in the prompt, explicitly say "return ONLY valid JSON, no other text," and set a reasonable max_tokens cap. If you need strict parsing, validate the response with a JSON parser and retry on failure.

Can this handle invoices from new vendors with no template setup? Yes — that's the main advantage over classic template-based OCR. Claude reasons about the document layout rather than matching fixed coordinates, so new vendor formats work without any configuration.

Turn your Claude access into an HTTPS API

SubToAPI gives you application API keys, streaming, tool use and usage insights on top of your existing Claude access — set up in minutes.

Start free  Read the quickstart →