Zum Inhalt springen

Übersicht und Schnellstart

Über diese Schnittstelle stellen Sie Zulassungsanträge bei der Großkundenschnittstelle (GKS) des Kraftfahrt-Bundesamts: Außerbetriebsetzung, Halteränderung, Umschreibung, Wiederzulassung (auch auf denselben Halter), Neu- und Tageszulassung. Sie sprechen JSON über HTTPS; das Ergebnis kommt als Webhook-Ereignis zurück und lässt sich jederzeit abfragen.

Die Schnittstelle ist API-kompatibel zu kennzeichen.dev (Dropshipping API 2.3.0, Webhooks 3.1.0). Was darüber hinausgeht, steht unter Umgebungen und Versionen.

Basis-URLs

InstanzBasis-URLAnträge gehen an
Produktionhttps://api.kfz-api.de/dropshipping-api/{clientId}/2.3.0die Produktionsumgebung des KBA — Anträge werden wirksam
Test-Instanzhttps://api.staging.kfz-api.de/dropshipping-api/{clientId}/2.3.0die Testumgebung des KBA — Anträge werden geprüft, aber nicht wirksam

{clientId} ist die Nummer Ihres Mandanten. Sie steht im Dashboard im Handbuch unter „Versionen" als Teil der vollständigen Basis-URL. Die Nummer im Pfad muss zu dem API-Benutzer passen, mit dem Sie sich anmelden — sonst antwortet die Schnittstelle mit 403.

Setzen Sie die Nummer als reine Ziffernfolge ein, genau so wie das Dashboard sie ausgibt — ohne Auffüllnullen, Leerzeichen, Vorzeichen, Dezimalpunkt oder Exponentialschreibweise. Jede andere Schreibweise wird abgewiesen, auch wenn sie rechnerisch dieselbe Nummer ergibt: 01, 1 , +1, 1.0 und 1e0 beantwortet die Schnittstelle mit 403, nicht nur eine fremde Nummer. Die Meldung ist dabei dieselbe wie bei einem fremden Mandanten — prüfen Sie also zuerst die Schreibweise in der Basis-URL.

Alle Pfade in dieser Dokumentation sind relativ zur Basis-URL: POST /vehicleRegistrations/registrations heißt POST https://api.kfz-api.de/dropshipping-api/{clientId}/2.3.0/vehicleRegistrations/registrations.

So bekommen Sie einen Zugang

Einen Zugang legen Sie nicht selbst an:

  1. Fragen Sie beim Support an — für die Test-Instanz, für die Produktion oder für beide.
  2. Der Betreiber richtet Sie ein: Er legt Ihren Mandanten und Ihre Anmeldung für das Dashboard an, auf jeder Instanz getrennt — eine Anmeldung der Test-Instanz gilt nicht für die Produktion. API-Benutzer legen Sie danach selbst an, siehe API-Benutzer anlegen.
  3. Für die Produktion gibt der Betreiber Ihren Mandanten zusätzlich frei. Bis dahin antwortet ein Antrag über einen produktiven GKS-Zugang mit 403 (siehe Umgebungen).

Was vor der Freigabe der Produktion geschehen muss, hängt davon ab, unter wessen Registrierung Sie senden:

Als Vertragspartner unter der Registrierung des Betreibers. Der Betreiber meldet Sie vor der Anbindung beim KBA — mit Haftungserklärung, Mustervertrag und Meldedatei (CSV). Das KBA prüft die Meldung und vergibt Ihre KOPA-VP; rechnen Sie mit bis zu etwa einer Woche, unter Umständen länger. Diese KOPA-VP nennen Sie dann in jedem Antrag als customization.contractPartner, siehe Vertragspartner und Kundennummer.

Mit eigener KBA-Registrierung. Sie senden über Ihren eigenen GKS-Zugang, siehe GKS-Zugänge anlegen und verwalten.

API-Benutzer anlegen

  1. Melden Sie sich im Dashboard an (Produktion: https://dashboard.kfz-api.de, Test-Instanz: https://dashboard.staging.kfz-api.de). Die Anmeldung bekommen Sie vom Betreiber, siehe So bekommen Sie einen Zugang.
  2. Öffnen Sie Stammdaten → API-Benutzer und legen Sie einen Benutzer mit Name und E-Mail an. Der Name ist Pflicht: Er wird bei jedem Antrag als handelnde Person protokolliert.
  3. Login und Passwort erscheinen einmalig im Seiteninhalt. Notieren Sie beide sofort; danach sind sie nicht mehr auslesbar. Ein neues Passwort lässt sich dort jederzeit erzeugen.

Legen Sie für einen Passwortwechsel ohne Ausfall einen zweiten Benutzer an, stellen Sie Ihre Systeme um und wechseln Sie erst dann das Passwort des ersten.

Authentifizierung

Jede Anfrage trägt HTTP Basic Authentication mit Login und Passwort des API-Benutzers.

LageAntwort
Kopfzeile Authorization fehlt, Zugangsdaten falsch oder Benutzer deaktiviert401 mit WWW-Authenticate: Basic realm="dropshipping-api"
Zugangsdaten gültig, aber für einen anderen Mandanten als den im Pfad403
Zugangsdaten gültig, der Mandant ist abgeschaltet403 mit dem Hinweis, dass die Zugangsdaten in Ordnung sind

Der erste Aufruf

Ein lesender Aufruf, der nichts anlegt — die Liste Ihrer Aufträge:

curl -u "$API_LOGIN:$API_PASSWORT" \
  -H "X-Trace-Id: mein-system-0001" \
  "https://api.staging.kfz-api.de/dropshipping-api/$CLIENT_ID/2.3.0/vehicleDeregistrations/orders?limit=1"

Die Liste umfasst alle Aufträge Ihres Mandanten — auch die anderer API-Benutzer und die aus dem Dashboard. Leer ist sie deshalb nur bei einem Mandanten, der noch keinen Auftrag hat:

Antwort 200 GET /vehicleDeregistrations/orders
{
  "orders": [],
  "limit": 1,
  "offset": 0,
  "total": 0,
  "hasMore": false
}

Der erste Antrag

Legen Sie den Rumpf in eine Datei und schicken Sie ihn ab. Das Beispiel ist eine Außerbetriebsetzung; die Felder erklärt die Seite Außerbetriebsetzung.

curl -u "$API_LOGIN:$API_PASSWORT" \
  -H "Content-Type: application/json" \
  --data @antrag.json \
  "https://api.staging.kfz-api.de/dropshipping-api/$CLIENT_ID/2.3.0/vehicleDeregistrations/deregistrations"
POST /vehicleDeregistrations/deregistrations
{
  "externalOrderId": "schnellstart-0001",
  "email": "kunde@example.de",
  "customization": {
    "productType": "VEHICLE_DEREGISTRATION",
    "licensePlateNumberComponents": { "usageType": "EURO", "city": "HN", "middle": "LL", "end": "2418" },
    "frontLicensePlateSecurityCode": "Vbg",
    "rearLicensePlateSecurityCode": "K7m",
    "vehicleIdentificationNumber": "WBA65432113218654",
    "vehicleRegistrationCertificateSecurityCode": "8407251",
    "licensePlateReservationIncluded": false
  }
}

Die Antwort nennt nur die Auftragsnummer:

Antwort 200 POST /vehicleDeregistrations/deregistrations
{ "order": { "id": 1 } }

Die Antwort kommt sofort, der Versand an das KBA läuft danach im Hintergrund. Das Ergebnis erfahren Sie über Webhooks oder über die Vorgangsauskunft.

X-Trace-Id

Jede Antwort unter /dropshipping-api/ trägt die Kopfzeile X-Trace-Id — auch eine erfolgreiche. Nennen Sie diesen Wert, wenn Sie beim Support nachfragen, zusammen mit dem Zeitpunkt des Aufrufs. Der Betrieb sucht die Anfrage damit im Protokoll — das allerdings nur begrenzt aufbewahrt wird. Melden Sie sich deshalb zeitnah; eine abgewiesene Anfrage legt nichts an und ist nur dort zu finden. Zu einem angelegten Vorgang helfen auch später noch order.id und externalOrderId.

Sie können die Kennung selbst setzen: Schicken Sie X-Trace-Id mit, wird Ihr Wert übernommen und zurückgegeben. Zulässig sind bis zu 128 Zeichen aus A–Z a–z 0–9 . _ : -. Ein anderer Wert wird nicht abgewiesen, sondern durch eine eigene Kennung ersetzt.

Fehlerformat

Jede Fehlerantwort hat denselben Rumpf: error mit der Beschreibung, an die die TraceId angehängt ist, und traceId mit demselben Wert wie in der Kopfzeile.

Antwort 400 POST /vehicleRegistrations/registrations
{
  "error": "Das Feld customization fehlt. (TraceId: 6f1c2a8e-3b7d-4c55-9a10-2f4e8b9d7c31)",
  "traceId": "6f1c2a8e-3b7d-4c55-9a10-2f4e8b9d7c31"
}

Das gilt auch für Fehler, die nicht aus einem Endpunkt stammen, solange der Pfad mit /dropshipping-api/ beginnt: unlesbares JSON, eine unbekannte Adresse (404), ein zu großer Rumpf (413) oder ein falscher Content-Type (415). Nur ein GET mit Accept: text/html — also ein Browser — bekommt für eine unbekannte Adresse eine Seite statt JSON.

Ein Pfad, der weder mit /dropshipping-api/ beginnt noch zu den ohne Anmeldung erreichbaren Zweigen gehört (/docs, /spec/, /health, /web, /login, /logout — dort nur POST zum Abmelden aus dem Dashboard, ein GET ergibt 404 —, /assets/, /favicon.svg sowie die Rückläufe des Vertrauensdienstes unter /vollmacht/), landet beim Dashboard derselben Instanz. Es antwortet mit Klartext statt JSON und ohne X-Trace-Id: ein GET mit einer Weiterleitung auf /login, andere Methoden mit 403 („CSRF-Schutz“) oder 401. Sehen Sie eine dieser Antworten, prüfen Sie die Basis-URL.

Eine unbekannte Adresse in einem der öffentlichen Zweige beantwortet der Server dagegen mit einer HTML-Seite (GET mit Accept: text/html) bzw. mit 404 im JSON-Fehlerformat samt X-Trace-Id.

StatusBedeutung
200angenommen bzw. geliefert
201angelegt — POST /gksConfigurations (mit Location auf den neuen Zugang) und, vom Schilderdienst durchgereicht, die physischen Bestellungen (dort ohne Location)
204ausgeführt, kein Rumpf — DELETE /gksConfigurations/{id}
400Eingabe fehlerhaft — die Meldung nennt das Feld; nichts wurde angelegt oder gesendet
401nicht angemeldet
403angemeldet, aber nicht berechtigt: fremder Mandant, Mandantennummer im Pfad nicht in der einfachen Ziffernschreibweise, Mandant abgeschaltet, Produktion nicht freigegeben oder Geschäftsvorfall nicht im freigegebenen Umfang
404unbekannt — etwa ein Vorgang, ein Beleg oder ein Vollmachtsvorgang, der nicht Ihnen gehört
409passt nicht zum Bestand — siehe Fehler
413Rumpf größer als 12 MB — siehe Grenzen
415falscher Content-Type; für JSON-Endpunkte gilt application/json
500unerwarteter Fehler auf unserer Seite — mit X-Trace-Id, bitte beim Support melden
501im Vertrag vorhanden, von dieser Schnittstelle nicht bedient — fehlen dabei Pflichtfelder, kommt zuerst 400 (siehe Umgebungen)
502ein angebundener Dienst (Vertrauensdienst, Schilderdienst) ist gestört
503gerade nicht möglich — etwa weil der GKS-Zugang nach einer abgelehnten Anmeldung gesperrt ist

Die physischen Bestellungen (POST /orders, /orders/emissionStickerOrders, /orders/reshippedOrders) reicht die Schnittstelle an den hinterlegten Schilderdienst weiter und gibt dessen Status unverändert zurück — dort sind auch andere Codes als die oben genannten möglich.

Grenzen

GrenzeWert
Rumpf einer Anfragehöchstens 12 MB, sonst 413 im üblichen {error, traceId}-Format
Eingebettetes Dokumenthöchstens 8 MB je Dokument (powerOfAttorney.documentBase64, sepaMandateBase64), sonst 400

Die beiden Grenzen greifen nacheinander. Base64 macht aus 8 MB rund 10,7 MB. Eine PDF über etwa 9 MB reißt deshalb schon die Rumpfgrenze: Statt des dokumentierten 400 („höchstens 8 MB") kommt ein 413, und die Meldung nennt kein Feld. Prüfen Sie die Dateigröße vor dem Kodieren.

Keine Ratenbegrenzung. Diese Schnittstelle antwortet nie mit 429 und setzt nie Retry-After. Bauen Sie dafür keine Rückzugsstrategie; welche Statuscodes ein Wiederholen rechtfertigen, steht unter Fehler. Begrenzt sind allein die Flächen des Dashboards — ein Mensch am Browser, keine Anbindung.

Durchsatz. Je GKS-Kennung geht immer nur ein Versand gleichzeitig an das KBA — sonst könnten gleichzeitige Anträge die Kennung beim KBA sperren. Ein Stapel Anträge bekommt deshalb sofort 200, geht aber nacheinander hinaus; verschiedene Zugänge behindern sich dabei nicht. Wer Stockungen bemerken will, misst sie über GET …/orders?state=angelegt — der Zustand eines Vorgangs, der noch nicht an das KBA hinaus ist — und das createdAt des ältesten solchen Auftrags; siehe Webhooks.

Ablauf in Kürze

  1. Für Dritte: Vollmacht einholen — über den Vertrauensdienst (Vollmacht) oder als qualifiziert unterschriebenes PDF. Die Außerbetriebsetzung braucht keine Vollmacht.
  2. Antrag stellenPOST an den Endpunkt der Vorgangsart. Die Antwort nennt order.id.
  3. Quittung des KBA — Ereignis mit status ACCEPTED, FORWARDED oder FAILED.
  4. Bescheid — über den Rückkanal, Ereignis mit APPROVED_WITH_DOCUMENTS, REJECTED_WITH_DOCUMENTS (oder ohne _WITH_DOCUMENTS, wenn keine Belege beiliegen).
  5. Belege abrufen — mit dem fileAccessKey aus dem Ereignis.

Vertrag und Referenz

Die vollständigen Verträge liegen als OpenAPI-Dateien vor: /spec/api.yaml und /spec/webhooks.yaml. Daraus lässt sich Client-Code erzeugen. Die Vorgaben des servers-Eintrags zeigen auf die Test-Instanz und tragen für die Mandantennummer einen Platzhalter — setzen Sie beide, bevor Sie den Client benutzen. Lesbar aufbereitet stehen sie unter Referenz: API und Referenz: Webhooks.

Beschrieben ist dort der Kundenvertrag unter /dropshipping-api/{clientId}/2.3.0 — das ist der einzige servers-Eintrag der Datei. GET /health steht als unauthentifizierte Betriebsauskunft daneben und ist in keiner der beiden YAML-Dateien als Pfad beschrieben; beschrieben ist es unter Umgebungen und Versionen.

Support

Fragen zur Anbindung, Störungen und Zugangsanfragen erreichen uns auch ohne Anmeldung:

Angemeldet geht es auch über Support im Dashboard: Ein Ticket nimmt die Angaben zu Ihrer Anbindung selbst mit. Eine Antwort im Ticket löst keine E-Mail aus — sehen Sie dort nach, und rufen Sie an, wenn es eilt.

Damit wir Ihre Anfrage im Protokoll finden, nennen Sie:

  • die TraceId aus der Kopfzeile X-Trace-Id der Antwort (siehe X-Trace-Id),
  • die Vorgangsnummer order.id und Ihre externalOrderId,
  • den Zeitpunkt des Aufrufs mit Datum und Uhrzeit,
  • bei einer Ablehnung den Quittungscode aus messages.

Schicken Sie keine Passwörter und keine Schlüssel mit.