Das Belegschema
GET /public/v1/files/{file_id}/document und GET /public/v1/documents/{document_id} liefern einen Beleg als ocost.document.v1, in den Begriffen der EN 16931 (der E-Rechnungsnorm hinter XRechnung, ZUGFeRD und Peppol UBL). Jeder Wert nennt seinen Business Term (BT-…) oder seine Gruppe (BG-…) und lässt sich so auf UBL oder CII abbilden.
Das Format ist stabil: Eine inkompatible Änderung kommt als ocost.document.v2 unter /public/v2, v1 bleibt noch 12 Monate erreichbar.
Konventionen
- Beträge und Mengen: Dezimalzeichenketten wie gedruckt (
"1270.92","2.5"), nie Zahlen. Nutzen Sie einen Dezimaltyp. - Sätze: Prozent-Zeichenketten (
"19","7","0","5.5"). - Daten nach ISO 8601 (
2026-11-03), Währungen nach ISO 4217 (EUR), Länder nach ISO 3166-1 alpha-2 (DE). - Einheiten: UNECE-Empfehlung 20 (
C62eins,H87Stück,HURStunde,KGMKilogramm) und Verpackungen der Empfehlung 21 mit ihremX(XCTKarton,XPFPalette). Unbekannt istnull, nieC62. - Fehlt etwas, ist es
null: nicht gedruckt oder verworfen, weil Ocost nicht sicher war. Ocost rät nie.
Die Felder
| Feld | EN 16931 | Bedeutung |
|---|---|---|
schema | Immer "ocost.document.v1". | |
id, file_id | Der Beleg und seine Datei. | |
pages | Seine Seiten in der Datei, ab 1. | |
kind | invoice (jede zu zahlende Rechnung: Abschlags-, Schluss-, Anzahlungs-, Sammel-, Dauerrechnung; type_code sagt, welche), credit_note, invoice_correction, receipt, pro_forma, delivery_note, order, order_confirmation, quote, contract (Miet-, Versicherungs-, sonstige Verträge), statement (Abrechnung eines Factors), payment_reminder, other. kind_detail ist die genaue Art, zur Information. | |
direction | incoming (die Rechnung eines Lieferanten), outgoing (Ihr Unternehmen hat ihn ausgestellt) oder unsure. Ermittelt aus USt-IdNr., Steuernummer und Namen unter Einstellungen › Unternehmen: Halten Sie sie aktuell. | |
type_code | BT-3 | UNCL 1001: 380 Rechnung, 381 Gutschrift, 384 korrigierte Rechnung, 326 Abschlagsrechnung, 386 Anzahlungsrechnung, 389 Gutschriftsverfahren, 325 Proforma. |
number, issue_date, due_date | BT-1, BT-2, BT-9 | Nummer, Rechnungsdatum, Fälligkeit. |
delivery_date | BT-72 | Lieferdatum. |
invoicing_period_start, invoicing_period_end | BT-73, BT-74 | Der abgerechnete Zeitraum. |
valid_until | Bei einem Angebot. | |
currency | BT-5 | Währung. |
buyer_reference | BT-10 | Referenz des Käufers. |
order_reference, order_references | BT-13 | Die Bestellung und jede genannte Bestellung. |
preceding_invoice | BT-25 | Worauf sich eine Gutschrift oder Korrektur bezieht. |
seller, buyer | BG-4, BG-7 | Je: name (BT-27, BT-44), vat_id (BT-31, BT-48), tax_registration_id (BT-32, die Steuernummer), legal_registration_id (BT-30, BT-47, der Registereintrag), address (street, postal_code, city, country), contact (email, phone), website. |
payee | BG-10 | Wer bezahlt wird, wenn nicht der Verkäufer (ein Factor). |
deliver_to | BG-15 | Die Lieferanschrift. |
other_parties[] | Jede weitere genannte Partei, mit role (invoicee, service_recipient, payer, ship_to, carrier, debtor, landlord, tenant, contractor, …) und printed_role (wie gedruckt). | |
payment | BG-16 | means_code (BT-81, UNCL 4461: 58 SEPA-Überweisung, 59 SEPA-Lastschrift, 48 Karte), means (als Wort oder already_paid), iban (BT-84), bic (BT-86), terms (BT-20 wie gedruckt), net_days (Tage bis zur vollen Zahlung ab Rechnungsdatum), paid_on (der Tag, an dem er laut Beleg bezahlt wurde). |
early_payment_discounts[] | BT-20 | Skonto (#SKONTO# der XRechnung): days, percent, base_amount (null: vom fälligen Betrag), due_date (Rechnungsdatum plus days). |
totals | BG-22 | net (BT-109), tax (BT-110), gross (BT-112), payable (BT-115, noch zu zahlen; null, wenn es der Bruttobetrag ist), prices_include_vat (wie auf einer Quittung). |
vat_breakdown[] | BG-23 | category (BT-118, UNCL 5305: S Regelsatz, Z Nullsatz, E steuerfrei, AE Reverse Charge, K innergemeinschaftlich, G Ausfuhr, O nicht steuerbar), rate (BT-119), taxable_amount (BT-116), tax_amount (BT-117), exemption_reason (BT-120). |
lines[] | BG-25 | id (BT-126, die Position), name (BT-153), seller_item_id (BT-155, Artikelnummer), standard_item_id (BT-157, GTIN), quantity (BT-129), unit (BT-130), price (BT-146, netto), base_quantity (BT-149, für wie viele Einheiten price gilt; null: eine), net_amount (BT-131), discount_percent, vat_category (BT-151), vat_rate (BT-152); wo gedruckt, ordered_quantity, backordered_quantity, batch, pzn, attributes (Farbe, Größe, Material, Marke, …). |
deductions[] | Die früheren Rechnungen, die eine Schlussrechnung abzieht: number, issue_date, net, tax, gross. | |
card | Für einen Beleg ohne eigene Felder (ein Prüfbericht, ein Brief): title, summary, facts (label, kind, date, amount, currency, number, text, page), Fristen zuerst. | |
worked_out[] | Ein Betrag, den Ocost ausgerechnet hat, weil der gelesene nicht stimmen kann: field, printed, rule. | |
sources | Je Wert, nach Pfad (number, totals.gross, seller.vat_id, …): page, quote (die gelesenen Worte), confidence und bei Zweifel why. | |
checks[] | Jede Prüfung, die Ocost im Code ausgeführt hat: name, passed, sums (eine Summenprüfung), fields (Pfade), at (der Satz oder die Position). | |
tax_check | Eine Eingangsrechnung nach § 14 UStG: case (standard, small, reverse_charge, intra_eu, exempt) und missing[] (item, law, at_stake: Fehlt es, kostet es den Vorsteuerabzug). Null für Arten, die nicht geprüft werden. | |
attention[] | Worauf ein Mensch vor dem Buchen schauen sollte: sums (eine Summe stimmt nicht), outgoing, possible_duplicate, self_billed (Gutschriftsverfahren). | |
possible_duplicate_of | Ein früherer Beleg derselben Art und Nummer vom selben Verkäufer, sonst null. | |
read_with | e_invoice (genau aus dem XML) oder reader (aus den Seiten). |
confidence in sources:
checked: Eine Prüfung hat den Wert bestätigt, oder er stammt aus einer E-Rechnung.read: Nichts spricht dagegen.doubt: Eine Prüfung schlug fehl (whynennt sie), oder seine Worte stehen nicht auf seiner Seite.
Die Summenprüfungen in checks sind total, vat, vat_net, vat_tax, gross, payable, signs, skonto, deduction, deductions und quantity. Füllen Sie eine Rechnung ohne Blick eines Menschen nur, wenn jede Prüfung mit sums: true bestanden ist.
Ein Beispiel
Eine Eingangsrechnung mit zwei Positionen zu 19 %, 2 % Skonto innerhalb von 14 Tagen:
{
"schema": "ocost.document.v1",
"id": "01a1b08c-7aa1-7b52-9d4e-2f1f1c0c4f11",
"file_id": "01a1b08c-6e3a-7562-8f4a-7924722667b1",
"pages": [1],
"kind": "invoice",
"kind_detail": "invoice",
"direction": "incoming",
"type_code": "380",
"number": "RE-2026-1187",
"issue_date": "2026-11-03",
"due_date": "2026-12-03",
"delivery_date": "2026-10-30",
"invoicing_period_start": null,
"invoicing_period_end": null,
"valid_until": null,
"currency": "EUR",
"buyer_reference": null,
"order_reference": "PO-2316",
"order_references": ["PO-2316"],
"preceding_invoice": null,
"seller": {
"name": "Musterbüro Lieferant GmbH",
"vat_id": "DE123456789",
"tax_registration_id": null,
"legal_registration_id": "HRB 12345",
"address": { "street": "Beispielweg 4", "postal_code": "50667", "city": "Köln", "country": "DE" },
"contact": { "email": "rechnung@lieferant.example", "phone": null },
"website": null
},
"buyer": {
"name": "Beispiel Handel GmbH",
"vat_id": "DE987654321",
"tax_registration_id": null,
"legal_registration_id": null,
"address": { "street": "Hauptstraße 1", "postal_code": "40213", "city": "Düsseldorf", "country": "DE" },
"contact": null,
"website": null
},
"payee": null,
"deliver_to": null,
"other_parties": [],
"payment": {
"means_code": "58",
"means": "transfer",
"iban": "DE02120300000000202051",
"bic": null,
"terms": "14 Tage 2 % Skonto, 30 Tage netto",
"net_days": 30,
"paid_on": null
},
"early_payment_discounts": [
{ "days": 14, "percent": "2", "base_amount": null, "due_date": "2026-11-17" }
],
"totals": { "net": "1068.00", "tax": "202.92", "gross": "1270.92", "payable": null, "prices_include_vat": false },
"vat_breakdown": [
{ "category": "S", "rate": "19", "taxable_amount": "1068.00", "tax_amount": "202.92", "exemption_reason": null }
],
"lines": [
{
"id": "1", "name": "Bürostuhl ErgoPlus schwarz", "seller_item_id": "ES-200", "standard_item_id": null,
"quantity": "4", "unit": "H87", "price": "189.00", "base_quantity": null, "net_amount": "756.00",
"discount_percent": null, "vat_category": "S", "vat_rate": "19",
"ordered_quantity": null, "backordered_quantity": null, "batch": null, "pzn": null,
"attributes": { "colour": "schwarz" }
},
{
"id": "2", "name": "Montage", "seller_item_id": null, "standard_item_id": null,
"quantity": "4", "unit": "HUR", "price": "78.00", "base_quantity": null, "net_amount": "312.00",
"discount_percent": null, "vat_category": "S", "vat_rate": "19",
"ordered_quantity": null, "backordered_quantity": null, "batch": null, "pzn": null,
"attributes": {}
}
],
"deductions": [],
"card": null,
"worked_out": [],
"sources": {
"number": { "page": 1, "quote": "RE-2026-1187", "confidence": "read", "why": null },
"totals.gross": { "page": 1, "quote": "1.270,92 €", "confidence": "checked", "why": null },
"seller.vat_id": { "page": 1, "quote": "DE123456789", "confidence": "checked", "why": null }
},
"checks": [
{ "name": "vat", "passed": true, "sums": true, "fields": ["totals.net", "totals.tax"], "at": "19" },
{ "name": "gross", "passed": true, "sums": true, "fields": ["totals.net", "totals.tax", "totals.gross"], "at": null }
],
"tax_check": { "case": "standard", "missing": [] },
"attention": [],
"possible_duplicate_of": null,
"read_with": "reader"
}Auslesen
from decimal import Decimal
document = session.get(f"{API}/files/{file_id}/document", timeout=15).json()
sums_hold = all(c["passed"] for c in document["checks"] if c["sums"])
gross = Decimal(document["totals"]["gross"]) if document["totals"]["gross"] else None
doubts = [path for path, s in document["sources"].items() if s["confidence"] == "doubt"]const document = await fetch(`${API}/documents/${documentId}`, { headers: auth }).then((r) => r.json());
const sumsHold = document.checks.filter((c) => c.sums).every((c) => c.passed);
// Beträge sind Zeichenketten: als solche behalten oder mit einer Dezimal-Bibliothek rechnen.
console.log(document.number, document.totals.gross, sumsHold);