Invoice Extraction JSON Schema Generator for OCR and LLM Output
Whether the extraction comes from OCR rules or a language model, the output needs a contract. A JSON Schema gives your AP workflow a strict definition of what a valid extraction looks like and rejects broken results before they reach the ERP.
Fill in
JSON Schema (draft 2020-12)
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.com/schemas/supplier-invoice.json",
"title": "SupplierInvoiceExtraction",
"type": "object",
"required": ["document_type", "supplier_name", "invoice_number", "invoice_date", "currency", "total_amount", "line_items"],
"properties": {
"document_type": { "type": "string", "enum": ["invoice", "credit_note", "debit_note", "proforma", "other"] },
"supplier_name": { "type": "string", "minLength": 1 },
"supplier_tax_id": { "type": ["string", "null"] },
"invoice_number": { "type": "string", "minLength": 1, "maxLength": 64 },
"invoice_date": { "type": "string", "format": "date" },
"due_date": { "type": ["string", "null"], "format": "date" },
"po_number": { "type": ["string", "null"] },
"currency": { "type": "string", "pattern": "^[A-Z]{3}$", "default": "USD" },
"subtotal": { "type": ["number", "null"] },
"tax_amount": { "type": ["number", "null"] },
"freight_amount": { "type": ["number", "null"] },
"total_amount": { "type": "number" },
"original_invoice_number": { "type": ["string", "null"], "description": "Required in practice for credit notes and corrected invoices" },
"line_items": {
"type": "array",
"minItems": 1,
"maxItems": 500,
"items": {
"type": "object",
"required": ["description", "quantity", "unit_price", "line_amount"],
"properties": {
"line_number": { "type": "integer", "minimum": 1 },
"supplier_part_number": { "type": ["string", "null"] },
"description": { "type": "string" },
"quantity": { "type": "number" },
"unit_of_measure": { "type": ["string", "null"] },
"unit_price": { "type": "number" },
"line_amount": { "type": "number" },
"po_line_number": { "type": ["integer", "null"] }
}
}
},
"confidence": {
"type": "object",
"description": "Per-field confidence from the extraction step, 0 to 1",
"additionalProperties": { "type": "number", "minimum": 0, "maximum": 1 }
},
"review": {
"type": "object",
"properties": {
"auto_accept_threshold": { "type": "number", "default": 0.9 },
"flags": { "type": "array", "items": { "type": "string" } }
}
}
},
"additionalProperties": false
}Validation snippet (Python, jsonschema package)
import json
from jsonschema import Draft202012Validator
schema = json.load(open("invoice_schema.json", encoding="utf-8"))
validator = Draft202012Validator(schema)
doc = json.load(open("extracted.json", encoding="utf-8"))
errors = sorted(validator.iter_errors(doc), key=lambda e: list(e.path))
for e in errors:
print("/".join(str(p) for p in e.path), e.message)
business_flags = []
if abs(sum(l["line_amount"] for l in doc["line_items"]) - (doc.get("subtotal") or 0)) > 0.01:
business_flags.append("lines_do_not_match_subtotal")
print("valid" if not errors and not business_flags else "needs review", business_flags)JSON Schema checks structure and types, not arithmetic or master data, so keep business checks such as totals, duplicates and PO matching in code. The format keyword may be treated as an annotation only unless your validator enables format checking. Adjust required fields to your own posting rules.
Want a schema tuned to your ERP posting rules?
Optional: an expert can adapt this schema to your ERP fields and approval flow.
Optional. The tool and every export work without this. No spam.
How to use the schema
Set the title, id, default currency and limits, then copy the schema into a file and validate every extraction result against it. If you use a model with structured output, pass the same schema as the response format so that outputs are constrained to the right shape. The review object carries the auto-accept threshold and any flags, so your approval queue can read it directly.
Design choices explained
Header fields that are always needed for posting are required: document type, supplier, invoice number, date, currency, total and at least one line. Optional fields allow null, which is better than empty strings because a null clearly means not found. The currency uses a three letter pattern to match ISO 4217 codes, and additionalProperties is false so that unexpected fields fail validation.
- document_type controls routing for credit notes and proformas
- original_invoice_number supports credit and corrected invoices
- po_line_number supports line-level matching
- confidence holds per-field scores for review rules
Add business validation next to it
Schema validation passes a document whose lines do not add up to its total. After the structure check, run business rules: line sum versus subtotal, subtotal plus tax versus total, duplicate invoice number per supplier, supplier match against the vendor master, and PO price and quantity tolerance. Record each failure as a flag so that the reviewer knows why the document stopped.
Common mistakes
Making every field required forces the model or OCR to invent values, which is worse than a null. Another mistake is to allow free text in the date field. Use the date format and normalize before validation. Finally, version your schema with the id and keep older versions for audit, since stored extractions must still be readable later.
Frequently Asked Questions
What is JSON Schema used for in invoice automation?
It defines the exact structure and types of extracted data, so that bad outputs from OCR or a language model are rejected automatically. It also documents the contract between the extraction step and the ERP integration.
Should the schema include confidence scores?
Yes, as an optional object keyed by field name. Confidence values drive review rules, for example sending documents to a person when the total or the invoice number is below your threshold. They do not replace business validation.
Does JSON Schema validate that totals add up?
No. It checks structure, types and simple constraints. Arithmetic, duplicates and master data matching must be coded as separate business rules that run after the schema validation.
Can I use this schema with an LLM structured output feature?
Often yes, but supported keywords vary by provider and model server. Some support only a subset of JSON Schema, so test the schema and simplify keywords such as type arrays or format if your tool rejects them.
If you want extraction results validated and posted to your ERP with human approval, Netray can build the service and keep it on your own servers.
Related Tools
Invoice Field Regex Generator (Python)
Set the labels your suppliers use and get a Python script with regexes for invoice number, PO number, invoice date and total amount, plus a total check.
Supply Chain & InventoryInvoice Document Type Codes Reference (UNTDID 1001, X12, EDIFACT)
Look up what invoice type codes such as 380, 381 and 389 mean, and map them to the X12 transaction sets and EDIFACT messages used for purchasing, shipping, invoicing and payment.
AI Agents & AutomationDocument AI and OCR Pilot Readiness Checklist
A practical checklist covering sample selection, ground truth labeling, success metrics, security and ERP posting before you start an OCR or document AI pilot.
Developer ToolsTesseract OCR Command Line Generator
Build the exact tesseract command for a single file and a PowerShell loop for a whole folder, with language, page segmentation mode, resolution and output format set from a form.
More Developer Tools tools
See all- SAP Sales Order ABAP SELECT Generator (VBAK, VBAP, VBFA)
- SAP Sales Order Create BAPI ABAP Generator (BAPI_SALESORDER_CREATEFROMDAT2)
- SAP ABAP Open Items SELECT Generator
- SAP ACDOCA SQL Query Generator
- SAP QM Inspection Lot ABAP SELECT Generator
- SAP Quality Notification Pareto SQL Query Generator
- SAP QM Usage Decision BAPI Skeleton
- ABAP Custom Exception Class Generator
- ABAP Unit Test Class Generator