Zum Inhalt springen

Auskunft, Liste und Belege

Webhooks melden jeden Zustandswechsel. Geht ein Ereignis verloren, holen Sie den Stand über die Schnittstelle nach. Liste, Auskunft und Belegabruf hängen am Vorgang, nicht an der Vorgangsart: Sie antworten unter allen fünf Präfixen gleich — vehicleDeregistrations, vehicleHolderChanges, vehicleTransfers, vehicleReRegistrations und vehicleRegistrations.

Auftragsliste

GET /{präfix}/orders listet Ihre Aufträge, neueste zuerst.

ParameterBedeutung
externalIdgenau Ihre Referenz aus dem Antrag — nicht unscharf
stateein Zustand oder mehrere mit Komma: beschieden,abgelehnt,fehlgeschlagen
businessTransactionein Geschäftsvorfall oder mehrere mit Komma, in Großschreibung: NZ,TZ
createdSincenur Aufträge ab diesem Zeitpunkt (ISO 8601)
changedSincenur Aufträge, deren Stand sich seitdem geändert hat — der Parameter für den täglichen Abgleich
limitSeitengröße, Vorgabe 50, höchstens 200; 0 gilt als 1
offsetVersatz, Vorgabe 0

Die Liste ist streng, damit ein Tippfehler nicht still den ganzen Bestand liefert. 400 gibt es für:

  • einen unbekannten Parameter — auch derivedStatus, das kein Filter ist,
  • einen mehrfach angegebenen Parameter (state=a&state=b; verbinden Sie die Werte mit Komma),
  • state=, businessTransaction=, externalId=, createdSince= oder changedSince= ohne Wert (bei den letzten drei auch nur aus Leerzeichen),
  • einen unbekannten Zustand oder Geschäftsvorfall (etwa nz),
  • einen unlesbaren Zeitpunkt oder ein limit/offset, das keine ganze Zahl ab 0 ist.
curl -u "$API_LOGIN:$API_PASSWORT" \
  "https://api.kfz-api.de/dropshipping-api/$CLIENT_ID/2.3.0/vehicleRegistrations/orders?businessTransaction=NZ,TZ&changedSince=2026-09-14T00:00:00Z&limit=200"
Antwort 200 GET /vehicleRegistrations/orders
{
  "orders": [
    {
      "order": { "id": 17, "externalId": "neuzulassung-4711" },
      "attemptOf": 17,
      "businessTransaction": "NZ",
      "state": "beschieden",
      "derivedStatus": "SUCCESS",
      "applicationId": "88888020260915000002",
      "vehicleIdentificationNumber": "WVWZZZ7HZ8H654321",
      "licensePlate": "SL-AB 123",
      "createdAt": "2026-09-15T09:02:11.412Z",
      "changedAt": "2026-09-15T11:02:10.087Z"
    }
  ],
  "limit": 200,
  "offset": 0,
  "total": 1,
  "hasMore": false
}

limit, offset und total nennen die Werte, die wirklich gegolten haben. Blättern Sie, solange hasMore true ist, und erhöhen Sie offset um die Zahl der gelieferten Einträge.

Die Liste führt nur Auftragsköpfe und bewusst keine Belege, Zulassungsdaten oder Gebühren — die holt die Einzelauskunft.

Vorgangsauskunft

GET /{präfix}/orders/{orderId} liefert den vollständigen Stand eines Vorgangs. Ein unbekannter oder fremder Vorgang ergibt 404.

Antwort 200 GET /vehicleRegistrations/orders/{orderId}
{
  "order": { "id": 17, "externalId": "neuzulassung-4711" },
  "attempt": 1,
  "attemptOf": 17,
  "businessTransaction": "NZ",
  "state": "beschieden",
  "derivedStatus": "SUCCESS",
  "applicationId": "88888020260915000002",
  "vehicleIdentificationNumber": "WVWZZZ7HZ8H654321",
  "licensePlate": "SL-AB 123",
  "files": [
    {
      "purposeType": "CERTIFICATE",
      "mediaType": "application/pdf",
      "fileAccessKey": "k-7a2e91d0",
      "expirationTime": "2026-09-18T09:02:10.000Z",
      "filename": "Vorgang-17_SL-AB-123_Zulassungsbescheid.pdf"
    }
  ],
  "registrationData": { "Kennzeichen": "SL AB 123" },
  "registrationDocumentsReady": true,
  "costBreakdown": {
    "kbaCost": 30,
    "registrationOfficeCosts": {
      "items": [{ "number": 1, "amount": 1110 }],
      "total": { "number": 2, "name": "Summe", "amount": 1110 }
    }
  },
  "attempts": [
    {
      "id": 17,
      "attempt": 1,
      "state": "beschieden",
      "derivedStatus": "SUCCESS",
      "applicationId": "88888020260915000002",
      "vehicleIdentificationNumber": "WVWZZZ7HZ8H654321"
    }
  ],
  "messages": [
    { "type": "QUITTUNG", "kind": "Warnung", "code": "07085", "text": "Für den Antrag wird eine Gebühr nach Geb. Nr. 129 GebOSt erhoben." }
  ],
  "createdAt": "2026-09-15T09:02:11.412Z",
  "updatedAt": "2026-09-15T11:02:10.087Z"
}

Die Beträge im Beispiel sind erfunden; die echten stehen im Bescheid der Zulassungsbehörde.

FeldInhalt
stateZustand des Versuchs, siehe unten
derivedStatusdieselbe Einordnung wie im Webhook-Ereignis
applicationIdAntragsnummer des KBA — erst nach der Quittung gesetzt
licensePlateKennzeichen in Anzeigeform, bei Zulassungen nach dem Bescheid das zugeteilte. Solange der Vorgang auf angelegt steht, also noch nicht gesendet ist, ist es null
filesBelege aus dem Rückkanal mit fileAccessKey, expirationTime und filename; am Auftragskopf die aller Versuche, siehe Versuche und Korrektur
registrationDataDaten der Zulassungsbescheinigung, wenn angefordert und geliefert
registrationDocumentsReadyErweiterung — kennzeichen.dev führt das Feld nicht. true, wenn die Zulassungsunterlagen (ZB I, ZB II, Plaketten) versandt sind oder zur Abholung bereitliegen. Nur bei Zulassungen und nur in der automatisierten Bearbeitung; fehlt das Feld, ist nichts gesagt — nicht „nicht versandt"
partiesBeteiligte laut Rückmeldung, vor allem der Halter — dieselben Felder wie im Webhook-Ereignis: role, roleName, kind, name und bei einer Vereinigung representative
messagesMeldungen des KBA mit code, text und additional — bei einer Ablehnung steht der Grund oft erst in additional. code ist nicht immer fünfstellig, siehe Quittungscodes
retryablenur gesetzt, wenn der Vorgang vorübergehend gescheitert ist
attempt, attemptOf, attemptsVersuche des Auftrags, siehe unten
paymentReference, feeAmountCents, costBreakdownGebühren, siehe unten
holderDataProvenanceHerkunftsnachweis der Halterdaten, nur bei Anträgen mit powerOfAttorney.processId

Zustände

stateBedeutungEreignis statusderivedStatus
angelegtangenommen, noch nicht an das KBA gesendetPENDING
eingereichtvom KBA angenommen, Entscheidung steht ausACCEPTEDPENDING
inBearbeitungbeim i-Kfz-Portal in BearbeitungACCEPTEDPENDING
weitergeleitetan die Zulassungsbehörde ausgesteuertFORWARDEDPENDING
beschiedenpositiv beschiedenAPPROVED_WITH_DOCUMENTS oder APPROVEDSUCCESS
abgelehntabgelehntREJECTED_WITH_DOCUMENTS oder REJECTEDFAILURE oder genauer
fehlgeschlagenabgewiesen, korrigieren und neu stellenFAILEDFAILURE oder genauer

_WITH_DOCUMENTS heißt: Es liegen Belege bei. Ist ein Antrag an die Zulassungsbehörde weitergeleitet, kennt das KBA den Arbeitsstand nicht mehr; die Entscheidung kommt trotzdem über den Rückkanal.

Eine Rückmeldung ohne Entscheidung schließt den Vorgang nicht. Meldet das KBA den Antrag als „abgeschlossen", ohne einen Entscheidungsblock und ohne einen Bescheid mitzuschicken, bleibt der Vorgang auf inBearbeitung mit derivedStatus: PENDING, und es geht kein Ereignis an Sie hinaus — aus einer Meldung, die nichts entscheidet, eine Ablehnung zu machen, wäre die gefährlichere Fehlrichtung. Das KBA schickt danach keine weitere Rückmeldung zu diesem Antrag. Ein solcher Vorgang fällt deshalb nur über die Überfälligkeit auf (nach 24 Stunden ohne Entscheidung); im Dashboard wird er dann über der Vorgangsliste eigens als überfällig ausgewiesen, und der Betrieb klärt ihn mit der Zulassungsbehörde. Beobachtet im Probelauf vom 16.09.2026; die einzige Kombination, nach der ein Vorgang ohne Kundenmeldung stehenbleibt.

Versuche und Korrektur

Ein abgewiesener Antrag lässt sich im Dashboard korrigieren und erneut senden. Beim KBA ist das ein neuer Antrag mit eigener Antragsnummer, bei der Schnittstelle ein weiterer Versuch desselben Auftrags:

  • Der neue Versuch trägt dieselbe externalId und eine eigene Id; attemptOf nennt die Id des Auftrags, attempt die laufende Nummer.
  • Der Auftragskopf folgt dem jüngsten Versuch — sein state kann von fehlgeschlagen wieder auf einen offenen Zustand wechseln. Ein Endzustand ist der Endzustand des Versuchs, nicht des Auftrags.
  • Die Liste führt nur Köpfe. attempts in der Auskunft nennt alle Versuche; jeder ist über seine Id einzeln abrufbar.
  • files am Auftragskopf führt die Belege aller Versuche (Kopf und attempts[].id), ohne Dubletten und in der Reihenfolge ihres Eingangs. Jeder davon ist über seinen fileAccessKey abrufbar. Die Auskunft zu einer Versuchs-Id führt nur die Belege dieses Versuchs. Dasselbe gilt für Webhook-Ereignisse: Trägt order.id die Id des Auftragskopfs, stehen in files die Belege aller Versuche.
  • Nach einer Korrektur trägt der Auftragskopf kein attempt; er ist selbst kein Versuch mehr.
  • Ordnen Sie Webhook-Ereignisse über attemptOf zu, nicht über order.id.
  • Abgerechnet wird der Auftrag einmal, dazu 0,12 € je abgewiesener Übermittlung. Das gilt nur für die Korrektur im Dashboard: Ein erneuter POST über die Schnittstelle legt einen neuen Auftrag an, und der wird wie jeder Auftrag berechnet.

Belege abrufen

GET /{präfix}/files/content/{fileAccessKey} liefert die Datei mit ihrem Content-Type und dem Dateinamen in Content-Disposition — derselbe wie filename in Ereignis und Auskunft.

curl -u "$API_LOGIN:$API_PASSWORT" -OJ \
  "https://api.kfz-api.de/dropshipping-api/$CLIENT_ID/2.3.0/vehicleRegistrations/files/content/$FILE_ACCESS_KEY"
  • Ein Schlüssel gilt bis expirationTime — wie lange, hängt davon ab, woher er stammt. Belege eines Vorgangs (aus Vorgangsauskunft und Webhook-Ereignis) gelten 72 Stunden ab dem Ablegen; im Dashboard unter „Belege" lässt sich ein solcher Beleg erneut freigeben. Die Dateien eines Sammelgebührenbescheids (gb_…) und einer Nachricht ohne Vorgang (ek_…) gelten 90 Tage; ihre Einzelauskunft — GET /vehicleDeregistrations/feeNotices/{id} und GET /vehicleDeregistrations/unmatchedMessages/{id} — setzt die Frist neu an. Danach antwortet der Abruf mit 404.
  • expirationTime trägt in Auskunft und Ereignis verschiedene Formate, und beide sind so gewollt: Die Auskunft liefert den vollständigen ISO-Zeitstempel mit Zone und Millisekunden (2026-09-19T14:38:22.558Z), das Webhook-Ereignis denselben Zeitpunkt als LocalDateTime — in UTC, ohne Zone, sekundengenau (2026-09-19T14:38:22), wie es der Webhook-Vertrag für jeden Zeitstempel vorschreibt. Beim Vergleich lesen Sie den Wert des Ereignisses als UTC.
  • Zwei Belege mit purposeType CERTIFICATE — etwa Zulassungsbescheid und vorläufiger Zulassungsnachweis — unterscheiden Sie am filename. Der Gebührenbescheid hat RECEIPT.
  • Ein unbekannter, abgelaufener oder fremder Schlüssel ergibt dieselbe Antwort: 404.

Gebühren

costBreakdown stammt aus dem Bescheid (0709):

  • kbaCost — die Nutzungsgebühr des KBA nach Nr. 129 GebOSt, 30 Cent. Sie steht erst da, wenn der Bescheid (0709) eingegangen ist — dann, wenn das KBA sie mit Quittungscode 07085 angekündigt hat oder der Antrag beschieden bzw. abgelehnt ist. Die Quittung mit 07085 allein führt noch kein costBreakdown.
  • registrationOfficeCosts — die Positionen der Zulassungsbehörde (items, Beträge in Cent) und ihre Summe (total). Die Position des KBA ist dort herausgenommen, damit sie nicht doppelt zählt.

paymentReference (Kassenzeichen) und feeAmountCents stammen aus dem Sammelgebührenbescheid (0103) der Zulassungsbehörde. Beide werden einzeln gesetzt — ein Betrag ohne Kassenzeichen kommt vor. Die Sammelgebührenbescheide selbst liefern GET /vehicleDeregistrations/feeNotices und das Ereignis FEE_NOTICE_XKFZ_EVENT.

Sichtbar nur mit eigener KBA-Registrierung. Die amtlichen Bescheide lauten auf den beim KBA Registrierten. Fahren Sie als Vertragspartner unter fremder Registrierung, fehlen costBreakdown, paymentReference und feeAmountCents in Auskunft, Versuchen und Webhook-Ereignis, der Gebührenbescheid fehlt in files, und sein Abruf ergibt 404 — dieselbe Antwort wie für einen unbekannten Schlüssel. GET /vehicleDeregistrations/feeNotices und GET /vehicleDeregistrations/feeNotices/{id} antworten dagegen mit 403 und nennen den Grund; eine leere Liste bekommen Sie dort nicht.

Was kfz-api.de berechnet, steht auf der Preisseite; Ihre Rechnungen liefert GET /invoices.

Nachrichten ohne Vorgang

Schickt das KBA etwas an Ihre Registrierung, zu dem kein Antrag dieser Schnittstelle passt — etwa den Bescheid zu einem Antrag aus einem früheren System —, legt die Schnittstelle es als Nachricht ohne Vorgang ab: GET /vehicleDeregistrations/unmatchedMessages, Ereignis UNMATCHED_MESSAGE_XKFZ_EVENT. Den Stand — OPEN, HANDLED oder IGNORED, auf Wunsch mit der orderId eines eigenen Vorgangs — setzen Sie mit PUT /vehicleDeregistrations/unmatchedMessages/{id}/state. Die Felder stehen in der Referenz.