Stop Copying Invoice Data by Hand — Automate It with One API Call

7 min read Document Extraction

The Invoice Problem Every Developer Knows

Someone on the finance team sends you a stack of PDFs. “We need the invoice numbers, dates, line items, and totals in a spreadsheet by Friday.” You look at the files — different vendors, different layouts, different ways of listing the same data. Some are clean digital PDFs. Some are scanned paper documents with coffee stains.

You could write a regex parser. It would work for the first three invoices and break on the fourth. You could build OCR templates — one per vendor layout. That works until the vendor updates their invoice design and your template silently extracts garbage.

There’s a better way. Define the fields you want, send the invoice, and get structured JSON back — with confidence scores on every field.

Define a Schema, Get Structured Data

The Document Extraction API uses schema-based extraction. You tell it what fields to look for, and it figures out where they are in the document. No regex, no templates, no layout-specific configuration.

Here’s a schema for a typical invoice:

import { IterationLayer } from "iterationlayer";

const client = new IterationLayer({ apiKey: "YOUR_API_KEY" });

const result = await client.extract({
  files: [
    { type: "url", name: "invoice.pdf", url: "https://example.com/invoice.pdf" }
  ],
  schema: {
    fields: [
      {
        name: "invoice_number",
        type: "TEXT",
        description: "The unique invoice identifier",
        is_required: true,
      },
      {
        name: "vendor_name",
        type: "TEXT",
        description: "Name of the company that issued the invoice",
        is_required: true,
      },
      {
        name: "invoice_date",
        type: "DATE",
        description: "Date the invoice was issued",
        is_required: true,
      },
      {
        name: "line_items",
        type: "ARRAY",
        description: "Individual items or services on the invoice",
        item_schema: {
          fields: [
            { name: "description", type: "TEXT", description: "Item description" },
            { name: "quantity", type: "INTEGER", description: "Number of units" },
            { name: "unit_price", type: "CURRENCY_AMOUNT", description: "Price per unit" },
            { name: "line_total", type: "CURRENCY_AMOUNT", description: "Total for this line" },
          ],
        },
      },
      {
        name: "subtotal",
        type: "CURRENCY_AMOUNT",
        description: "Sum before tax",
        is_required: true,
      },
      {
        name: "tax_amount",
        type: "CURRENCY_AMOUNT",
        description: "Tax amount",
      },
      {
        name: "total_due",
        type: "CURRENCY_AMOUNT",
        description: "Total amount due including tax",
        is_required: true,
      },
      {
        name: "currency",
        type: "CURRENCY_CODE",
        description: "Currency of the invoice (ISO 4217)",
      },
    ],
  },
});

That’s it. No OCR configuration, no bounding box coordinates, no vendor-specific rules. The parser reads the document — whether it’s a native PDF or a scanned image — and extracts the fields you defined.

What the Response Looks Like

The API returns structured JSON with every field, its value, and a confidence score:

{
  "success": true,
  "data": {
    "invoiceNumber": {
      "type": "TEXT",
      "value": "INV-2026-0391",
      "confidence": 0.98
    },
    "vendorName": {
      "type": "TEXT",
      "value": "Nordic Office Supplies AB",
      "confidence": 0.96
    },
    "invoiceDate": {
      "type": "DATE",
      "value": "2026-01-28",
      "confidence": 0.97
    },
    "lineItems": {
      "type": "ARRAY",
      "value": [
        [
          { "value": "Ergonomic keyboard", "confidence": 0.95 },
          { "value": 10, "confidence": 0.97 },
          { "value": 89.99, "confidence": 0.94 },
          { "value": 899.90, "confidence": 0.96 }
        ],
        [
          { "value": "USB-C Monitor Cable", "confidence": 0.93 },
          { "value": 25, "confidence": 0.96 },
          { "value": 12.50, "confidence": 0.95 },
          { "value": 312.50, "confidence": 0.94 }
        ]
      ],
      "confidence": 0.95
    },
    "subtotal": {
      "type": "CURRENCY_AMOUNT",
      "value": 1212.40,
      "confidence": 0.96
    },
    "taxAmount": {
      "type": "CURRENCY_AMOUNT",
      "value": 242.48,
      "confidence": 0.94
    },
    "totalDue": {
      "type": "CURRENCY_AMOUNT",
      "value": 1454.88,
      "confidence": 0.97
    },
    "currency": {
      "type": "CURRENCY_CODE",
      "value": "SEK",
      "confidence": 0.96
    }
  }
}

Every value has a confidence score between 0.0 and 1.0. This is what makes the difference between a demo and a production system.

Confidence Scores Change the Game

Raw extraction is table stakes. Knowing when to trust the extraction — that’s what matters in production.

A typical workflow:

  • Confidence above 0.90 — auto-accept the value, no human review needed
  • Confidence between 0.70 and 0.90 — flag for quick human verification
  • Confidence below 0.70 — route to manual data entry

This turns invoice processing from an all-or-nothing automation into a graduated pipeline. Most invoices flow through automatically. Edge cases get flagged. Nothing gets silently wrong.

Line Items as Arrays

The ARRAY field type handles tabular data naturally. Each row in the line items table becomes an array entry, with its own nested fields — description, quantity, unit price, line total. No flattening, no column-index guessing, no regex for table boundaries.

The parser handles tables of varying lengths. An invoice with 3 line items and an invoice with 300 line items use the same schema definition.

Built-In OCR for Scanned Invoices

Some invoices arrive as photos or scanned PDFs. The parser includes built-in OCR — no separate OCR step, no pre-processing pipeline. Send an image of a paper invoice and get the same structured JSON output.

Supported image formats: PNG, JPG, JPEG, GIF, WEBP.

Currency and Financial Fields

The parser includes field types built for financial documents:

  • CURRENCY_AMOUNT — extracts numeric values that represent money, handling decimal separators and formatting differences across locales
  • CURRENCY_CODE — extracts and validates ISO 4217 currency codes (USD, EUR, GBP, SEK)
  • CALCULATED — define computed fields (e.g., subtotal + taxAmount = totalDue) and let the parser verify the math

These aren’t generic text fields with post-processing. They’re purpose-built for financial data extraction.

Cross-Checking Totals with CALCULATED Fields

Invoices sometimes have math errors, or the OCR misreads a digit. The CALCULATED field type lets you verify arithmetic as part of the extraction:

{
  name: "computedTotal",
  type: "CALCULATED",
  description: "Subtotal plus tax, for verification",
  operation: "sum",
  source_field_names: ["subtotal", "taxAmount"],
}

The parser extracts subtotal and taxAmount from the document, then computes computedTotal by summing them. If the computed value doesn’t match the extracted totalDue, you know something is off — either an OCR misread or a genuine discrepancy in the invoice itself. Flag it for review.

Handling Different Invoice Formats

The same schema works across vendor formats. A German invoice that lists “Gesamtbetrag” instead of “Total Due” and uses comma as a decimal separator (1.234,56 EUR) goes through the same pipeline as a US invoice with a dollar sign and period decimals ($1,234.56). The parser understands the content, not just the character patterns.

International invoices often include additional fields worth extracting — VAT registration numbers, purchase order references, payment terms. Add them to the schema as needed:

{
  name: "vatNumber",
  type: "TEXT",
  description: "Vendor VAT registration number",
},
{
  name: "purchaseOrderReference",
  type: "TEXT",
  description: "PO number referenced on the invoice",
},
{
  name: "paymentTerms",
  type: "TEXT",
  description: "Payment terms (e.g., 'Net 30', 'Due on receipt')",
}

No schema changes are needed per vendor. The same field definitions work regardless of whether the invoice comes from a US supplier, a European distributor, or an APAC manufacturer.

Batch Processing Invoices

End-of-month invoice runs can involve dozens or hundreds of documents. Send up to 20 invoices in a single API call (50 MB per file, 200 MB total per request). For larger volumes, split into batches and send them concurrently.

A confidence-based review workflow makes batch processing practical. Most invoices in a batch will extract cleanly with confidence above 0.90 — those go straight to your accounting system. The handful with lower confidence get routed to a review queue where a human confirms or corrects the values. This keeps throughput high without sacrificing accuracy.

Get Started

Check out the docs for the full API reference, including all 17 field types and batch processing (up to 20 invoices in a single request). The TypeScript and Python SDKs handle authentication and request building, so your first extraction is a few lines of code away.

Sign up for a free account — no credit card required. Start with one invoice and see the structured output. Once you trust the confidence scores, automate the pipeline.

Start building in minutes

Free trial included. No credit card required.