Pdf Invoice Table Extraction avatar

Pdf Invoice Table Extraction

Pricing

from $30.00 / 1,000 result returneds

Go to Apify Store
Pdf Invoice Table Extraction

Pdf Invoice Table Extraction

Automation workflows need to convert varied native-text or scanned invoices into consistent accounting-ready line items while detecting uncertain fields and arithmetic mismatches before downstream import.

Pricing

from $30.00 / 1,000 result returneds

Rating

0.0

(0)

Developer

Jordan Nabbe

Jordan Nabbe

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

20 hours ago

Last modified

Share

PDF Invoice Table Extraction turns invoices into clean, accounting-ready JSON and CSV for automation builders, accounts-payable teams and agencies who connect invoice intake to ERP, accounting or workflow systems. It reads real native-text PDF files (base64 or HTTPS URL) plus text, HTML, CSV and JSON invoices, normalizes header fields and line items, recomputes the totals and tells you exactly which invoices need a human look before import.

What it does

  • Parses PDF bytes with a real PDF parser, page by page, and keeps the source page of every line item.
  • Also accepts inline text, HTML tables, CSV line-item tables, JSON invoice records, and base64-encoded versions of these.
  • Extracts vendor, tax id, invoice number, invoice and due date, currency, PO number, subtotal, discount, tax, shipping, grand total and line items (description, SKU, quantity, unit price, discount, tax, line total).
  • Normalizes dates to ISO YYYY-MM-DD and amounts to plain numbers. European and US notation are both understood.
  • Never guesses ambiguous values. 1.234 vs 1,234 and 03/04/2025 are rejected with AMBIGUOUS_NUMBER or AMBIGUOUS_DATE unless the document settles them (for example 13/04/2025 or 1.234,56) or you set localeHint.
  • Reconciles line totals, subtotal and grand total within a configurable tolerance. Stated values are never overwritten; stated and calculated values are both returned with the difference.
  • Reports evidence lines with page numbers and explicit exceptions (TOTAL_MISMATCH, SUBTOTAL_MISMATCH, LINE_TOTAL_MISMATCH, MISSING_FIELD, INVALID_VALUE, ...). No confidence scores are invented; only measured checks are reported.
  • Supports vendor column aliases and a targetSchema that renames canonical fields in an extra mappedInvoice copy.
  • Writes one dataset row per extracted invoice, an OUTPUT record with the summary, all rows, per-source failures and an outcome block, and an OUTPUT.csv line-item file.
  • One bad source never fails the batch; it is reported in OUTPUT with an error code. If nothing usable was produced, the run fails after writing OUTPUT.

How to use it

Paste sources into the input and run. Example:

{
"sources": [
{
"mode": "inline",
"name": "acme-invoice-1001.txt",
"format": "text",
"content": "ACME Supplies\nInvoice: INV-1001\nInvoice Date: 2025-01-15\nCurrency: USD\n\nDescription,SKU,Qty,Unit Price,Line Total\nBlue widgets,BW-10,2,10.00,20.00\n\nSubtotal: 20.00\nTax: 2.00\nTotal: 22.00"
},
{ "mode": "url", "name": "vendor-b.pdf", "url": "https://files.example.com/invoices/b.pdf", "format": "pdf" }
],
"currencyHint": "USD",
"localeHint": "en-US",
"reconciliationTolerance": 0.02
}

For a PDF you already hold, use {"mode":"inline","name":"a.pdf","format":"base64_document","mediaType":"application/pdf","content":"<base64>"}.

Tables in text and PDFs are detected from a header row whose columns match known names (Description, SKU, Qty, Unit Price, Line Total and aliases), separated by commas, tabs, pipes or two or more spaces. Header fields are read from Label: value lines.

Output

FieldMeaning
inputName, sourceYour source name and a query-free source reference
statussucceeded when invoice number, grand total and line items were extracted; partial when an invoice was produced but one of those is missing
reviewStatusclean, or needs_review when any warning was raised (for example a total mismatch)
vendorName, invoiceNumber, currency, grandTotal, lineItemCountFlat columns for spreadsheets
invoiceCanonical invoice with lineItems
reconciliationCalculated vs stated subtotal and grand total, difference, withinTolerance
sourceReferencesEvidence line and page per field
exceptionscode, field, severity, message

Abridged row:

{ "inputName": "acme-invoice-1001.txt", "recordType": "invoice", "status": "succeeded", "reviewStatus": "clean", "invoiceNumber": "INV-1001", "grandTotal": 38.5,
"reconciliation": { "calculatedGrandTotal": 38.5, "statedGrandTotal": 38.5, "difference": 0, "withinTolerance": true },
"reviewRequired": false }

The OUTPUT record adds outcome with status (SUCCEEDED, PARTIAL, FAILED or LIMIT_REACHED), itemsReceived, itemsSucceeded, itemsFailed, billableCount, limitReached and undelivered. Sources that could not be read (for example INVALID_BASE64, URL_BLOCKED, OCR_REQUIRED) appear only in OUTPUT.rows with status: failed, never in the dataset.

Pricing

Pay per event. The main charge is per invoice; everything else listed below is free.

EventPrice (USD)Charged when
Actor start (apify-actor-start)$0.005The run starts.
Invoice processed (apify-default-dataset-item)$0.03An extracted invoice row (status succeeded or partial) is written to the default dataset. Sources that could not be read are never written to the dataset.

Not charged:

  • failed source rows (OUTPUT only)
  • OUTPUT summary
  • OUTPUT.csv line-item file

Examples (default 512 MB memory, one start event):

  • 10 invoices processed: $0.005 start + 1 × $0.005 + 10 × $0.03 = $0.31
  • 8 invoices, 2 sources failed: $0.005 start + 1 × $0.005 + 8 × $0.03 = $0.25

Spending limit: when you set a maximum cost per run, the Actor stops before it would exceed it, keeps every invoice it already delivered and reports limitReached in the OUTPUT record. It never delivers results beyond the limit.

The Store's Pricing tab shows the prices in force. If this section and the Pricing tab ever differ, the Pricing tab applies.

Use cases

  • Normalize invoice headers and line items before ERP or accounting import.
  • Catch subtotal, tax, shipping and grand-total mismatches automatically.
  • Queue invoices with needs_review for human review.
  • Map different vendors' column names onto one schema.
  • Convert PDF, HTML, CSV or JSON invoices to JSON and CSV.

Limits

  • At most 50 sources per run, 1000 rows and 1000 line items per invoice; 10 MiB per inline source, 25 MiB per download; up to 500 PDF pages (maxPagesPerDocument defaults to 100).
  • PDFs must contain a text layer. Scanned or image-only PDFs are reported with OCR_REQUIRED; there is no OCR. Encrypted or damaged PDFs give PDF_TEXT_UNSUPPORTED.
  • Extraction is rule-based. Unusual layouts, or tables separated by single spaces, may be missed; those invoices surface as exceptions rather than silent wrong values.
  • minimumConfidence is accepted for compatibility but has no effect, because no confidence scores are produced.
  • URL mode: HTTPS only, public hosts only (private, loopback and link-local addresses and embedded credentials are rejected, redirects are re-validated, at most 3), 30-second timeout.
  • Spreadsheet (.xlsx) input is not supported; export the sheet to CSV first.
  • If your spending limit is reached, remaining invoices are not delivered and OUTPUT.outcome reports them as undelivered with limitReached: true.
  • Invoice content is never written to the log. Datasets and key-value stores follow your Apify retention settings.

FAQ

Does it work offline? Yes, for all inline sources, including base64 PDFs.

Does it read scanned invoices? No. It reports OCR_REQUIRED for that source.

Are totals silently corrected? Never. Stated values are kept, the difference is reported and the row is marked needs_review.

What if the number format is ambiguous? The value is left empty and an ambiguity exception is added, unless localeHint settles it.

What happens with invalid input? The run fails before processing with INPUT_VALIDATION_ERROR.

Is my invoice data shared or used for training? No. Extraction is rule-based and runs inside your Actor run. In URL mode only the exact HTTPS URL you supply (and its validated redirects) is downloaded.