Fehlercodes
| HTTP | error.code | Bedeutung | Was tun? |
|---|---|---|---|
| 401 | missing_token | Kein API-Token übergeben. Erwartet: Authorization: Bearer <token>. | Eingabe korrigieren: Den Kopf Authorization: Bearer <token> mitsenden. |
| 401 | invalid_authorization_scheme | Das Authorization-Schema wird nicht unterstützt. Erwartet: Authorization: Bearer <token>. | Eingabe korrigieren: Das Schema Bearer verwenden (nicht Basic o. Ä.). |
| 401 | invalid_token | Das API-Token ist ungültig oder wurde widerrufen. | Eingabe korrigieren: Token auf Tippfehler prüfen. Ist es widerrufen oder der Ersteller deaktiviert, in der Verwaltung ein neues Token anlegen und im Programm austauschen. Nicht wiederholen: Wiederholungen mit falschem Token zählen als Fehlversuche je IP-Adresse. |
| 401 | token_expired | Das API-Token ist abgelaufen. Bitte ein neues Token anlegen. | Eingabe korrigieren: In der Verwaltung ein neues Token anlegen und im Programm austauschen. |
| 401 | wrong_environment | Das API-Token gehört zu einer anderen Umgebung. | Eingabe korrigieren: Das Token der passenden Umgebung (live, stg, dev) verwenden — jedes Token gilt nur in seiner eigenen. |
| 400 | token_in_url_forbidden | Tokens dürfen nicht in der Adresse stehen. Bitte den Authorization-Header verwenden. | Eingabe korrigieren: Das Token aus der Adresse entfernen und im Kopf Authorization senden. Tokens, die in einer Adresse standen, sind als kompromittiert zu betrachten: widerrufen. |
| 403 | insufficient_scope | Das API-Token hat nicht die nötige Berechtigung (Scope). | Eingabe korrigieren: Das Token braucht den in error.required_scope genannten Scope: ein neues Token mit diesem Scope anlegen (ein bestehendes lässt sich nicht erweitern). |
| 403 | insufficient_permissions | Der Ersteller des API-Tokens hat das nötige Recht in der Verwaltung nicht (mehr). | Eingabe korrigieren: Dem Ersteller des Tokens das fehlende Recht in der Verwaltung geben (oder ein Token einer Person mit dem Recht anlegen). Das Token funktioniert danach ohne Änderung wieder. |
| 400 | validation_error | Die Anfrage ist ungültig. | Eingabe korrigieren: error.details nennt je Feld die Fehlercodes: Anfrage korrigieren und neu senden. Eine unveränderte Wiederholung scheitert wieder. |
| 400 | invalid_cursor | Der Cursor ist ungültig. Bitte ohne Cursor neu beginnen. | Eingabe korrigieren: Ohne Cursor neu beginnen. Cursor nur unverändert und nur auf demselben Endpunkt verwenden, von dem sie stammen. |
| 410 | cursor_expired | Der Cursor des Änderungsabgleichs ist abgelaufen (Änderungen werden 90 Tage aufbewahrt). Bitte neu einsteigen und einmal alles abrufen. | Eingabe korrigieren: Neuen Einstieg über …/changes/cursor holen, einmal alles über die Liste abrufen und von dort aus weiter abgleichen. |
| 404 | not_found | Nicht gefunden. | Eingabe korrigieren: Id prüfen (stammt sie aus Ihrer Organisation und aus dem richtigen Listenaufruf?). Die Ressource kann auch gelöscht worden sein. Nicht wiederholen. |
| 404 | route_not_found | Diese Adresse gibt es in der API nicht. Alle Endpunkte stehen unter /v1. | Eingabe korrigieren: Pfad und Schreibweise prüfen; alle Endpunkte stehen unter /v1 (siehe Referenz). |
| 400 | range_too_large | Der Zeitraum ist zu groß (Höchstspanne je Endpunkt in der Doku). Bitte in kleinere Abschnitte teilen. | Eingabe korrigieren: Den Zeitraum bzw. die Auswahl in kleinere Abschnitte teilen (Höchstspanne je Endpunkt in der Referenz; bei Dateiausgabe error.details.max_rows). |
| 400 | field_not_allowed | Bankdaten (iban, bic, account_holder) können über die API nicht übergeben werden. | Eingabe korrigieren: Die in error.details genannten Felder (Zeile und Feld) aus der Anfrage entfernen; Bankdaten tragen Sie in der Verwaltung ein. |
| 400 | idempotency_key_required | Der Kopf Idempotency-Key fehlt. Bitte je Vorgang einen eindeutigen Schlüssel mitsenden (z. B. eine UUID). | Eingabe korrigieren: Je Vorgang einen Idempotency-Key (z. B. eine UUID) mitsenden und für Wiederholungen desselben Vorgangs wiederverwenden. |
| 409 | idempotency_conflict | Dieser Idempotency-Key wurde schon mit einem anderen Inhalt verwendet. | Eingabe korrigieren: Der Schlüssel gehört zu einem anderen Inhalt. Für einen neuen Vorgang einen neuen Schlüssel erzeugen; für eine Wiederholung exakt den ersten Body senden. |
| 409 | readings_locked | Die Zählerstände Ihrer Organisation werden gerade bearbeitet (andere Erfassung, Import oder Abrechnung). Dieser Aufruf wurde abgebrochen; bitte in einigen Sekunden erneut senden (bei Aufrufen mit Idempotency-Key mit demselben Schlüssel). Wird ein Aufruf in mehreren Blöcken verarbeitet (Import-Übernahme ab 25 Datensätzen), können frühere Blöcke schon übernommen sein: sie melden beim erneuten Senden `already_transferred`. | Erneut versuchen: Die Zählerstände der Organisation werden gerade bearbeitet. Der Aufruf wurde abgebrochen; in einigen Sekunden erneut senden (mit demselben Idempotency-Key, falls der Aufruf einen trägt). Bei der Import-Übernahme in mehreren Blöcken können frühere Blöcke schon übernommen sein (`already_transferred`). |
| 409 | appointment_conflict | Für diesen Vertrag gibt es bereits einen aktiven Termin dieser Art. Er lässt sich über die API nicht umplanen. | Eingabe korrigieren: Für Vertrag und Art gibt es schon einen aktiven Termin; er lässt sich über die API nicht umplanen. In der Verwaltung ändern oder absagen. |
| 409 | meter_exists | An dieser Einheit gibt es für diese Art (Strom oder Wasser) bereits einen aktiven Zähler. Ein weiterer lässt sich über die API nicht anlegen. | Eingabe korrigieren: An der Einheit hängt für diese Art schon ein aktiver Zähler. Vorhandene Zähler lesen Sie mit GET /v1/meters?unit_id=…; Austausch oder Änderung erfolgt in der Verwaltung. |
| 422 | unit_not_configured | Die Einheit ist für diese Art (Strom 230 V, Strom 400 V oder Wasser) nicht eingerichtet. Bitte zuerst den Anschluss an der Einheit in der Verwaltung eintragen. | Eingabe korrigieren: Den Anschluss (Strom 230 V, Strom 400 V oder Wasser) an der Einheit in der Verwaltung eintragen, danach den Aufruf mit demselben Idempotency-Key wiederholen. |
| 413 | payload_too_large | Die Anfrage ist zu groß. Die Grenze gilt je Endpunkt und steht in error.details.max_bytes (in Byte). | Eingabe korrigieren: Den Body unter die Grenze dieses Endpunkts (error.details.max_bytes, in Byte) bringen, etwa Datensätze auf mehrere Aufrufe verteilen. |
| 409 | session_has_transferred_records | Der Import enthält bereits übernommene Datensätze und kann nicht abgebrochen werden (Mieter und Verträge verweisen auf ihn). | Eingabe korrigieren: Ein Import mit übernommenen Datensätzen lässt sich nicht abbrechen. Er kann nur in der Verwaltung weiterbearbeitet werden. |
| 415 | unsupported_media_type | Erwartet: Content-Type: application/json. | Eingabe korrigieren: Den Kopf Content-Type: application/json senden. |
| 403 | sandbox_unavailable | Die Sandbox ist derzeit nicht nutzbar: Der API-Zugang Ihrer Organisation ist nicht aktiv (Testzeit abgelaufen, Zusatzmodul API-Zugänge nicht gebucht oder vom Betreiber gesperrt) oder die Sandbox ist abgelaufen. Das Zusatzmodul unter Administration → API-Zugänge prüfen; mit aktivem Zugang funktioniert dasselbe Token wieder. | Eingabe korrigieren: Nur Sandbox-Tokens: Das Zusatzmodul API-Zugänge in der Verwaltung prüfen (Testzeit, Buchung); ist die Sandbox abgelaufen, eine neue anlegen. Das Token selbst ist gültig und funktioniert mit aktivem Zugang wieder. |
| 422 | sandbox_limit_reached | Die Sandbox hat ihren Datenbestand erreicht (höchstens 3000 Mieter, Interessenten, Schäden, Zählerstände, Termine und Importsätze zusammen). Unnötige Testdaten in der Verwaltung entfernen oder die Sandbox ersetzen; ungenutzte Sandboxen werden nach 30 Tagen gelöscht. | Eingabe korrigieren: Nur in der Sandbox: Testdaten in der Verwaltung entfernen oder die Sandbox ersetzen („Neue Sandbox anlegen“ nach Ablauf); ungenutzte Sandboxen werden nach 30 Tagen gelöscht. |
| 422 | import_limit_reached | Die Höchstzahl offener Importe ist erreicht (Grenze in error.details). Offene Importe in der Verwaltung übernehmen oder löschen — oder den Support um eine höhere Grenze bitten. | Eingabe korrigieren: Offene Importe in der Verwaltung übernehmen oder per DELETE /v1/tenant-imports/{id} abbrechen; oder den Support um eine höhere Grenze bitten. |
| 422 | import_total_limit_reached | Ihre Organisation hat bereits 500 Importe (Datei und API, auch abgeschlossene). Bitte abgeschlossene Importe in der Verwaltung löschen. | Support: Abgeschlossene Importe in der Verwaltung löschen; reicht das nicht, den Support mit der request_id kontaktieren. |
| 429 | import_rate_limited | Dieses Token hat die Höchstzahl neuer Importe je Stunde erreicht (Grenze in error.details). Bitte später erneut versuchen oder den Support um eine höhere Grenze bitten. | Erneut versuchen: Später erneut versuchen (Stundengrenze je Token, Grenze und Stand in error.details); oder den Support um eine höhere Grenze bitten. |
| 400 | period_conflict | Zeitfilter: Bitte genau eine Angabe verwenden (period, date oder from/to). | Eingabe korrigieren: Genau eine Form des Zeitfilters verwenden: period, date oder from/to. |
| 400 | range_invalid | Der Zeitraum ist ungültig (from muss vor to liegen). | Eingabe korrigieren: from muss vor to liegen; Werte tauschen oder korrigieren. |
| 400 | unsupported_format | Dieses Ausgabeformat wird von diesem Endpunkt nicht unterstützt. | Eingabe korrigieren: Eines der in error.details.supported_formats genannten Formate wählen (json, csv); oder weniger Spalten bzw. kürzere Texte abrufen. |
| 404 | file_not_available | Zu diesem Eintrag ist keine Datei verfügbar. | Eingabe korrigieren: Zu diesem Eintrag gibt es keine Datei; nicht wiederholen. Die Liste zeigt je Eintrag, ob eine Datei vorhanden ist. |
| 409 | export_not_ready | Der Export ist noch nicht fertig. Bitte später erneut abrufen. | Erneut versuchen: Den Export nach kurzer Wartezeit erneut abrufen (GET /v1/datev/exports/{id}), bis status = ready. |
| 400 | webhook_url_invalid | Die Webhook-Adresse ist ungültig oder nicht erlaubt (nur https auf Port 443, nur öffentliche Adressen). | Eingabe korrigieren: Eine öffentlich erreichbare https-Adresse auf Port 443 ohne Zugangsdaten verwenden, die sich per DNS auflösen lässt. |
| 409 | webhook_limit_reached | Die Höchstzahl an Webhooks ist erreicht (Grenze in error.details). | Eingabe korrigieren: Einen nicht mehr benötigten Webhook löschen (DELETE /v1/webhooks/{id}) oder einen bestehenden ändern. |
| 409 | delivery_not_replayable | Diese Zustellung lässt sich nicht erneut senden: nur fehlgeschlagene oder verworfene Zustellungen der letzten 29 Tage, keine Testereignisse (Grund in error.details.reason). | Eingabe korrigieren: error.details.reason nennt den Grund (not_failed, test_event, expired, paused); nicht wiederholen. Bei test_event ein neues Testereignis auslösen. |
| 429 | rate_limited | Zu viele Anfragen. Bitte nach der in Retry-After genannten Zeit erneut versuchen. | Erneut versuchen: Mindestens die Zeit aus dem Kopf Retry-After (Sekunden) warten, dann unverändert wiederholen; bei weiteren 429 die Wartezeit verdoppeln. |
| 503 | service_unavailable | Die API ist vorübergehend nicht verfügbar. | Erneut versuchen: Mit wachsender Wartezeit (Backoff) erneut versuchen. Schreibende Aufrufe mit demselben Idempotency-Key wiederholen. Bleibt der Fehler, den Support mit der request_id kontaktieren. |
| 500 | internal_error | Interner Fehler. Bitte mit der request_id an den Support wenden. | Erneut versuchen: Einmal nach kurzer Wartezeit wiederholen (schreibend mit demselben Idempotency-Key); bleibt der Fehler, den Support mit der request_id kontaktieren. Nicht in einer engen Schleife wiederholen. |
„Erneut versuchen“ heißt: Die Anfrage war in Ordnung, ein späterer Versuch kann gelingen — schreibend mit demselben Idempotency-Key. „Eingabe korrigieren“ heißt: Eine unveränderte Wiederholung scheitert wieder; ändern Sie Anfrage, Token oder Rechte. „Support“: nicht selbst behebbar — bitte mit der request_id melden (siehe Sicherheit & Support und das Bedrohungsmodell).
Antwortet die API mit 500 internal_error oder 503 service_unavailable oder kommen Anfragen ungewöhnlich langsam zurück, prüfen Sie zuerst die Statusseite: Dort stehen der aktuelle Zustand der API und der Webhook-Zustellung sowie laufende Vorfälle.
Unbekannte oder fremde Ids beantworten wir immer mit 404 not_found — nie mit „keine Berechtigung“. So verrät die API nicht, ob es eine Id anderswo gibt. Eine Kennung im Pfad, die gar keine UUID ist (/v1/invoices/abc), ist dagegen ein Formatfehler: 400 validation_error mit { "id": ["invalid_uuid"] } in error.details (bis 2026-10-07 antwortete die API hier mit 404). Eine Adresse, die es nicht gibt (/v1/foo), ergibt 404 route_not_found im selben Fehlerformat.
Was error.details enthält
error.details ist optional und fehlt bei den meisten Fehlern. Wo es steht, hat es je Fehlercode eine feste Form; in der OpenAPI ist es entsprechend beschrieben, und die Antworten der einzelnen Endpunkte in der Referenz nennen, welche Details sie liefern.
| error.code | Form von error.details | Beispiel |
|---|---|---|
validation_error | Objekt: Feldname → Liste von Codes (Codes siehe unten) | { "from": ["required"], "foo": ["unknown_parameter"] } |
field_not_allowed | Liste mit Zeile (row) und Feld (field), höchstens 50 Einträge | [{ "row": 1, "field": "iban" }] |
payload_too_large | Höchstgröße dieses Endpunkts in Byte (je Endpunkt verschieden, z. B. 1048576 beim Import, 65536 bei der Übernahme, 4096 beim Sammel-Replay) | { "max_bytes": 1048576 } |
import_limit_reached | Grenze und Stand offener Importe | { "limit": 50, "open": 50 } |
import_rate_limited | Grenze und Stand je Stunde und Token | { "limit": 20, "used": 20 } |
webhook_limit_reached | Grenze und aktueller Stand der Webhooks je Organisation (in einer Sandbox nur die Grenze: { "limit": 3 }) | { "limit": 10, "used": 10 } |
delivery_not_replayable | Status der Zustellung und Grund | { "status": "succeeded", "reason": "not_failed" } |
rate_limited | nur bei Webhook-Replay, Testereignissen und Interessentenanfragen: Grenze (Replay zusätzlich retry_after); sonst kein details | { "limit": 1000, "retry_after": 1800 } |
range_too_large | nur bei Dateiausgabe (CSV/Excel): Höchstzahl Zeilen; sonst kein details | { "max_rows": 200 } |
unsupported_format | erlaubte Formate; bei zu langer Excel-Zelle zusätzlich Grund, Spalte und Höchstlänge | { "supported_formats": ["json", "csv", "xlsx"] } |
Details bei validation_error
Bei 400 validation_error nennt error.message das erste Problem im Klartext. error.details ordnet jedem betroffenen Feld eine Liste von Codes zu — der Schlüssel ist der Name des Abfrageparameters oder Body-Felds, bei Listen im Body mit Position (records[2].lease_start). Die Codes sind stabil; die Meldung darf sich ändern.
{
"success": false,
"error": {
"code": "validation_error",
"message": "Parameter „from“ fehlt (erwartet: YYYY-MM-DD).",
"details": { "from": ["required"], "to": ["required"], "foo": ["unknown_parameter"] }
},
"request_id": "req_…"
}| Code | Bedeutung |
|---|---|
required | Pflichtangabe fehlt |
invalid_type | falscher Typ, etwa eine Zahl als Text |
invalid_format | Wert passt nicht zum erwarteten Format |
invalid_uuid | keine gültige Kennung (UUID) |
invalid_date | kein gültiges Datum (JJJJ-MM-TT) bzw. kein gültiger ISO-Zeitpunkt |
invalid_value | Wert nicht erlaubt (die Meldung nennt die erlaubten Werte) |
too_small | Zahl, Text oder Liste unter der Mindestgröße |
too_big | Zahl, Text oder Liste über der Höchstgröße |
too_many_ids | mehr als 100 Kennungen in ids |
duplicate_ids | dieselbe Kennung mehrfach in ids |
unknown_parameter | unbekannter Abfrageparameter (der Name steht als Schlüssel) |
unknown_field | unbekanntes Feld im Body |
before_from | to liegt vor from — dann lautet der Fehlercode range_invalid |
invalid_json | der Body ist kein gültiges JSON |
invalid_characters | unzulässiges Zeichen (U+0000) in Adresse oder Body |
Frühere Rohcodes (VALIDATION_INVALID_UUID, date_format_yyyy_mm_dd, date_or_datetime_iso, status_code_or_class, path_prefix_format) stehen bei Parametern, die sie früher nannten, weiterhin hinter dem neuen Code in der Liste — bei Positionen in Listen (ids[1], records[2].lease_start) zusätzlich unter dem obersten Feld (ids, records), wo sie früher standen. Englische Standardtexte der Prüfbibliothek (etwa „Too small: expected number to be >=1“) liefert die API nicht mehr; from nach to meldet überall range_invalid statt validation_error.