API v1 documentation
German energy invoices
Separate German electricity and natural-gas invoice packets, then extract each invoice’s identity, supply points, consumption, readings, charges, taxes, balances, due dates, and payment data.
Supported invoices
Use this profile when you need an integration-ready German electricity or natural-gas supply invoice: who supplied it, which customer and supply point it belongs to, how much energy was consumed, how the amount was calculated, what remains payable or refundable, and how payment should happen. Profile 2.0.1 is designed for invoice posting, spend and consumption analysis, supply-point onboarding, payment preparation, and exception review.
- Input format
- One text-based, hybrid, or scanned PDF invoice packet
- Customer
- Musterwerke GmbH
- Billing period
- 2024-01-01 to 2024-12-31
- Supply point
- Werkstraße 14, 70173 Stuttgart
- Market location (MaLo)
- 12345678905
- Meter
- MTR-EXAMPLE-001
- Billed energy
- 15,482 kWh
- Outstanding amount
- EUR 406.83 due 2025-03-03
Annual, final, periodic, monthly, and other clearly identified German supply invoices are recognized. One PDF can contain an invoice with its detail and annex pages, or multiple independently issued invoices. Each independently issued invoice is returned as a separate item in physical source order. A single invoice can still describe multiple electricity or natural-gas supply points and a sequence of meters at one location.
Data available from the invoice
| Data group | Returned data | Typical use |
|---|---|---|
| Invoice | Kind, document number, issue date, billing period, and currency. | Identify and reconcile the source document. |
| Parties | Supplier name, customer name, and customer billing address. | Match supplier and customer records. |
| Customer relationship | Customer number, debtor number, business-partner number, membership number, contract account, and contract number when shown. | Link the invoice to an account or contract. |
| Supply points and tariffs | Commodity, service address, market-location ID (MaLo), metering-location IDs (MeLo), product, tariff, and grid or metering operators. | Identify the physical supply and its commercial context. |
| Meters and consumption | Meter assignments, registers, dated readings and reading methods, billed or metered quantities, units, periods, and historical/forecast context. | Build consumption and document-backed meter history. |
| Natural-gas conversion | Volume difference, condition number, calorific value, energy basis, and calculated energy for each conversion segment. | Audit the conversion from cubic metres to kWh. |
| Charges and taxes | Energy, base-price, network, metering, levy, tax, carbon-cost, discount, surcharge, and adjustment rows with quantities, unit prices, net, tax, and gross amounts. | Post or analyze the invoice at line level. |
| Settlement and payment | Invoice totals, advance and other payments, outstanding amount or credit, due date, payment method/status, references, installment schedules, and bank accounts. | Prepare payment or refund workflows. |
| Packet structure | Invoice page ranges, unassigned pages, packet classification, boundary blockers, and one stable invoice_ref per issued invoice. | Separate independently issued invoices without losing their source-page ownership. |
| Quality and review | Per-invoice outcomes, per-field status, validation signals, source evidence, and packet-level workflow state. | Automate verified data and route uncertain values to the correct invoice review. |
Values that are not visible or cannot be supported by the document are returned as JSON null, never placeholder strings such as "unknown". Collections are empty when the invoice provides no supported rows. Use invoices[].data.field_quality to distinguish verified, missing, redacted, and review-required values.
Common invoice labels and JSON paths
| English term and German invoice label | JSON path | Example |
|---|---|---|
| Invoice number (Rechnungsnummer) | invoices[].data.document.document_number | RE-EXAMPLE-2025-10 |
| Billing period (Abrechnungszeitraum) | invoices[].data.document.billing_period_start and billing_period_end | 2024-01-01 to 2024-12-31 |
| Customer number (Kundennummer) | invoices[].data.customer_relationships[].identifiers[] with type=customer_number | CUSTOMER-EXAMPLE-001 |
| Market location (Marktlokation, MaLo) | invoices[].data.supply_points[].market_location_id | 12345678905 |
| Metering location (Messlokation, MeLo) | invoices[].data.supply_points[].metering_locations[].metering_location_id | DEEXAMPLE000000000000000000000000 |
| Meter number (Zählernummer) | invoices[].data.supply_points[].meter_assignments[].meter_number | MTR-EXAMPLE-001 |
| Meter reading (Zählerstand) | invoices[].data.supply_points[].readings[].value | 11658.000 m3 |
| Consumption (Verbrauch) | invoices[].data.supply_points[].measurements[].quantity | 15482.000 kWh |
| Outstanding amount (Forderung) | invoices[].data.settlements[].balance_amount where balance_kind=amount_due | 406.83 EUR |
| Payment due date (Fälligkeit) | invoices[].data.settlements[].payment_due_date | 2025-03-03 |
Upload a PDF invoice
Every active account can select de.energy.supply-invoice explicitly with the normal document upload. New uploads use profile version 2.0.1 and schema version 2.0.0. It accepts PDF uploads and requires processing_mode=extraction with AI processing enabled. If extraction_profile is omitted, exdata always uses generic document extraction.
curl -sS -X POST "https://www.exdata.app/api/v1/documents" \
-H "Authorization: Bearer $EXDATA_API_TOKEN" \
-H "Idempotency-Key: energy-invoice-2025-001" \
-F "file=@./energy-invoice.pdf" \
-F "locale=de" \
-F "extraction_profile=de.energy.supply-invoice"
custom_types[] extends generic classification labels. It does not activate specialized profile fields or replace extraction_profile. The profile uses the document upload, polling, extraction, review, and export endpoints; it does not add a separate profile-result endpoint.
The optional requester field remains available as upload metadata and does not affect profile extraction.
Example response
The business data you normally map is under sector_extraction.effective_payload.invoices[].data. The surrounding packet object accounts for the PDF and each invoice item supplies its own page range, outcomes, source components, and validation state. This example shows a single invoice at invoices[0]; the same array contains multiple independently issued invoices when they share one PDF. It omits the required document.references, field_quality, validation_summary, and source_components values to keep the business relationships visible; the complete payload appears in Result metadata. Use effective_payload rather than machine_payload so reviewed corrections are reflected automatically.
{
"sector_extraction": {
"effective_outcome": "accepted",
"handoff_status": "accepted",
"effective_payload": {
"packet": {
"ref": "packet_123",
"classification": {
"kind": "invoice_packet",
"document_kind": "annual_invoice"
},
"physical_page_count": 2,
"unassigned_pages": [],
"unassigned_physical_pages": [],
"blockers": [],
"review_reasons": [],
"warnings": []
},
"invoices": [
{
"invoice_ref": "invoice_5f2db86e322d058b2bfd",
"page_range": {
"start": 1,
"end": 2
},
"physical_pages": [
1,
2
],
"machine_outcome": "accepted",
"effective_outcome": "accepted",
"handoff_status": "accepted",
"review_reasons": [],
"warnings": [],
"data": {
"document": {
"ref": "document_1",
"kind": "annual_invoice",
"document_number": "RE-EXAMPLE-2025-10",
"issue_date": "2025-02-14",
"billing_period_start": "2024-01-01",
"billing_period_end": "2024-12-31",
"currency": "EUR"
},
"supplier": {
"ref": "supplier_1",
"legal_name": "Beispiel Energie GmbH",
"brand_name": null
},
"customer": {
"ref": "customer_1",
"name": "Musterwerke GmbH",
"billing_address": {
"raw": "Werkstraße 14, 70173 Stuttgart",
"street": "Werkstraße",
"house_number": "14",
"postal_code": "70173",
"city": "Stuttgart",
"country_code": "DE"
}
},
"customer_relationships": [
{
"ref": "relationship_1",
"supplier_ref": "supplier_1",
"customer_ref": "customer_1",
"supply_point_refs": [
"supply_point_1"
],
"identifiers": [
{
"type": "customer_number",
"value": "CUSTOMER-EXAMPLE-001",
"normalized_value": "CUSTOMER-EXAMPLE-001",
"scope_type": "customer_relationship",
"entity_ref": "relationship_1",
"lineage": "current",
"valid_from": null,
"valid_to": null,
"status": "verified"
},
{
"type": "contract_account",
"value": "ACCOUNT-EXAMPLE-001",
"normalized_value": "ACCOUNT-EXAMPLE-001",
"scope_type": "customer_relationship",
"entity_ref": "relationship_1",
"lineage": "current",
"valid_from": null,
"valid_to": null,
"status": "verified"
},
{
"type": "contract_number",
"value": "CONTRACT-EXAMPLE-001",
"normalized_value": "CONTRACT-EXAMPLE-001",
"scope_type": "customer_relationship",
"entity_ref": "relationship_1",
"lineage": "current",
"valid_from": null,
"valid_to": null,
"status": "verified"
}
]
}
],
"supply_points": [
{
"ref": "supply_point_1",
"commodity": "natural_gas",
"service_address": {
"raw": "Werkstraße 14, 70173 Stuttgart",
"street": "Werkstraße",
"house_number": "14",
"postal_code": "70173",
"city": "Stuttgart",
"country_code": "DE"
},
"market_location_id": "12345678905",
"legacy_metering_point_id": null,
"metering_locations": [
{
"ref": "metering_location_1",
"metering_location_id": "DEEXAMPLE000000000000000000000000"
}
],
"meter_assignments": [
{
"ref": "meter_assignment_1",
"metering_location_ref": "metering_location_1",
"meter_number": "MTR-EXAMPLE-001",
"component_ref": "component_cdd6bf8f85d49227",
"observed_from": "2024-01-01",
"observed_to": "2024-12-31",
"installed_at": null,
"removed_at": null
}
],
"product_name": "GasFix 24",
"tariff_name": "Business Gas 2024",
"operators": [
{
"ref": "operator_1",
"supply_point_ref": "supply_point_1",
"role": "grid_operator",
"name": "Beispiel Netze GmbH",
"operator_code": "9900123400007",
"valid_from": "2024-01-01",
"valid_to": "2024-12-31"
}
],
"registers": [
{
"ref": "register_1",
"supply_point_ref": "supply_point_1",
"scope_type": "meter_assignment",
"scope_ref": "meter_assignment_1",
"register_code": "gas_volume",
"measurement_kind": "gas_volume",
"direction": "consumption",
"unit": "m3"
}
],
"readings": [
{
"ref": "reading_1",
"supply_point_ref": "supply_point_1",
"scope_type": "meter_assignment",
"scope_ref": "meter_assignment_1",
"register_ref": "register_1",
"reading_role": "period_start",
"read_at": "2024-01-01",
"value": "10234.000",
"unit": "m3",
"read_method": "network_read",
"raw_read_method": "Netzbetreiberablesung"
},
{
"ref": "reading_2",
"supply_point_ref": "supply_point_1",
"scope_type": "meter_assignment",
"scope_ref": "meter_assignment_1",
"register_ref": "register_1",
"reading_role": "period_end",
"read_at": "2024-12-31",
"value": "11658.000",
"unit": "m3",
"read_method": "network_read",
"raw_read_method": "Netzbetreiberablesung"
}
],
"measurements": [
{
"ref": "measurement_1",
"supply_point_ref": "supply_point_1",
"scope_type": "supply_point",
"scope_ref": "supply_point_1",
"register_ref": "register_1",
"kind": "billed_energy",
"quantity": "15482.000",
"unit": "kWh",
"period_start": "2024-01-01",
"period_end": "2024-12-31",
"energy_basis": "gross_calorific_value_hs",
"context": "current_billing_period",
"summary_level": "summary"
}
],
"gas_conversion_segments": [
{
"ref": "gas_conversion_segment_1",
"supply_point_ref": "supply_point_1",
"scope_type": "meter_assignment",
"scope_ref": "meter_assignment_1",
"register_ref": "register_1",
"start_reading_ref": "reading_1",
"end_reading_ref": "reading_2",
"measurement_ref": "measurement_1",
"period_start": "2024-01-01",
"period_end": "2024-12-31",
"volume_difference": "1424.000",
"volume_unit": "m3",
"condition_number": "0.9600",
"calorific_value": "11.3252",
"calorific_value_unit": "kWh/m3",
"energy_basis": "gross_calorific_value_hs",
"calculated_energy": "15482.000",
"energy_unit": "kWh"
}
]
}
],
"charge_lines": [
{
"ref": "charge_line_1",
"scope_type": "supply_point",
"scope_ref": "supply_point_1",
"supply_point_ref": "supply_point_1",
"settlement_ref": "settlement_1",
"component_ref": "component_cdd6bf8f85d49227",
"commodity": "natural_gas",
"category": "energy_consumption",
"description": "Energy charge (Arbeitspreis)",
"period_start": "2024-01-01",
"period_end": "2024-12-31",
"quantity": "15482.000",
"quantity_unit": "kWh",
"unit_price_amount": "0.0835",
"unit_price_currency": "EUR",
"unit_price_currency_scale": "major_unit",
"unit_price_basis_quantity": "1",
"unit_price_basis_unit": "kWh",
"net_amount": "1292.75",
"tax_rate": "19.00",
"tax_amount": "245.62",
"gross_amount": "1538.37",
"currency": "EUR",
"effect": "increases_cost"
},
{
"ref": "charge_line_2",
"scope_type": "supply_point",
"scope_ref": "supply_point_1",
"supply_point_ref": "supply_point_1",
"settlement_ref": "settlement_1",
"component_ref": "component_cdd6bf8f85d49227",
"commodity": "natural_gas",
"category": "base_price",
"description": "Base price (Grundpreis)",
"period_start": "2024-01-01",
"period_end": "2024-12-31",
"quantity": "12",
"quantity_unit": "month",
"unit_price_amount": "15.00",
"unit_price_currency": "EUR",
"unit_price_currency_scale": "major_unit",
"unit_price_basis_quantity": "1",
"unit_price_basis_unit": "month",
"net_amount": "180.00",
"tax_rate": "19.00",
"tax_amount": "34.20",
"gross_amount": "214.20",
"currency": "EUR",
"effect": "increases_cost"
},
{
"ref": "charge_line_3",
"scope_type": "supply_point",
"scope_ref": "supply_point_1",
"supply_point_ref": "supply_point_1",
"settlement_ref": "settlement_1",
"component_ref": "component_cdd6bf8f85d49227",
"commodity": "natural_gas",
"category": "carbon_cost",
"description": "Carbon cost (CO₂-Kosten)",
"period_start": "2024-01-01",
"period_end": "2024-12-31",
"quantity": null,
"quantity_unit": null,
"unit_price_amount": null,
"unit_price_currency": null,
"unit_price_currency_scale": null,
"unit_price_basis_quantity": null,
"unit_price_basis_unit": null,
"net_amount": "45.60",
"tax_rate": "19.00",
"tax_amount": "8.66",
"gross_amount": "54.26",
"currency": "EUR",
"effect": "increases_cost"
}
],
"tax_breakdowns": [
{
"ref": "tax_breakdown_1",
"scope_type": "settlement",
"scope_ref": "settlement_1",
"supply_point_ref": "supply_point_1",
"settlement_ref": "settlement_1",
"charge_line_ref": null,
"commodity": "natural_gas",
"taxable_amount": "1518.35",
"tax_amount": "288.49",
"tax_rate": "19.00",
"taxability": "taxable",
"tax_collection_mechanism": "seller_collected",
"tax_exemption_reason": null,
"currency": "EUR"
}
],
"settlements": [
{
"ref": "settlement_1",
"scope_type": "document",
"scope_ref": "document_1",
"supply_point_ref": "supply_point_1",
"commodity": "natural_gas",
"currency": "EUR",
"net_amount": "1518.35",
"tax_amount": "288.48",
"gross_amount": "1806.83",
"advance_payments_amount": "1400.00",
"other_payments_amount": "0.00",
"adjustments": [],
"balance_kind": "amount_due",
"balance_amount": "406.83",
"payment_due_date": "2025-03-03",
"disposition": {
"ref": "payment_disposition_1",
"settlement_ref": "settlement_1",
"action": "payment_due",
"payment_method": "bank_transfer",
"status": "requested",
"date": "2025-03-03",
"payment_account_ref": "payment_account_1",
"payment_reference": "RE-EXAMPLE-2025-10",
"mandate_reference": null,
"creditor_identifier": null
},
"installment_plans": []
}
],
"payment_accounts": [
{
"ref": "payment_account_1",
"scope_type": "settlement",
"scope_ref": "settlement_1",
"supply_point_ref": "supply_point_1",
"settlement_ref": "settlement_1",
"role": "supplier_collection_account",
"account_holder": "Beispiel Energie GmbH",
"iban": "DE89370400440532013000",
"bic": "COBADEFFXXX",
"bank_name": "Beispielbank"
}
],
"detected_commodities": [
"natural_gas"
]
}
}
]
}
}
}
All names and identifiers in this example are synthetic. Entity ref values are illustrative opaque IDs; store and return the exact refs supplied by your response instead of constructing or parsing them.
The data map contains the flat generic extraction fields. This is the outer extraction response map, not an invoice item's nested data object. It is not the complete energy result and its candidates are not profile evidence. Read supply identities, tariffs, operators, readings, consumption, gas conversion, charges, taxes, settlement totals, outstanding amounts, due dates, and payment accounts from each sector_extraction.effective_payload.invoices[].data object.
Read the result after processing
Poll GET /api/v1/documents/{document}, or consume lifecycle webhooks, until the document reaches a terminal status: completed, error, or blocked. When sector_extraction_summary is present, read the complete result from its extractions_url.
| Step | Request and use |
|---|---|
| Poll document | GET /documents/{document} returns data.sector_extraction_summary for a delivered result. Use it to detect review work without loading the complete payload. |
| Read result | GET /documents/{document}/extractions returns sector_extraction with the complete energy payload, quality state, and decisions. |
| Inspect evidence | Add ?include=evidence when building a review UI or checking the source page and text supporting a value. |
curl -sS "https://www.exdata.app/api/v1/documents/123/extractions" \
-H "Authorization: Bearer $EXDATA_API_TOKEN"
Compact document summary
sector_extraction_summary appears on a completed document for routing and workflow views. If all profile attempts fail, an error document can expose a canonical failed summary instead; a blocked upload has no extraction result.
{
"data": {
"id": 123,
"status": "completed",
"sector_extraction_summary": {
"id": 789,
"extraction_run_id": 456,
"profile": "de.energy.supply-invoice",
"profile_version": "2.0.1",
"schema_version": "2.0.0",
"machine_outcome": "accepted",
"effective_outcome": "accepted",
"handoff_status": "accepted",
"review_reasons": [],
"handoff_review_reasons": [],
"warnings": [],
"lock_version": 0,
"etag": "\"extraction-result-789-v0\"",
"extractions_url": "https://www.exdata.app/api/v1/documents/123/extractions",
"exports": {
"canonical_json": {
"url": "https://www.exdata.app/api/v1/documents/123/exports/canonical.json",
"version": "de-energy-canonical-json:2.0.0",
"available": true
},
"invoice_lines_csv": {
"url": "https://www.exdata.app/api/v1/documents/123/exports/invoice-lines.csv",
"version": "de-energy-invoice-lines-csv:2.0.0",
"available": true
}
}
}
}
}
Returned fields
effective_payload always contains exactly two top-level properties: packet and invoices. This is true for a single invoice, a multi-invoice PDF, and a source-verified non-invoice. The packet accounts for physical pages; each invoice keeps its own values, evidence, and references inside a bounded page range.
| Property | Type | Meaning |
|---|---|---|
packet.ref | String | Stable reference for the uploaded PDF packet. |
packet.classification | Object | kind is invoice_packet, non_invoice, or unknown; document_kind and optional evidence explain that classification. |
packet.physical_page_count | Integer | Total physical PDF pages considered by the profile. |
packet.unassigned_pages[] | Object[] | Pages not owned by an invoice, classified as blank, cover, non_invoice, or ambiguous. The companion unassigned_physical_pages[] contains only their page numbers. |
packet.blockers[] | Object[] | Boundary problems with a stable code and, when known, phase, invoice, and physical pages. |
packet.review_reasons[] / warnings[] | String[] | Packet-level review reasons and non-blocking warnings. |
invoices[] | Object[] | One item per independently issued invoice in physical source order. A single-invoice PDF still returns one item; a source-verified non-invoice returns an empty array. |
Invoice result
| Property | Type | Meaning |
|---|---|---|
invoice_ref | String | Stable invoice reference for joins and the required scope for field confirmation or correction. |
page_range | Object | Inclusive start and end physical PDF pages. |
physical_pages[] | Integer[] | Contiguous pages owned by this invoice. |
machine_outcome / effective_outcome / handoff_status | String | Invoice-local extraction, reviewed, and downstream readiness states. |
review_reasons[] / warnings[] | String[] | Invoice-local review reasons and non-blocking warnings. |
validation_summary | Object | Invoice-local field counts, reconciliation checks, and handoff diagnostics. |
source_components[] | Object[] | Invoice-scoped source groups whose pages are contained by this invoice. |
data | Object | Source-evidenced invoice business fields described below. |
Invoice data
Inside each invoices[].data object, stable ref and *_ref values join related rows without relying on array position. All eleven properties below are always present; arrays are empty when the invoice contains no applicable rows.
| Property | Type | Meaning |
|---|---|---|
document | Object | Invoice identity, type, dates, currency, and document-scoped references. |
supplier | Object or null | Supplier legal and brand names. |
customer | Object or null | Customer name and billing address. |
customer_relationships[] | Object[] | Supplier/customer relationship identifiers linked explicitly to supply points. |
supply_points[] | Object[] | Electricity or natural-gas delivery locations, market-location IDs (MaLo), metering-location IDs (MeLo), and meter history. |
charge_lines[] | Object[] | Itemized charges with scope, quantity, unit price, tax rate, and net/tax/gross amounts. |
tax_breakdowns[] | Object[] | Tax rows linked to a document, supply point, settlement, or charge line. |
settlements[] | Object[] | Invoice totals, payments, balance, due date, payment disposition, and installment schedules. |
payment_accounts[] | Object[] | Supplier collection or customer refund/direct-debit accounts shown on the invoice. |
detected_commodities[] | String[] | All utility signals detected in the packet: electricity, natural_gas, or other. |
field_quality[] | Object[] | Entity-scoped field status, validation signals, and optional evidence. |
Document and parties
| Field | Type | Example or rule |
|---|---|---|
document.ref | String | Stable entity reference such as document_1. |
document.kind | String | annual_invoice, final_invoice, periodic_invoice, monthly_invoice, invoice, contract_confirmation, advance_payment_notice, price_notice, welcome_letter, tariff_notice, energy_mix_annex, other, or unknown. |
document.document_number | String or null | Visible invoice/document number, for example RE-EXAMPLE-2025-10. A populated value also appears as an invoice_number item in document.references[]. |
document.issue_date | Date or null | ISO YYYY-MM-DD. |
document.billing_period_start / billing_period_end | Date or null | Inclusive ISO billing-period boundaries. |
document.currency | String or null | Uppercase ISO-4217 code such as EUR. |
document.references[] | Typed identifier[] | Document-scoped typed identifiers. A populated document_number always adds invoice_number; source-scoped internal or membership references can also appear here. |
supplier | Object or null | ref, legal_name, and brand_name. |
customer | Object or null | ref, name, and billing_address. |
Address object
Both customer.billing_address and supply_points[].service_address use the same shape. The billing address and physical supply address are deliberately separate.
| Field | Type | Example |
|---|---|---|
raw | String or null | Werkstraße 14, 70173 Stuttgart. |
street | String or null | Werkstraße. |
house_number | String or null | 14. |
postal_code | String or null | 70173. |
city | String or null | Stuttgart. |
country_code | String or null | Uppercase ISO-3166-1 alpha-2 code such as DE. |
Typed identifiers
document.references[] and customer_relationships[].identifiers[] share one explicit object. Missing values are JSON null; the API never substitutes "unknown", an empty string, or the literal string "null".
| Field | Type | Values and meaning |
|---|---|---|
type | String | Full-invoice profile versions 2.0.0 and 2.0.1 emit invoice_number, internal_document_reference, customer_number, customer_debtor_number, business_partner_number, membership_number, contract_account, and contract_number. The owning array and scope_type preserve their document-backed scope. |
value | String or null | Display value supported by the document. |
normalized_value | String or null | Whitespace/casing-normalized value used for comparison. |
scope_type | String | document, customer_relationship, supply_point, metering_location, or meter_assignment. |
entity_ref | String | Reference of the owning entity. |
lineage | String | current, former, successor, or unknown. |
valid_from / valid_to | Date or null | Optional ISO validity range. |
status | String | verified, needs_review, missing, or redacted. |
Market-location IDs (MaLo), legacy metering-point IDs, metering-location IDs (MeLo), meter numbers, and operator codes are canonical scalar properties on their owning supply-point, metering-location, meter-assignment, or operator objects. Do not look for them in either typed-identifier array.
Relationships, supply points, and meters
| Field | Type | Meaning |
|---|---|---|
customer_relationships[].ref | String | Stable relationship reference. |
customer_relationships[].supplier_ref / customer_ref | String | Links the relationship to the party objects. |
customer_relationships[].supply_point_refs[] | String[] | Explicit supply-point associations for the relationship. |
customer_relationships[].identifiers[] | Typed identifier[] | Customer, debtor, business-partner, membership, contract-account, contract, or internal-reference values. |
supply_points[].ref | String | Stable supply-point reference. |
supply_points[].commodity | String | electricity or natural_gas. other is detection-only and never creates a supply point. |
supply_points[].service_address | Address or null | Physical delivery/consumption address. |
supply_points[].market_location_id | String or null | Market-location ID (MaLo) in its source/display form. After display whitespace is removed: 11 digits, beginning with 1–9, with a valid check digit. |
supply_points[].legacy_metering_point_id | String or null | Legacy technical identifier when explicitly shown. |
supply_points[].metering_locations[].ref | String | Stable metering-location (MeLo) entity reference. |
supply_points[].metering_locations[].metering_location_id | String or null | Metering-location ID (MeLo): after display whitespace is removed, DE followed by 31 letters or digits. |
supply_points[].meter_assignments[].ref | String | Stable meter-history reference. |
supply_points[].meter_assignments[].metering_location_ref | String or null | Optional link to the owning metering location. |
supply_points[].meter_assignments[].meter_number | String or null | 4–32 allowed characters and at least one digit. |
supply_points[].meter_assignments[].component_ref | String or null | Source component in which the assignment was observed. |
supply_points[].meter_assignments[].observed_from / observed_to | Date or null | Period for which the document associates the meter. |
supply_points[].meter_assignments[].installed_at / removed_at | Date or null | Reserved lifecycle fields; full-invoice profile versions 2.0.0 and 2.0.1 return null. Use observed_from, observed_to, and readings with reading_role=meter_installation or meter_removal for document-backed history. |
Explicit source labels for former values (ehemalig, alt, or vormals) or future values (zukünftig) are preserved as lineage and are not treated as current values. Use entity ref values when displaying or submitting field review.
Multiple supply points and a meter replacement
This effective_payload.invoices[0].data fragment shows why the profile uses arrays and references. One relationship can link to multiple supply points, and sequential meters remain assignments under one supply point instead of creating duplicate locations.
{
"customer_relationships": [
{
"ref": "relationship_1",
"supplier_ref": "supplier_1",
"customer_ref": "customer_1",
"supply_point_refs": [
"supply_point_1",
"supply_point_2"
],
"identifiers": []
}
],
"supply_points": [
{
"ref": "supply_point_1",
"commodity": "electricity",
"service_address": {
"raw": "Werkstraße 1, 10115 Berlin",
"street": "Werkstraße",
"house_number": "1",
"postal_code": "10115",
"city": "Berlin",
"country_code": "DE"
},
"market_location_id": "12345678905",
"legacy_metering_point_id": null,
"metering_locations": [
{
"ref": "metering_location_1",
"metering_location_id": "DEEXAMPLE000000000000000000000000"
}
],
"meter_assignments": [
{
"ref": "meter_assignment_1",
"metering_location_ref": "metering_location_1",
"meter_number": "MTR-OLD-1",
"component_ref": "component_cdd6bf8f85d49227",
"observed_from": "2024-01-01",
"observed_to": "2024-06-30",
"installed_at": null,
"removed_at": null
},
{
"ref": "meter_assignment_2",
"metering_location_ref": "metering_location_1",
"meter_number": "MTR-NEW-2",
"component_ref": "component_cdd6bf8f85d49227",
"observed_from": "2024-07-01",
"observed_to": "2024-12-31",
"installed_at": null,
"removed_at": null
}
]
},
{
"ref": "supply_point_2",
"commodity": "natural_gas",
"service_address": {
"raw": "Werkstraße 2, 10115 Berlin",
"street": "Werkstraße",
"house_number": "2",
"postal_code": "10115",
"city": "Berlin",
"country_code": "DE"
},
"market_location_id": "98765432105",
"legacy_metering_point_id": null,
"metering_locations": [],
"meter_assignments": [
{
"ref": "meter_assignment_3",
"metering_location_ref": null,
"meter_number": "GAS-9001",
"component_ref": "component_cdd6bf8f85d49227",
"observed_from": null,
"observed_to": null,
"installed_at": null,
"removed_at": null
}
]
}
],
"detected_commodities": [
"electricity",
"natural_gas"
]
}
Tariffs, operators, registers, and readings
Supply-point detail rows use stable references rather than array indexes. supply_point_ref always identifies the parent supply point. For register, reading, measurement, and gas-conversion rows, scope_type says whether the value applies to a supply_point, metering_location, or meter_assignment; scope_ref contains that entity's ref.
| Field | Type | Meaning |
|---|---|---|
supply_points[].product_name / tariff_name | String or null | Supplier product and tariff names as shown on the invoice. |
operators[].role | String or null | grid_operator or metering_operator. |
operators[].name / operator_code | String or null | Named operator and source/display identifier, with optional valid_from and valid_to. |
registers[].register_code | String or null | Printed register/OBIS-style code such as 1.8.0. |
registers[].measurement_kind | String or null | active_energy, reactive_energy, demand, gas_volume, or other. |
registers[].direction | String or null | consumption, feed_in, bidirectional, or other. |
readings[].reading_role | String or null | period_start, period_end, intermediate, meter_installation, meter_removal, comparison, or other. |
readings[].read_at / value / unit | Date / decimal string / string or null | Dated meter reading with units such as kWh or m3. |
readings[].read_method | String or null | customer_read, network_read, remote_read, load_profile, calculated, estimated, substitute_value, or other. raw_read_method preserves the printed wording. |
Consumption and gas conversion
| Field | Type | Meaning |
|---|---|---|
measurements[].kind | String or null | billed_energy, metered_energy, reactive_energy, measured_demand, billed_demand, gas_volume, or other. |
measurements[].quantity / unit | Decimal string / string or null | Document-backed quantity and unit, for example 15482.000 kWh. Keep the value as a decimal string until your posting or analytics layer chooses a precision. |
measurements[].period_start / period_end | Date or null | Period to which the measured or billed quantity applies. |
measurements[].context | String or null | current_billing_period, historical_comparison, forecast, disclosure, or other. Use this field to avoid posting comparison/forecast values as current consumption. |
measurements[].summary_level | String or null | detail or summary. Do not sum both levels without applying your own deduplication rule. |
gas_conversion_segments[].volume_difference | Decimal string or null | Consumed gas volume in volume_unit, currently m3. |
condition_number / calorific_value | Decimal string or null | Condition number and calorific value used by the printed conversion; calorific_value_unit is kWh/m3. |
calculated_energy / energy_unit | Decimal string / string or null | Energy produced by the conversion. start_reading_ref, end_reading_ref, and measurement_ref link the calculation to its inputs and billed result. |
Charge lines and taxes
Money and tax rates are returned as dot-decimal strings with exactly two fractional digits. Quantities and unit prices are decimal strings that preserve the supported source precision. effect tells you whether a positive amount increases or decreases invoice cost.
| Field | Type | Meaning |
|---|---|---|
charge_lines[].category | String or null | energy_consumption, base_price, demand_price, metering, meter_operation, grid_usage, concession_fee, levy, energy_tax, carbon_cost, discount, relief, surcharge, service_fee, adjustment, or other. |
description / period_start / period_end | String / dates or null | Printed line description and applicable charge period. |
quantity / quantity_unit | Decimal string / string or null | Billed units such as kWh, kW, cubic metres, days, months, years, or items. |
unit_price_amount / unit_price_currency | Decimal string / currency or null | Unit price. unit_price_currency_scale distinguishes major_unit from cent; the basis quantity and unit preserve prices such as EUR per 100 kWh. |
net_amount / tax_amount / gross_amount | Amount string or null | Line amounts excluding tax, tax amount, and amount including tax. currency is an uppercase ISO-4217 code. |
tax_breakdowns[].taxable_amount / tax_amount | Signed amount string or null | Tax base and tax amount; signed values allow documented tax corrections. |
tax_rate / taxability | Decimal string / string or null | Percent rate and taxable, zero_rated, exempt, or out_of_scope. |
tax_collection_mechanism | String or null | seller_collected, reverse_charge, buyer_use_tax, or not_collected. An exemption explanation is returned in tax_exemption_reason. |
Settlement, outstanding amount, and payment
| Field | Type | Meaning |
|---|---|---|
settlements[].net_amount / tax_amount / gross_amount | Amount string or null | Invoice totals before tax, tax total, and total including tax. |
advance_payments_amount / other_payments_amount | Amount string or null | Payments already applied to the invoice. |
adjustments[] | Object[] | Relief, discount, rebate, fee, surcharge, correction, or other adjustments, with effect and whether the amount is included in or applied after the gross amount. |
balance_kind / balance_amount | String / amount string or null | amount_due, credit, or settled, plus the absolute outstanding/refund amount. |
payment_due_date | Date or null | Printed due date for the balance. |
disposition.action | String or null | payment_due, refund, carry_forward, bank_details_required, or none. |
disposition.payment_method / status | String or null | Payment method and requested, scheduled, completed, cancelled, or other status, with an optional date, account ref, payment reference, mandate reference, and creditor identifier. |
installment_plans[] | Object[] | Plan totals, frequency, first/last due dates, count, and a dated schedule[] of installment amounts/statuses. |
payment_accounts[].role | String or null | supplier_collection_account, customer_refund_account, customer_direct_debit_account, or other. |
account_holder / iban / bic / bank_name | String or null | Document-backed bank account details. Use scope_type, scope_ref, supply_point_ref, and settlement_ref to select the correct account for a payment or refund. |
Download exports
Accepted full-invoice profile versions 2.0.0 and 2.0.1 advertise two deterministic exports in sector_extraction.exports. Use the returned URL only when its available value is true; before acceptance the URL stays stable and returns 409 profile_export_not_ready.
| Descriptor | Route and contract | Output |
|---|---|---|
canonical_json | /documents/{document}/exports/canonical.jsonde-energy-canonical-json:2.0.0 | application/json; charset=UTF-8 containing profile, profile_version, schema_version, effective_outcome, and the complete packet-shaped effective_payload. It retains packet, every invoices[] item, and nested field_quality[].evidence for audit use. |
invoice_lines_csv | /documents/{document}/exports/invoice-lines.csvde-energy-invoice-lines-csv:2.0.0 | text/csv; charset=UTF-8 with one row per invoices[].data.charge_lines[] item. Its leading columns identify the owning invoice and source page range. It is also available as an all-or-nothing batch export for 1–100 documents. |
curl -L "https://www.exdata.app/api/v1/documents/123/exports/canonical.json" \
-H "Authorization: Bearer $EXDATA_API_TOKEN" \
-o energy-invoice-123.json
curl -L "https://www.exdata.app/api/v1/documents/exports/invoice-lines.csv?document_ids[]=123&document_ids[]=456" \
-H "Authorization: Bearer $EXDATA_API_TOKEN" \
-o invoice-lines.csv
Invoice-line CSV columns
Columns are emitted in this stable order:
invoice_ref,invoice_ordinal,invoice_start_page,invoice_end_page,document_id,profile_result_id,document_ref,document_number,supply_point_ref,market_location_id,settlement_ref,charge_line_ref,component_ref,scope_type,scope_ref,commodity,category,description,period_start,period_end,quantity,quantity_unit,unit_price_amount,unit_price_currency,unit_price_currency_scale,unit_price_basis_quantity,unit_price_basis_unit,net_amount,tax_rate,tax_amount,gross_amount,currency,effect
invoice_ordinal is one-based physical source order; invoice_start_page and invoice_end_page are inclusive. Batch rows are sorted by ascending document_id, then preserve invoice and charge-line order. Text that begins with a spreadsheet formula marker is prefixed with an apostrophe; valid signed numeric cells remain numeric.
Quality and evidence
Because the source invoice is German, evidence label and text values preserve the document's original language.
Every field_quality[] item identifies one profile-defined quality or review target by entity_ref and field. Most targets name a direct property, while a composite target such as billing_period summarizes billing_period_start and billing_period_end. Do not derive a payload path from field; use json_pointer only when it is non-null. status is verified, needs_review, missing, or redacted, and signals[] contains extensible reason or validation codes.
| Quality field | Type | Description |
|---|---|---|
entity_ref | String | Stable reference of the document, party, relationship, supply point, metering location, meter assignment, operator, register, reading, measurement, gas-conversion segment, charge, tax row, settlement, payment disposition, installment, or payment account. |
field | String | Profile-defined quality/review target, for example direct customer_number or composite billing_period. It is not guaranteed to be a property name. |
json_pointer | String or null | Exact path within the versioned payload when available; null for composite or otherwise non-addressable targets. |
status | String | verified, needs_review, missing, or redacted. |
signals | String[] | Extensible machine-readable checks and reasons such as checksum_valid or ocr_character_ambiguity. |
evidence | Object[] | Source citations, included only when the response is requested with include=evidence. |
The profile does not invent a numeric confidence percentage. Use the closed status, the supporting signals and evidence, plus the result and handoff outcomes as the automation contract.
The compact response recursively omits embedded properties named evidence. Request include=evidence when building a review screen or investigating a field. The response then retains each invoices[].data.field_quality[].evidence array and packet-classification evidence, and adds flattened top-level evidence[] plus sorted, unique evidence_pages[]. Each flattened German energy evidence item carries its owning invoice_ref.
curl -sS "https://www.exdata.app/api/v1/documents/123/extractions?include=evidence" \
-H "Authorization: Bearer $EXDATA_API_TOKEN"
Needs-review evidence example
This focused response excerpt shows an OCR ambiguity between the letter O and digit 0. Unchanged payload and envelope properties are omitted only to keep the evidence relationship visible.
{
"sector_extraction": {
"machine_outcome": "needs_review",
"effective_outcome": "needs_review",
"handoff_status": "needs_review",
"review_reasons": [
"ocr_character_ambiguity"
],
"handoff_review_reasons": [],
"effective_payload": {
"packet": {
"ref": "packet_123",
"classification": {
"kind": "invoice_packet",
"document_kind": "annual_invoice"
},
"physical_page_count": 2,
"unassigned_pages": [],
"unassigned_physical_pages": [],
"blockers": [],
"review_reasons": [],
"warnings": []
},
"invoices": [
{
"invoice_ref": "invoice_5f2db86e322d058b2bfd",
"page_range": {
"start": 1,
"end": 2
},
"physical_pages": [
1,
2
],
"effective_outcome": "needs_review",
"data": {
"customer_relationships": [
{
"ref": "relationship_1",
"supplier_ref": "supplier_1",
"customer_ref": "customer_1",
"supply_point_refs": [
"supply_point_1"
],
"identifiers": [
{
"type": "customer_number",
"value": "KUNDE-1O",
"normalized_value": "KUNDE-1O",
"scope_type": "customer_relationship",
"entity_ref": "relationship_1",
"lineage": "current",
"valid_from": null,
"valid_to": null,
"status": "needs_review"
}
]
}
],
"field_quality": [
{
"entity_ref": "relationship_1",
"field": "customer_number",
"json_pointer": null,
"status": "needs_review",
"signals": [
"exact_source_match",
"label_compatible",
"ocr_alphanumeric_ambiguity",
"ocr_character_ambiguity",
"ocr_field_confidence_low",
"pixel_corroborated",
"tesseract_only"
],
"evidence": [
{
"component_ref": "component_8a1f74f0f1d8c2ab",
"physical_page": 1,
"printed_page": "1",
"label": "Kundennummer",
"text": "Kundennummer KUNDE-1O",
"source": "tesseract_ocr",
"match": "exact",
"bbox": null
}
]
}
]
}
}
]
},
"evidence": [
{
"invoice_ref": "invoice_5f2db86e322d058b2bfd",
"entity_ref": "relationship_1",
"field": "customer_number",
"field_status": "needs_review",
"component_ref": "component_8a1f74f0f1d8c2ab",
"physical_page": 1,
"printed_page": "1",
"label": "Kundennummer",
"text": "Kundennummer KUNDE-1O",
"source": "tesseract_ocr",
"match": "exact",
"bbox": null
}
],
"evidence_pages": [
{
"physical_page": 1,
"available": true,
"preview_url": "https://www.exdata.app/api/v1/documents/123/extraction-runs/456/pages/1/preview"
}
]
}
}
| Evidence field | Type | Description |
|---|---|---|
component_ref | String | Source component such as the primary invoice, invoice detail, portal snapshot, annex, or annotation. |
physical_page | Integer | One-based physical PDF page used for verification. |
printed_page | String or null | Optional page label printed on the document. |
label / text | String or null / String | Visible label and short supporting text span. |
source | String | native_text, embedded_ocr, tesseract_ocr, or combined. |
match | String | exact, normalized, or manual. |
reviewer_transcribed | Boolean | Present as true when an authorized reviewer supplied correction evidence text manually. |
bbox | Object or null | Optional page bounding box with x, y, width, and height. |
The top-level flattened evidence[] is immutable machine evidence and includes invoice_ref. Reviewer-supplied citations remain visible inside effective_payload.invoices[].data.field_quality[].evidence and review_decisions[].evidence_reference. The latter is returned even in compact mode because the evidence switch only removes properties literally named evidence.
Evidence page previews
Each evidence_pages[] item contains physical_page, available, and preview_url. When the safe persisted page artifact exists, available=true and the protected URL has the form /api/v1/documents/{document}/extraction-runs/{extractionRun}/pages/{physicalPage}/preview. The URL requires the same account-scoped documents:read access as the extraction result. Missing, expired, unsafe, or non-matching artifacts remain explicit as available=false with preview_url=null; exdata never substitutes a page from another run.
Result outcomes
The document processing status tells you whether the extraction attempt completed. Profile outcomes separately describe whether the complete packet is usable, needs review, or is not a supported invoice. Each effective_payload.invoices[] item also exposes invoice-local outcomes so a review UI can show exactly which invoice and fields need attention.
| Field | Values | Use |
|---|---|---|
machine_outcome | accepted, needs_review, unsupported, failed | Immutable outcome produced by extraction and validation. |
effective_outcome | Machine values plus rejected | Current outcome after append-only review decisions. |
handoff_status | accepted, needs_review, unsupported, rejected | Whether the result meets the requirements for downstream handoff. |
Choose the next action
Do not import a result only because the document has status=completed. Check the envelope's effective_outcome and handoff_status together, then inspect each invoice's corresponding states before acting on effective_payload.invoices[].data. The packet is accepted only when every invoice and the packet boundary are accepted.
| Current state | Recommended integration action |
|---|---|
effective_outcome=accepted and handoff_status=accepted | Use the effective payload for downstream processing. |
Either field is needs_review | Hold automatic import and inspect the cited fields and evidence. |
effective_outcome=unsupported | Treat the upload as a non-invoice. Confirm effective_payload.packet.classification.kind=non_invoice and effective_payload.invoices=[]; do not create supply-point records. |
effective_outcome=failed | Handle the extraction failure; there is no usable profile payload. |
effective_outcome=rejected | Stop downstream processing. The reviewed result is terminally rejected. |
Reason and warning arrays contain extensible machine-readable strings rather than closed enums. Store unknown codes and use the outcome fields for control flow.
A source-verified non-invoice such as a price notice, contract confirmation, or advance-payment notice (for example, advance-payment plan (Abschlagsplan) or advance-payment notice (Abschlagsmitteilung)) returns unsupported with packet metadata and invoices=[]. An incomplete document is never finalized as unsupported, even when its visible pages resemble a known non-invoice; it stays needs_review until a new, complete extraction can reassess the packet. A successful extraction can also return needs_review when a critical identifier, amount, reconciliation, boundary, or its evidence is uncertain.
A PDF with multiple independently issued invoices returns one source-ordered invoices[] item per validated page range. Their entity refs, source components, evidence, supply points, charges, and settlements remain invoice-scoped. Ambiguous page ownership returns needs_review with document_structure_ambiguous; affected pages appear in packet.unassigned_pages or packet.blockers instead of being attached to the wrong invoice.
Full-invoice profile versions 2.0.0 and 2.0.1 also fail closed for an incomplete mixed-utility detail packet when visible electricity or natural-gas data cannot be associated safely with non-target utility content. The result stays needs_review with mixed_commodity_scope_ambiguous and produces no downstream rows. Upload the complete invoice packet or separate the target-energy invoice before retrying.
For common German invoice layouts, full-invoice profile versions 2.0.0 and 2.0.1 can conservatively recover a missing invoice date or billing period from narrow, source-backed text patterns. Recovery is used only when document evidence is unique and structurally consistent; competing dates or periods remain unresolved and require review.
Review a result
List documents requiring review with GET /api/v1/documents?extraction_profile=de.energy.supply-invoice&review_status=needs_review, then read GET /api/v1/documents/{document}/extractions. The extraction response returns an ETag; send it as If-Match with every decision. Review tokens require the extractions:review ability. Add documents:read when the integration also needs field values or the full reviewed payload in the write response.
Include optional review_duration_seconds when the reviewer measured the active human-review time used to reach that individual decision. The accepted range is 1–86,400 seconds. This caller-supplied value is workflow telemetry, not queue age or wall-clock elapsed time. Omission or null means the duration was not measured, leaves duration coverage incomplete, and is never treated as zero.
| Action | Required body fields | Behavior |
|---|---|---|
confirm | invoice_ref, entity_ref, field | Confirms the current non-empty value and its cited evidence inside exactly one invoice. |
correct | invoice_ref, entity_ref, field, corrected_value, evidence_reference | Stores an audited correction with a fresh citation from a page owned by that invoice, then revalidates the invoice and aggregate packet. Most values are strings; billing periods and service or billing addresses use objects. |
reject | reason | Rejects the complete packet. Rejection is terminal and must omit invoice_ref. |
Stored decision fields
Every newly applied decision appends one object to sector_extraction.review_decisions[]. An idempotent replay returns the existing decision without appending or mutating the result. A review write returns data.decision plus the updated data.sector_extraction; a review-only token without documents:read receives a reduced audit response without payload values.
| Field | Type | Description |
|---|---|---|
id | Integer | Decision ID. |
action | String | confirm, correct, or reject. |
invoice_ref | String or null | Reviewed invoice for confirmation or correction; null for complete-packet rejection. |
entity_ref / field | String or null | Reviewed target; null for complete-result rejection. |
reason | String or null | Reviewer-supplied explanation. |
previous_value / corrected_value | JSON value or null | Audited value transition. |
evidence_reference | Object or null | Reviewer citation used by the decision. |
review_duration_seconds | Integer or null | Caller-supplied workflow telemetry containing measured active human-review time for the decision; null is unmeasured rather than zero. |
reviewer_user_id / account_api_token_id | Integer or null | Authenticated reviewer identity. |
previous_effective_outcome / resulting_effective_outcome | String | Outcome transition. |
previous_handoff_status / resulting_handoff_status | String | Handoff transition. |
expected_lock_version / resulting_lock_version | Integer | Optimistic-concurrency transition. |
idempotency_key_prefix | String | Non-secret prefix retained for retry audit. |
created_at | Date-time or null | Decision time. |
curl -sS -X POST "https://www.exdata.app/api/v1/documents/123/extractions/reviews" \
-H "Authorization: Bearer $EXDATA_REVIEW_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: correct-customer-number-123" \
-H 'If-Match: "extraction-result-789-v0"' \
--data '{
"action": "correct",
"invoice_ref": "invoice_5f2db86e322d058b2bfd",
"entity_ref": "relationship_1",
"field": "customer_number",
"corrected_value": "KUNDE-10",
"reason": "Confirmed against the printed account block.",
"review_duration_seconds": 95,
"evidence_reference": {
"component_ref": "component_8a1f74f0f1d8c2ab",
"physical_page": 1,
"printed_page": "1",
"label": "Kundennummer",
"text": "Kundennummer KUNDE-10",
"source": "native_text",
"match": "manual"
}
}'
Any identical retry with the same idempotency key is replayed without appending another decision. A different payload with the same key returns 409 idempotency_conflict. A stale ETag returns 409 extraction_version_conflict. As soon as both effective_outcome and handoff_status are accepted, the accepted handoff is terminal; every later decision returns a 422 validation error and cannot change the accepted snapshot.
Both confirmation and correction require the target invoice's invoice_ref and evidence that supports the reviewed value on one of that invoice's physical pages. Identifier evidence needs a type-compatible label inside the evidence text. Supplier and customer names need the correct party role; service and billing addresses need the correct address role. Every populated structured address component must occur in raw, and an explicit country code must be visible as the country name or uppercase code. Technical identifiers are normalized and format-checked for both actions. Market-location IDs (MaLo) and legacy metering-point values belong to a supply point, metering-location IDs (MeLo) to a metering location, meter numbers to a meter assignment, and operator_code to an operator; values cannot be moved into a different entity collection or invoice.
For a manual correction, exdata verifies that the cited component, physical page, and selected text source belong to the requested invoice in the recorded page manifest. The authorized reviewer transcribes the visible label and text; exdata stores reviewer_transcribed=true and does not compare that transcription with OCR or native extracted text. This permits correction of OCR errors, so grant extractions:review only to trusted reviewers and submit text only after visually checking the cited page.
The response always keeps machine_payload unchanged and returns the reviewed value only in the selected effective_payload.invoices[] item. Other invoices remain unchanged, and the packet outcome is recalculated from all invoice and packet states. Selected generic fields in the outer response data map follow the effective packet only when it contains exactly one safe accepted invoice. Structural candidate/grouping conflicts remain in review until a new extraction can re-evaluate the original candidate set. Confirming or correcting a value does not clear an ambiguous supply-point association; affected relationship identifiers remain in review in the canonical payload until a new extraction resolves the association.
Customer-facing reads use the newest usable profile result. A later failed retry remains in the extraction-run audit history but does not hide that result. If every attempt failed, the latest failure remains visible. The complete canonical result, including reviewed values, relationship identifiers, supply points, meter history, and evidence descriptors, is available from GET /api/v1/documents/{document}/extractions. Reprocessing an existing document preserves the profile version, processing settings, and credit rate recorded for that document. Profile setting changes apply to new uploads only.
Result metadata
Use the result envelope for workflow, audit, concurrency, and versioning. Map business data from effective_payload.invoices[].data and packet structure from effective_payload.packet. Interpret the nested payload by the exact combination of profile, profile_version, and schema_version.
Accepted result details
The first tab shows the complete packet plus a representative invoice whose data contains all eleven business-data groups used at both machine_payload and the initial effective_payload. Repeated detail and quality arrays are representative rather than exhaustive, so use the field tables as the contract. The second is a focused response-envelope excerpt with flat summary values and result metadata; it omits unpopulated flat fields and the two large payload snapshots.
{
"packet": {
"ref": "packet_123",
"classification": {
"kind": "invoice_packet",
"document_kind": "annual_invoice"
},
"physical_page_count": 2,
"unassigned_pages": [],
"unassigned_physical_pages": [],
"blockers": [],
"review_reasons": [],
"warnings": []
},
"invoices": [
{
"invoice_ref": "invoice_5f2db86e322d058b2bfd",
"page_range": {
"start": 1,
"end": 2
},
"physical_pages": [
1,
2
],
"machine_outcome": "accepted",
"effective_outcome": "accepted",
"handoff_status": "accepted",
"review_reasons": [],
"warnings": [],
"validation_summary": {
"outcome_reason": null,
"machine_review_reasons": [],
"structural_review_reasons": [],
"document_kind": "annual_invoice",
"supply_point_count": 1,
"field_status_counts": {
"verified": 30,
"missing": 1
},
"handoff_projection": "de.energy.prior-supplier-overview@1",
"handoff_status": "accepted",
"handoff_review_reasons": [],
"full_invoice_checks": {
"referential_integrity": {
"status": "passed",
"duplicate_refs": [],
"unknown_references": [],
"missing_scope_references": [],
"inconsistent_references": []
},
"value_validation": [],
"date_ranges": [],
"gas_reconciliations": [
{
"entity_ref": "gas_conversion_segment_1",
"check": "volume_times_condition_number_times_calorific_value",
"status": "passed"
}
],
"monetary_reconciliations": [
{
"entity_ref": "settlement_1",
"check": "settlement_net_plus_tax_equals_gross",
"status": "passed"
}
]
}
},
"source_components": [
{
"ref": "component_8a1f74f0f1d8c2ab",
"kind": "primary_invoice",
"physical_pages": [
1
],
"precedence": 1
},
{
"ref": "component_cdd6bf8f85d49227",
"kind": "invoice_detail",
"physical_pages": [
2
],
"precedence": 2
}
],
"data": {
"document": {
"ref": "document_1",
"kind": "annual_invoice",
"document_number": "RE-EXAMPLE-2025-10",
"issue_date": "2025-02-14",
"billing_period_start": "2024-01-01",
"billing_period_end": "2024-12-31",
"currency": "EUR",
"references": [
{
"type": "invoice_number",
"value": "RE-EXAMPLE-2025-10",
"normalized_value": "RE-EXAMPLE-2025-10",
"scope_type": "document",
"entity_ref": "document_1",
"lineage": "unknown",
"valid_from": null,
"valid_to": null,
"status": "verified"
}
]
},
"supplier": {
"ref": "supplier_1",
"legal_name": "Beispiel Energie GmbH",
"brand_name": null
},
"customer": {
"ref": "customer_1",
"name": "Musterwerke GmbH",
"billing_address": {
"raw": "Werkstraße 14, 70173 Stuttgart",
"street": "Werkstraße",
"house_number": "14",
"postal_code": "70173",
"city": "Stuttgart",
"country_code": "DE"
}
},
"customer_relationships": [
{
"ref": "relationship_1",
"supplier_ref": "supplier_1",
"customer_ref": "customer_1",
"supply_point_refs": [
"supply_point_1"
],
"identifiers": [
{
"type": "customer_number",
"value": "CUSTOMER-EXAMPLE-001",
"normalized_value": "CUSTOMER-EXAMPLE-001",
"scope_type": "customer_relationship",
"entity_ref": "relationship_1",
"lineage": "current",
"valid_from": null,
"valid_to": null,
"status": "verified"
},
{
"type": "contract_account",
"value": "ACCOUNT-EXAMPLE-001",
"normalized_value": "ACCOUNT-EXAMPLE-001",
"scope_type": "customer_relationship",
"entity_ref": "relationship_1",
"lineage": "current",
"valid_from": null,
"valid_to": null,
"status": "verified"
},
{
"type": "contract_number",
"value": "CONTRACT-EXAMPLE-001",
"normalized_value": "CONTRACT-EXAMPLE-001",
"scope_type": "customer_relationship",
"entity_ref": "relationship_1",
"lineage": "current",
"valid_from": null,
"valid_to": null,
"status": "verified"
}
]
}
],
"supply_points": [
{
"ref": "supply_point_1",
"commodity": "natural_gas",
"service_address": {
"raw": "Werkstraße 14, 70173 Stuttgart",
"street": "Werkstraße",
"house_number": "14",
"postal_code": "70173",
"city": "Stuttgart",
"country_code": "DE"
},
"market_location_id": "12345678905",
"legacy_metering_point_id": null,
"metering_locations": [
{
"ref": "metering_location_1",
"metering_location_id": "DEEXAMPLE000000000000000000000000"
}
],
"meter_assignments": [
{
"ref": "meter_assignment_1",
"metering_location_ref": "metering_location_1",
"meter_number": "MTR-EXAMPLE-001",
"component_ref": "component_cdd6bf8f85d49227",
"observed_from": "2024-01-01",
"observed_to": "2024-12-31",
"installed_at": null,
"removed_at": null
}
],
"product_name": "GasFix 24",
"tariff_name": "Business Gas 2024",
"operators": [
{
"ref": "operator_1",
"supply_point_ref": "supply_point_1",
"role": "grid_operator",
"name": "Beispiel Netze GmbH",
"operator_code": "9900123400007",
"valid_from": "2024-01-01",
"valid_to": "2024-12-31"
}
],
"registers": [
{
"ref": "register_1",
"supply_point_ref": "supply_point_1",
"scope_type": "meter_assignment",
"scope_ref": "meter_assignment_1",
"register_code": "gas_volume",
"measurement_kind": "gas_volume",
"direction": "consumption",
"unit": "m3"
}
],
"readings": [
{
"ref": "reading_1",
"supply_point_ref": "supply_point_1",
"scope_type": "meter_assignment",
"scope_ref": "meter_assignment_1",
"register_ref": "register_1",
"reading_role": "period_start",
"read_at": "2024-01-01",
"value": "10234.000",
"unit": "m3",
"read_method": "network_read",
"raw_read_method": "Netzbetreiberablesung"
},
{
"ref": "reading_2",
"supply_point_ref": "supply_point_1",
"scope_type": "meter_assignment",
"scope_ref": "meter_assignment_1",
"register_ref": "register_1",
"reading_role": "period_end",
"read_at": "2024-12-31",
"value": "11658.000",
"unit": "m3",
"read_method": "network_read",
"raw_read_method": "Netzbetreiberablesung"
}
],
"measurements": [
{
"ref": "measurement_1",
"supply_point_ref": "supply_point_1",
"scope_type": "supply_point",
"scope_ref": "supply_point_1",
"register_ref": "register_1",
"kind": "billed_energy",
"quantity": "15482.000",
"unit": "kWh",
"period_start": "2024-01-01",
"period_end": "2024-12-31",
"energy_basis": "gross_calorific_value_hs",
"context": "current_billing_period",
"summary_level": "summary"
}
],
"gas_conversion_segments": [
{
"ref": "gas_conversion_segment_1",
"supply_point_ref": "supply_point_1",
"scope_type": "meter_assignment",
"scope_ref": "meter_assignment_1",
"register_ref": "register_1",
"start_reading_ref": "reading_1",
"end_reading_ref": "reading_2",
"measurement_ref": "measurement_1",
"period_start": "2024-01-01",
"period_end": "2024-12-31",
"volume_difference": "1424.000",
"volume_unit": "m3",
"condition_number": "0.9600",
"calorific_value": "11.3252",
"calorific_value_unit": "kWh/m3",
"energy_basis": "gross_calorific_value_hs",
"calculated_energy": "15482.000",
"energy_unit": "kWh"
}
]
}
],
"charge_lines": [
{
"ref": "charge_line_1",
"scope_type": "supply_point",
"scope_ref": "supply_point_1",
"supply_point_ref": "supply_point_1",
"settlement_ref": "settlement_1",
"component_ref": "component_cdd6bf8f85d49227",
"commodity": "natural_gas",
"category": "energy_consumption",
"description": "Energy charge (Arbeitspreis)",
"period_start": "2024-01-01",
"period_end": "2024-12-31",
"quantity": "15482.000",
"quantity_unit": "kWh",
"unit_price_amount": "0.0835",
"unit_price_currency": "EUR",
"unit_price_currency_scale": "major_unit",
"unit_price_basis_quantity": "1",
"unit_price_basis_unit": "kWh",
"net_amount": "1292.75",
"tax_rate": "19.00",
"tax_amount": "245.62",
"gross_amount": "1538.37",
"currency": "EUR",
"effect": "increases_cost"
},
{
"ref": "charge_line_2",
"scope_type": "supply_point",
"scope_ref": "supply_point_1",
"supply_point_ref": "supply_point_1",
"settlement_ref": "settlement_1",
"component_ref": "component_cdd6bf8f85d49227",
"commodity": "natural_gas",
"category": "base_price",
"description": "Base price (Grundpreis)",
"period_start": "2024-01-01",
"period_end": "2024-12-31",
"quantity": "12",
"quantity_unit": "month",
"unit_price_amount": "15.00",
"unit_price_currency": "EUR",
"unit_price_currency_scale": "major_unit",
"unit_price_basis_quantity": "1",
"unit_price_basis_unit": "month",
"net_amount": "180.00",
"tax_rate": "19.00",
"tax_amount": "34.20",
"gross_amount": "214.20",
"currency": "EUR",
"effect": "increases_cost"
},
{
"ref": "charge_line_3",
"scope_type": "supply_point",
"scope_ref": "supply_point_1",
"supply_point_ref": "supply_point_1",
"settlement_ref": "settlement_1",
"component_ref": "component_cdd6bf8f85d49227",
"commodity": "natural_gas",
"category": "carbon_cost",
"description": "Carbon cost (CO₂-Kosten)",
"period_start": "2024-01-01",
"period_end": "2024-12-31",
"quantity": null,
"quantity_unit": null,
"unit_price_amount": null,
"unit_price_currency": null,
"unit_price_currency_scale": null,
"unit_price_basis_quantity": null,
"unit_price_basis_unit": null,
"net_amount": "45.60",
"tax_rate": "19.00",
"tax_amount": "8.66",
"gross_amount": "54.26",
"currency": "EUR",
"effect": "increases_cost"
}
],
"tax_breakdowns": [
{
"ref": "tax_breakdown_1",
"scope_type": "settlement",
"scope_ref": "settlement_1",
"supply_point_ref": "supply_point_1",
"settlement_ref": "settlement_1",
"charge_line_ref": null,
"commodity": "natural_gas",
"taxable_amount": "1518.35",
"tax_amount": "288.49",
"tax_rate": "19.00",
"taxability": "taxable",
"tax_collection_mechanism": "seller_collected",
"tax_exemption_reason": null,
"currency": "EUR"
}
],
"settlements": [
{
"ref": "settlement_1",
"scope_type": "document",
"scope_ref": "document_1",
"supply_point_ref": "supply_point_1",
"commodity": "natural_gas",
"currency": "EUR",
"net_amount": "1518.35",
"tax_amount": "288.48",
"gross_amount": "1806.83",
"advance_payments_amount": "1400.00",
"other_payments_amount": "0.00",
"adjustments": [],
"balance_kind": "amount_due",
"balance_amount": "406.83",
"payment_due_date": "2025-03-03",
"disposition": {
"ref": "payment_disposition_1",
"settlement_ref": "settlement_1",
"action": "payment_due",
"payment_method": "bank_transfer",
"status": "requested",
"date": "2025-03-03",
"payment_account_ref": "payment_account_1",
"payment_reference": "RE-EXAMPLE-2025-10",
"mandate_reference": null,
"creditor_identifier": null
},
"installment_plans": []
}
],
"payment_accounts": [
{
"ref": "payment_account_1",
"scope_type": "settlement",
"scope_ref": "settlement_1",
"supply_point_ref": "supply_point_1",
"settlement_ref": "settlement_1",
"role": "supplier_collection_account",
"account_holder": "Beispiel Energie GmbH",
"iban": "DE89370400440532013000",
"bic": "COBADEFFXXX",
"bank_name": "Beispielbank"
}
],
"detected_commodities": [
"natural_gas"
],
"field_quality": [
{
"entity_ref": "document_1",
"field": "kind",
"json_pointer": null,
"status": "verified",
"signals": [
"exact_source_match"
]
},
{
"entity_ref": "document_1",
"field": "document_number",
"json_pointer": null,
"status": "verified",
"signals": [
"exact_source_match",
"label_compatible"
]
},
{
"entity_ref": "document_1",
"field": "issue_date",
"json_pointer": null,
"status": "verified",
"signals": [
"exact_source_match",
"label_compatible"
]
},
{
"entity_ref": "document_1",
"field": "billing_period_start",
"json_pointer": null,
"status": "verified",
"signals": [
"exact_source_match",
"label_compatible"
]
},
{
"entity_ref": "document_1",
"field": "billing_period_end",
"json_pointer": null,
"status": "verified",
"signals": [
"exact_source_match",
"label_compatible"
]
},
{
"entity_ref": "document_1",
"field": "billing_period",
"json_pointer": null,
"status": "verified",
"signals": [
"exact_source_match",
"label_compatible"
]
},
{
"entity_ref": "document_1",
"field": "currency",
"json_pointer": null,
"status": "verified",
"signals": [
"exact_source_match"
]
},
{
"entity_ref": "supplier_1",
"field": "legal_name",
"json_pointer": null,
"status": "verified",
"signals": [
"exact_source_match",
"explicit_role_label",
"label_compatible",
"party_role_validated"
]
},
{
"entity_ref": "customer_1",
"field": "name",
"json_pointer": null,
"status": "verified",
"signals": [
"exact_source_match",
"explicit_role_label",
"label_compatible",
"party_role_validated"
]
},
{
"entity_ref": "customer_1",
"field": "billing_address",
"json_pointer": null,
"status": "verified",
"signals": [
"exact_source_match",
"label_compatible"
]
},
{
"entity_ref": "relationship_1",
"field": "customer_number",
"json_pointer": null,
"status": "verified",
"signals": [
"exact_source_match",
"label_compatible"
]
},
{
"entity_ref": "relationship_1",
"field": "contract_account",
"json_pointer": null,
"status": "verified",
"signals": [
"exact_source_match",
"label_compatible"
]
},
{
"entity_ref": "relationship_1",
"field": "contract_number",
"json_pointer": null,
"status": "verified",
"signals": [
"exact_source_match",
"label_compatible"
]
},
{
"entity_ref": "supply_point_1",
"field": "commodity",
"json_pointer": null,
"status": "verified",
"signals": [
"exact_source_match",
"label_compatible"
]
},
{
"entity_ref": "supply_point_1",
"field": "service_address",
"json_pointer": null,
"status": "verified",
"signals": [
"exact_source_match",
"label_compatible"
]
},
{
"entity_ref": "supply_point_1",
"field": "market_location_id",
"json_pointer": null,
"status": "verified",
"signals": [
"exact_source_match",
"label_compatible",
"format_valid",
"checksum_valid"
]
},
{
"entity_ref": "supply_point_1",
"field": "legacy_metering_point_id",
"json_pointer": null,
"status": "missing",
"signals": []
},
{
"entity_ref": "metering_location_1",
"field": "metering_location_id",
"json_pointer": null,
"status": "verified",
"signals": [
"exact_source_match",
"label_compatible"
]
},
{
"entity_ref": "meter_assignment_1",
"field": "meter_number",
"json_pointer": null,
"status": "verified",
"signals": [
"exact_source_match",
"label_compatible"
]
},
{
"entity_ref": "meter_assignment_1",
"field": "observed_from",
"json_pointer": null,
"status": "verified",
"signals": [
"exact_source_match",
"label_compatible"
]
},
{
"entity_ref": "meter_assignment_1",
"field": "observed_to",
"json_pointer": null,
"status": "verified",
"signals": [
"exact_source_match",
"label_compatible"
]
},
{
"entity_ref": "operator_1",
"field": "operator_code",
"json_pointer": null,
"status": "verified",
"signals": [
"exact_source_match",
"label_compatible"
]
},
{
"entity_ref": "reading_1",
"field": "value",
"json_pointer": null,
"status": "verified",
"signals": [
"exact_source_match",
"label_compatible"
]
},
{
"entity_ref": "reading_2",
"field": "value",
"json_pointer": null,
"status": "verified",
"signals": [
"exact_source_match",
"label_compatible"
]
},
{
"entity_ref": "measurement_1",
"field": "quantity",
"json_pointer": null,
"status": "verified",
"signals": [
"exact_source_match",
"unit_valid"
]
},
{
"entity_ref": "gas_conversion_segment_1",
"field": "calculated_energy",
"json_pointer": null,
"status": "verified",
"signals": [
"exact_source_match",
"reconciled"
]
},
{
"entity_ref": "charge_line_1",
"field": "net_amount",
"json_pointer": null,
"status": "verified",
"signals": [
"exact_source_match",
"reconciled"
]
},
{
"entity_ref": "tax_breakdown_1",
"field": "tax_amount",
"json_pointer": null,
"status": "verified",
"signals": [
"exact_source_match",
"reconciled"
]
},
{
"entity_ref": "settlement_1",
"field": "balance_amount",
"json_pointer": null,
"status": "verified",
"signals": [
"exact_source_match",
"reconciled"
]
},
{
"entity_ref": "settlement_1",
"field": "payment_due_date",
"json_pointer": null,
"status": "verified",
"signals": [
"exact_source_match",
"label_compatible"
]
},
{
"entity_ref": "payment_account_1",
"field": "iban",
"json_pointer": null,
"status": "verified",
"signals": [
"exact_source_match",
"format_valid",
"checksum_valid"
]
}
]
}
}
]
}
{
"data": {
"document_number": {
"value": "RE-EXAMPLE-2025-10",
"candidates": [
"RE-EXAMPLE-2025-10"
]
},
"date": {
"value": "2025-02-14",
"candidates": [
"2025-02-14"
]
},
"currency": {
"value": "EUR",
"candidates": [
"EUR"
]
},
"sender_name": {
"value": "Beispiel Energie GmbH",
"candidates": [
"Beispiel Energie GmbH"
]
},
"recipient_name": {
"value": "Musterwerke GmbH",
"candidates": [
"Musterwerke GmbH"
]
}
},
"sector_extraction": {
"id": 789,
"document_id": 123,
"extraction_run_id": 456,
"profile": "de.energy.supply-invoice",
"profile_version": "2.0.1",
"schema_version": "2.0.0",
"machine_outcome": "accepted",
"effective_outcome": "accepted",
"handoff_status": "accepted",
"review_reasons": [],
"handoff_review_reasons": [],
"warnings": [],
"lock_version": 0,
"etag": "\"extraction-result-789-v0\"",
"acceptance_source": "machine",
"reviewed_at": null,
"validation_summary": {
"machine_review_reasons": [],
"structural_review_reasons": [],
"packet_review_reasons": [],
"unassigned_physical_pages": [],
"invoice_count": 1,
"field_status_counts": {
"verified": 30,
"missing": 1
},
"handoff_projection": "de.energy.prior-supplier-overview@1",
"handoff_status": "accepted",
"handoff_review_reasons": [],
"invoices": [
{
"invoice_ref": "invoice_5f2db86e322d058b2bfd",
"machine_outcome": "accepted",
"effective_outcome": "accepted",
"handoff_status": "accepted"
}
]
},
"source_components": [
{
"invoice_ref": "invoice_5f2db86e322d058b2bfd",
"ref": "component_8a1f74f0f1d8c2ab",
"kind": "primary_invoice",
"physical_pages": [
1
],
"precedence": 1
},
{
"invoice_ref": "invoice_5f2db86e322d058b2bfd",
"ref": "component_cdd6bf8f85d49227",
"kind": "invoice_detail",
"physical_pages": [
2
],
"precedence": 2
}
],
"review_decisions": [],
"exports": {
"canonical_json": {
"url": "https://www.exdata.app/api/v1/documents/123/exports/canonical.json",
"version": "de-energy-canonical-json:2.0.0",
"available": true
},
"invoice_lines_csv": {
"url": "https://www.exdata.app/api/v1/documents/123/exports/invoice-lines.csv",
"version": "de-energy-invoice-lines-csv:2.0.0",
"available": true
}
},
"created_at": "2026-02-15T10:00:00.000000Z",
"updated_at": "2026-02-15T10:00:00.000000Z"
}
}
| Field | Type | Description and example |
|---|---|---|
id | Integer | Profile-result ID, for example 789. |
document_id | Integer | Owning document ID, for example 123. |
extraction_run_id | Integer | Immutable source run, for example 456. |
profile | String | de.energy.supply-invoice. |
profile_version | String | Behavior version used for new uploads, currently 2.0.1. Stored 2.0.0 runs remain readable and executable. |
schema_version | String | Version of the nested payload contract, currently 2.0.0. |
machine_outcome | String | Immutable extraction outcome. |
effective_outcome | String | Current result outcome after review. |
handoff_status | String | Whether the result meets the requirements for downstream handoff. |
review_reasons | String[] | Canonical blockers such as ocr_character_ambiguity. |
handoff_review_reasons | String[] | Additional downstream blockers such as a missing verified market-location ID (MaLo). |
warnings | String[] | Non-blocking source or extraction warnings. |
lock_version | Integer | Monotonic version used for optimistic review concurrency. |
etag | String | Current review ETag, for example "extraction-result-789-v0". The HTTP response returns the same value in its ETag header. |
acceptance_source | String or null | machine, human_review, or null while not accepted. |
reviewed_at | Date-time or null | Time of the latest recorded review decision. |
machine_payload | Object or null | Immutable normalized {packet,invoices} payload produced by the run. It is null on a canonical failed result when no finalized usable profile payload exists. |
effective_payload | Object or null | Current {packet,invoices} payload. It initially equals machine_payload, changes only through audited review decisions, and is null when no machine payload exists. |
validation_summary | Object | Versioned diagnostic snapshot from profile validation; see the caveat below. |
source_components | Object[] | Flattened logical source groups with invoice_ref, ref, kind, physical_pages, and precedence. |
evidence | Object[] | Flattened immutable machine evidence with invoice_ref, present only with include=evidence. |
evidence_pages | Object[] | Run-bound cited-page descriptors, present only with include=evidence. |
review_decisions | Object[] | Append-only audit history in application order. |
exports | Object | canonical_json and invoice_lines_csv descriptors with stable url, contract version, and available state. |
created_at / updated_at | Date-time or null | Result creation and last-update times. |
Packet validation summary fields
| Field | Typical type | Meaning |
|---|---|---|
machine_review_reasons | String[] | Machine-time validation blockers. |
structural_review_reasons / packet_review_reasons | String[] | Aggregate structural blockers and the packet-only subset. |
unassigned_physical_pages | Integer[] | Physical pages not owned by a returned invoice. |
invoice_count | Integer | Number of independently issued invoice results. |
field_status_counts | Object | Machine-time field-quality counts aggregated across invoices. |
handoff_projection | String | Validation contract used to determine handoff readiness. |
handoff_status / handoff_review_reasons | String / String[] | Diagnostic handoff state captured by validation. |
invoices[] | Object[] | Compact per-invoice outcome and validation summaries keyed by invoice_ref. |
valid, reviewed, review_reasons, warnings | Mixed | Review diagnostics added after a decision. |
failure_code | String | Failure detail when no finalized usable profile payload exists, including a finalization failure after provisional result persistence. |
Invoice validation summary fields
Each effective_payload.invoices[].validation_summary is bounded to that invoice and includes outcome_reason, machine_review_reasons, structural_review_reasons, document_kind, supply_point_count, field_status_counts, and handoff diagnostics. Its full_invoice_checks contains deterministic referential_integrity, value_validation, date_ranges, gas_reconciliations, and monetary_reconciliations checks. Failed checks contribute invoice and packet review reasons.
validation_summary is diagnostic and extensible. After a review, machine-time entries such as field_status_counts or its nested handoff_status can still describe the original validation snapshot. For current workflow state, use the envelope's top-level effective_outcome, handoff_status, reason arrays, each invoice's current outcomes, and effective_payload.invoices[].data.field_quality.
If every profile attempt fails, the canonical result has machine_outcome=failed, effective_outcome=failed, handoff_status=needs_review, null machine and effective payloads, and a diagnostic validation_summary.failure_code. The owning document can have status=error; this result remains readable for audit through the normal extractions endpoint.
Source component fields
| Field | Type | Description |
|---|---|---|
invoice_ref | String | Owning invoice on flattened envelope-level source components. The same field is unnecessary inside an already scoped invoices[].source_components[] item. |
ref | String | Stable component reference used by evidence and meter assignments. |
kind | String | primary_invoice, invoice_detail, portal_snapshot, annex, form, annotation, or unknown. |
physical_pages | Integer[] | One-based PDF pages belonging to the component. |
precedence | Integer | Profile-defined source priority used when evidence overlaps. |
Profile cost and recorded settings
German energy extraction currently costs 3 credits per started 10-page band: 1–10 processed pages use 3 credits, 11–20 use 6, and 21–30 use 9. latest_extraction_run.credit_cost shows the per-band rate recorded for the run and latest_extraction_run.credits_charged shows the current total. The total is kept when a usable result or retrievable extracted fields remain. Terminal failures that leave neither, and page-band blocks caused by unavailable credits, return the applied credits.
The applicable rate and billing details are returned in the extraction-run metadata. Use credit_cost_source when your integration needs to understand how the returned rate was determined rather than infer it from the profile name. Rates apply to new uploads; reprocessing an existing document preserves the rate recorded for that document.
The selected profile records the processing settings used for each run. The values are returned in latest_extraction_run.ai_model and latest_extraction_run.ai_reasoning_effort, so a queued run remains reproducible when profile settings change.