How to Automate Invoice Processing with an API: A Complete Guide
March 15, 2026 · Updated
Your accounts payable team is manually keying vendor names, invoice numbers, and line item totals into your ERP. Eight hours a week. Every week. For documents that all look basically the same.
This is a solved problem. Automated invoice processing APIs can eliminate the bulk of manual data entry from invoice workflows — and getting one running takes less than an afternoon. This guide walks through exactly how to do it.
What "automated invoice processing" actually means
The term covers a few different things depending on who's using it:
- OCR + raw text extraction: Turning a scanned invoice image into readable text. Useful, but not sufficient — you still have to parse the text yourself.
- Template-based extraction: Building custom rules per vendor. Works until you add a new vendor. Breaks constantly.
- AI-powered structured extraction: Send the document for schema-guided extraction and receive structured data with a confidence map and validation details. Inspect review results before using the data.
The third approach is what we're covering here. It's the one that actually scales.
What you need before you start
- A document parsing API (we'll use Dokyumi — 25 free credits/month; one credit covers a document up to five pages, no card required)
- Your invoices in PDF or image format (JPG, PNG — even poor scans work)
- Your destination system (a database, ERP, spreadsheet, or webhook endpoint)
That's it. No AWS account. No GCP project. No ML pipeline to maintain.
Step 1: Define your invoice extraction schema
The first step is telling the API what fields you want out of an invoice. You do this in plain English, not code.
Sign in to dokyumi.com/dashboard, go to Schemas → New Schema, and describe your invoice:
"An accounts payable invoice. I need: vendor_name, vendor_address, invoice_number, invoice_date, due_date, subtotal, tax_amount, total_amount, currency, and line_items (an array with description, quantity, unit_price, and line_total for each)."
The AI generates the full extraction schema for you. You can review it, add fields, or remove ones you don't need. Give it a slug like invoice-parser.
You now use the shared POST https://dokyumi.com/api/v1/extract endpoint and send your schema slug in the optional multipart schema field.
Step 2: Send your first invoice
Get your API key from API Keys → New Key. Then:
curl -X POST https://dokyumi.com/api/v1/extract \
-H "Authorization: Bearer dk_live_your_api_key" \
-F "file=@invoice.pdf" \
-F "schema=invoice-parser"
Example successful response:
{
"id": "6f8c2d4a-7b31-4e95-9a20-c1d7f6b84210",
"status": "completed",
"schema": "invoice-parser",
"data": {
"vendor_name": "Acme Office Supply Co.",
"vendor_address": "123 Main St, Chicago, IL 60601",
"invoice_number": "INV-2026-00847",
"invoice_date": "2026-03-10",
"due_date": "2026-04-09",
"subtotal": 2340.00,
"tax_amount": 187.20,
"total_amount": 2527.20,
"currency": "USD",
"line_items": [
{
"description": "Office Chair (Ergonomic, Model X3)",
"quantity": 4,
"unit_price": 285.00,
"line_total": 1140.00
},
{
"description": "Standing Desk (Adjustable, 60in)",
"quantity": 2,
"unit_price": 600.00,
"line_total": 1200.00
}
]
},
"confidence": {
"vendor_name": 0.99,
"invoice_number": 0.98,
"invoice_date": 0.99,
"total_amount": 0.99,
"line_items": 0.95
},
"validation": {
"valid": true,
"errors": [],
"low_confidence_fields": []
},
"meta": {
"processing_time_ms": 4210,
"page_count": 1,
"credits_used": 1,
"ocr_cached": false,
"model": "anthropic/claude-sonnet-4"
},
"request_id": "8f72e3b4-849d-4b6d-9eb1-7a5dd60dc8a7"
}
A successful response returns structured data plus a confidence map and validation details, with status completed or review. For a review response, inspect both validation.errors and validation.low_confidence_fields, and do not assume every data field has a confidence entry. Hard failures return a non-2xx error envelope with error, code, and usually request_id.
Step 3: Build the automation layer
Now you wire this into your workflow. Here's a minimal Python script that processes a directory of invoices and writes results to a database:
import os
import json
import requests
from pathlib import Path
API_KEY = os.environ["DOKYUMI_API_KEY"]
SCHEMA_SLUG = "invoice-parser"
INVOICE_DIR = Path("./invoices/pending")
def extract_invoice(file_path: Path) -> dict:
with open(file_path, "rb") as f:
response = requests.post(
"https://dokyumi.com/api/v1/extract",
headers={"Authorization": f"Bearer {API_KEY}"},
files={"file": (file_path.name, f, "application/pdf")},
data={"schema": SCHEMA_SLUG},
timeout=30
)
response.raise_for_status()
return response.json()
def process_pending_invoices():
results = []
for invoice_file in INVOICE_DIR.glob("*.pdf"):
print(f"Processing {invoice_file.name}...")
try:
result = extract_invoice(invoice_file)
if result["status"] in ("completed", "review"):
data = result["data"]
validation = result["validation"]
flagged = validation["low_confidence_fields"]
validation_errors = validation["errors"]
# "review" can mean validation errors, low confidence, or both
data["needs_review"] = result["status"] == "review"
data["review_details"] = {
"low_confidence_fields": flagged,
"validation_errors": validation_errors,
}
data["source_file"] = invoice_file.name
data["extraction_id"] = result["id"]
results.append(data)
invoice_file.rename(invoice_file.parent.parent / "processed" / invoice_file.name)
review_details = {
"errors": validation_errors,
"low_confidence_fields": flagged,
}
print(f" ✓ {data['vendor_name']} — ${data['total_amount']}"
+ (f" (review: {review_details})" if data["needs_review"] else ""))
else:
print(f" ✗ Unexpected success status: {result.get('status')}")
except Exception as e:
print(f" ✗ Error: {e}")
return results
if __name__ == "__main__":
invoices = process_pending_invoices()
print(f"\nProcessed {len(invoices)} invoices")
print(f"Flagged for review: {sum(1 for i in invoices if i['needs_review'])}")
This pattern — extract, inspect validation and confidence, and route every review result to a human — is the core of a production invoice automation system.
Step 4: Handle the edge cases that kill real implementations
Most tutorials stop at the happy path. Here's what you actually need to handle in production:
Multi-page invoices
Dokyumi accepts multi-page PDFs within the applicable page limit, so you do not need to split a supported document before sending it. Test line-item arrays that cross page boundaries on representative invoices and route uncertain results to review.
Low-quality scans
Build a review queue when status is review. Show the human both validation.low_confidence_fields and validation.errors, because type-validation failures can trigger review without adding a field to the low-confidence list.
International invoices
Add currency and locale to your schema description: "invoices may be in USD, EUR, or GBP — normalize all amounts to a float". The model handles comma-as-decimal-separator, VAT vs. tax labeling, and date format variations.
Duplicate detection
Dokyumi caches OCR results by file hash, so a repeated file can skip OCR and return faster. Every extraction still consumes page-weighted credits. Deduplicate before sending by file hash or a business key such as invoice_number + vendor_name.
Bounded-concurrency API batches
POST /api/v1/extract returns each result synchronously and does not accept a per-request webhook URL. For API batches, use a queue with bounded concurrency and persist each response. Webhook delivery is separate and applies only to documents submitted through a configured upload site.
curl -X POST https://dokyumi.com/api/v1/extract \
-H "Authorization: Bearer dk_live_your_api_key" \
-F "file=@invoice.pdf" \
-F "schema=invoice-parser"
Step 5: Connect to your ERP or accounting system
The JSON you get back is already structured to map directly to most AP systems. Here are common integration patterns:
QuickBooks Online
Use the QBO Bills API. Map vendor_name → VendorRef, total_amount → TotalAmt, line_items → Line[].
NetSuite
POST to the Vendor Bills REST endpoint. The line item array maps cleanly to item.items[].
Xero
Use the Xero Invoices API and explicitly map your schema fields to Contact, LineItems[], currency, tax, and amount fields required by your Xero configuration.
Google Sheets / Airtable
For smaller operations: flatten the line items with json.dumps(data["line_items"]) and write each invoice as a row. Quick and works well for teams not yet on a full ERP.
The complete invoice field checklist
Whatever system you feed, the fields below are the ones AP workflows actually consume. Use this as the starting point for your schema — capture only what your downstream process needs, because a leaner schema extracts faster and reviews easier.
Header information
- Vendor details: company name, remit-to address, tax ID, contact info
- Invoice metadata: invoice number, invoice date, due date, currency
- Purchase order references: PO numbers and contract references for three-way matching
- Payment terms: net payment period, early-payment discounts, late fees
Line item details
- Descriptions: item names, SKUs, service descriptions
- Quantities and units: ordered quantity, unit of measure
- Pricing: unit price, extended amount, discounts applied
- Tax: tax rate, tax amount, exemption codes
Totals and payment data
- Subtotals: line-item subtotal, tax total, shipping charges
- Total amount due and any prior payments or credits applied
- Banking details: ACH/wire instructions when your process pays directly from the invoice
Build vs. buy: when custom extraction makes sense
Building your own extraction pipeline (raw OCR plus your own parsing and validation code) gives you total control — and a permanent maintenance obligation. It only tends to pay off when at least one of these is true:
- Your documents are so unusual that general-purpose extraction genuinely can't handle them
- You have in-house ML expertise you're happy to keep pointed at this problem indefinitely
- A compliance mandate requires fully on-premise processing
For everyone else, an API with schema-first extraction gets you to production in a day instead of a quarter, and the vendor absorbs the model, OCR, and infrastructure maintenance. The accounts payable use case walks through what that looks like end to end.
KPIs worth tracking once you're live
- Straight-through processing rate: the share of invoices that arrive as
status: "completed"and flow to your ERP with zero human touches. This is the single best health metric for the whole pipeline. - Review-queue rate and clearance time: how often extractions land in
review, and how long flagged fields wait for a human. A rising review rate usually means a new vendor format worth adding fields for. - Time from receipt to data availability: the end-to-end latency your AP team actually feels.
- Cost per invoice: subscription plus review labor, divided by volume — the number to compare against what manual entry was costing.
What this actually costs
This is the question that matters. Here's a realistic cost model for a mid-sized AP team processing 500 invoices/month:
| Approach | Setup time | Monthly cost | Manual hours/month |
|---|---|---|---|
| Manual data entry | — | $2,000–4,000 (labor) | 40–80 hrs |
| AWS Textract + custom processing | 2–6 weeks | Per-page metered (varies) + dev time | 10–20 hrs (maintenance) |
| Dokyumi Starter plan | Varies by schema, integration, and representative testing | $99/month for 500 credits | Measure review volume on your own invoices |
The flat-rate pricing matters more than it sounds. AWS Textract and Google Document AI both charge per page — which is fine until you start processing attachments, multi-page statements, or remittance PDFs. At 500 invoices averaging 3 pages each, your bill becomes a function of page counts you don't control and per-feature rates you have to model — and you won't know the number until month-end. Dokyumi's Starter plan covers this volume flat: $99 for 500 credits.
Common mistakes to avoid
Trying to build this with raw OCR first. If you extract raw text and then write regex to find "Total:" or "Invoice #", you're building a fragile system that breaks on every new vendor template. AI structured extraction is cheaper, more accurate, and infinitely more maintainable.
Skipping review details. AI extraction is not 100% accurate on every document. Use the model-reported confidence map, validation.errors, and validation.low_confidence_fields together, and route every review result to a human before downstream use.
Not testing with your worst documents first. Use your oldest, lowest-quality scans during testing. If the API handles those well, everything else is easy. If it struggles, you want to know before you've built the integration.
Unbounded batch concurrency. Queue large API batches, cap concurrent synchronous requests, and checkpoint each response so the job can resume safely. Use site webhooks only for documents submitted through a configured upload site.
The result
Measure time savings and review volume on your own invoices. Dokyumi returns confidence and validation details and stores extraction records and source documents; implement workflow audit logging and downstream review records in your own system when a compliance trail is required.
Setup time and ROI depend on schema complexity, integration work, document quality, and review volume. Measure them on representative invoices before forecasting production savings.
The full invoice extraction workflow — schema definition, API integration, ERP mapping, confidence-based review routing — is something you can have running this week.
Continue this path
These articles are selected from the same editorial cluster, not generated from keyword overlap.
Put invoices and financial operations to work
Use the ready field map and current JSON response as an implementation reference.
See multi-page credit math, transaction arrays, and arithmetic validation.
Connect invoice intake and structured output to the operating workflow.
Test the extraction on your own documents
25 free credits each month. One credit covers a document up to 5 pages; self-serve documents can be up to 50 pages. No credit card required.