Beleg hochladen und auslesen
Einen Beleg ohne Doppelungen hochladen, den Stand der Erkennung abfragen und die erkannten Daten lesen.
Achtung
Probiere das Rezept deshalb mit einer Firma und einem Beleg aus, die du dafür vorgesehen hast. Die Regeln für den Upload stehen ausführlich unter Beleg-Upload.
Ablauf
- Hochladen: Die Datei geht als
multipart/form-dataanPOST /api/document/, mit einer eigenen ID im HeaderX-Upload-Request-Id. Die Antwort enthält den neuen Beleg mit seinerid. - Stand abfragen:
GET /api/document/{id}liefert den Beleg mit dem Stand der Erkennung inuploadDocument.ocrStatus. Du fragst alle paar Sekunden ab, bis der Standsuccess,failedoderquota_pausedist. - Ergebnis lesen: Bei
successstehen die erkannten Daten im Beleg, etwa Rechnungsnummer, Rechnungsdatum, Aussteller und Positionen.
Code
Du brauchst einen Schlüssel mit der Berechtigung upload für den Upload und read für die Abfragen, gespeichert in der Umgebungsvariable BIMETRICS_API_KEY. Die Beispiele laufen mit curl und jq, mit Node.js ab Version 20 oder mit Python und dem Paket requests. Das JavaScript-Beispiel läuft nur als ES-Modul, weil es import und await außerhalb von Funktionen nutzt: Speichere es als beleg-upload.mjs oder setze in deiner package.json "type": "module".
#!/usr/bin/env bash
set -euo pipefail
API="https://app.bimetrics.de/api"
AUTH="Authorization: Bearer $BIMETRICS_API_KEY"
# Eine eigene ID je Beleg, zum Beispiel die Belegnummer in deinem System.
# Bei einer Wiederholung bleibt sie gleich.
UPLOAD_ID="wawi-2026-000123"
# 1. Hochladen. --retry wiederholt bei Zeitüberschreitung, 429, 500, 502,
# 503 und 504 mit derselben ID und wartet dabei die Zeit aus Retry-After ab.
id=$(curl --fail --silent --show-error --retry 5 "$API/document/" \
-H "$AUTH" \
-H "X-Upload-Request-Id: $UPLOAD_ID" \
-F "auto[]=@rechnung.pdf" | jq -r '.[0].id')
echo "Beleg $id"
# 2. Stand abfragen, alle 5 Sekunden, höchstens 10 Minuten lang
status=""
for _ in $(seq 120); do
status=$(curl --fail --silent --show-error --retry 5 "$API/document/$id" -H "$AUTH" \
| jq -r '.uploadDocument.ocrStatus')
case "$status" in success | failed | quota_paused) break ;; esac
sleep 5
done
echo "Stand der Erkennung: $status"
# 3. Ergebnis lesen
if [ "$status" = "success" ]; then
curl --fail --silent --show-error --retry 5 "$API/document/$id" -H "$AUTH" | jq '{
kind,
invoiceNumber,
invoiceDate,
issuer: .issuer.name,
totalCents: ([.invoicePositions[]?.total] | add)
}'
fiDie Upload-ID
- Verwende für jeden neuen Beleg eine neue ID, am besten eine, die es in deinem System schon gibt, etwa die Belegnummer. Dann kannst du einen abgebrochenen Lauf später mit derselben ID fortsetzen.
- Bei einer Wiederholung bleiben ID, Datei, Dateiname und Feld gleich. Die API liefert dann denselben Beleg zurück, auch wenn die erste Anfrage schon angekommen war.
- Dieselbe ID mit einer anderen Datei ergibt
409mit dem CodeUploadRequestConflict. Das wiederholst du nicht.
Liegt dieselbe Datei in der Firma schon als Beleg vor, legt bimetrics keinen zweiten an. Die Antwort enthält dann den vorhandenen Beleg und "duplicate": true.
Stand der Erkennung
uploadDocument.ocrStatus | Was tun |
|---|---|
pending, processing | Weiter abfragen. Nach einem vorübergehenden Fehler kann der Stand von processing wieder auf pending gehen. |
success | Ergebnis lesen. |
failed | Der Beleg ist gespeichert, die Daten wurden aber nicht erkannt. Prüfe ihn in der App. |
quota_paused | Der Beleg ist gespeichert, das Kontingent ist ausgeschöpft. bimetrics setzt die Erkennung fort, sobald wieder Kontingent frei ist. Lade den Beleg nicht erneut hoch. |
- Frage höchstens alle paar Sekunden ab. Jede Abfrage zählt zu den Limits.
- Bleibt der Stand länger bei
pendingoderprocessing, brich nach einer Obergrenze ab und frage später wieder ab. Der Beleg ist in jedem Fall gespeichert. - Lädst du viele Belege hoch, frage den Stand gesammelt über
POST /api/document/filterab, etwa mituploadDocument.ocrStatusundcreatedAt, statt jeden Beleg einzeln.
Das Ergebnis
Die erkannten Daten stehen direkt im Beleg (gekürzt, Werte erfunden):
{
"id": "0b5c2f4e-8a1d-4c3e-9f6a-2d7b1e8c4a90",
"kind": "receipt",
"invoiceNumber": "RE-2026-0917",
"invoiceDate": { "year": 2026, "month": 9, "day": 17 },
"dueDate": { "year": 2026, "month": 10, "day": 1 },
"issuer": { "name": "Schreinerei Albrecht GmbH", "iban": "DE89370400440532013000" },
"recipient": { "name": "Mustermann Bau GmbH" },
"invoicePositions": [
{ "label": "Einbauschrank Eiche", "total": 238000, "vatPercentage": "19" },
{ "label": "Montage", "total": 35700, "vatPercentage": "19" }
],
"uploadDocument": { "ocrStatus": "success" }
}totalist der Bruttobetrag der Position in Cent,vatPercentageder Steuersatz in Prozent. Der Bruttobetrag des Belegs ist die Summe dertotal-Werte, hier 2.737,00 €. Mehr unter Datentypen.- Mit
auto[]kann sichkindbei der Erkennung ändern, etwa aufinvoice, wenn die Rechnung von der eigenen Firma stammt (siehe Glossar). - Die Originaldatei rufst du mit
GET /api/document/{id}/contentab.