Lieferanten-API nutzen
Dein ERP direkt ans Portal anbinden — API-Key, Endpoints, Rate-Limits, Fehler-Handling.
Das Cleverbikes Portal bietet eine REST-API, über die dein ERP-System Bikes direkt anlegen, aktualisieren und abfragen kannst. Keine manuellen Uploads mehr — alles programmatisch über Bearer-Token-Auth, Rate-Limits und vollständige Fehlerbehandlung (RFC 7807).
Schnelleinstieg
- API-Key — siehe Eigene Daten.
- Base-URL — alle Endpoints unter
/api/public/v1(dynamisch von deiner Portaldomain abgeleitet). - Interaktive Referenz — teste Calls live unter https://cb-dev.apps.xentralintelligence.com/api/docs/supplier mit deinem Key.
Authentifizierung
Jeden Request mit Bearer-Token-Header:
Authorization: Bearer sk_live_dein_klartext_keyDer Klartext-Key (nur beim Create sichtbar) wird serverseitig gehasht — keine Plaintext-Speicherung.
Health-Check
Du möchtest schnell prüfen, ob die API erreichbar ist (ohne Auth)?
curl -X GET https://cb-dev.apps.xentralintelligence.com/api/public/v1/health
Response: HTTP 200 mit { status: "ok", layer: "public-supplier-api", timestamp, version }.
Perfekt für Uptime-Monitore + Load-Balancer-Health-Checks.
Selbstdiagnose — /me
Sichere dich ab, dass du als erwarteter Lieferant authentifiziert bist, und lese live die aktuelle Rate-Limit-Quota:
curl -X GET https://cb-dev.apps.xentralintelligence.com/api/public/v1/me
Response-Shape:
{
"supplier": {
"id": "supplier-uuid",
"slug": "velo-gmbh",
"name": "Velo GmbH"
},
"apiKey": {
"label": "Production Key",
"prefix": "sk_live_ABCD",
"createdAt": "2025-05-10T10:00:00Z",
"lastUsedAt": "2025-05-12T14:30:00Z"
},
"rateLimit": {
"perMinute": 100,
"perHour": 1000,
"remainingMinute": 99,
"remainingHour": 998,
"resetMinute": 42,
"resetHour": 1234
},
"scope": "supplier"
}Use-Case: Smoke-Test nach API-Key-Rotation oder um sicherzustellen, dass dein Client den richtigen Lieferanten-Scope hat.
Schema-Discovery
Felder dynamisch laden
Dein ERP soll Bike-Formulare automatisch aus den verfügbaren Feldern generieren?
curl -X GET https://cb-dev.apps.xentralintelligence.com/api/public/v1/fields
Response: Liste aller Felder + Typ (text, dropdown, date, currency, …) + Validation-Constraints + Dropdown-Optionen. So bleibt dein UI bei Schema-Änderungen immer in Sync.
Dropdown-Enum-Werte
Für dynamische Dropdowns (Radtypen, Rahmengrößen, Bike-Status):
curl -X GET https://cb-dev.apps.xentralintelligence.com/api/public/v1/enums/bike_types
Unterstützte Typen: bike_statuses, bike_types, frame_sizes.
Bikes erstellen & verwalten
Einzelnes Bike anlegen
curl -X POST https://cb-dev.apps.xentralintelligence.com/api/public/v1/bikes \
-d '"{\n\"name\": \"Canyon Grand Canyon 7\",\n\"frame_number\": \"FR-2025-00042\",\n\"fieldValues\": {\n \"bike_type\": \"normales_rad\",\n \"brand\": \"Canyon\",\n \"model\": \"Grand Canyon\",\n \"frame_size\": \"L\",\n \"customer_name\": \"Max Mustermann\",\n \"leasing_start_date\": \"2025-06-01\",\n \"gross_uvp\": \"1299.99\",\n \"reference\": \"LS-2025-12345\"\n}\n}"'
Wichtig:
name+frame_numbersind Pflichtfelder.frame_numbermuss unique pro Lieferant sein.fieldValuesnimmt nur Felder an, die viaGET /fieldsverfügbar sind.- Idempotency-Key ist Pflicht — verhindert Duplikate bei Netzwerk-Retries.
Response: HTTP 201 + Bike-JSON mit generierter id.
Batch-Create (max 50)
Für viele Bikes auf einmal:
curl -X POST https://cb-dev.apps.xentralintelligence.com/api/public/v1/bikes/batch \
-d '"{\n\"bikes\": [\n {\n \"name\": \"Bike 1\",\n \"frame_number\": \"FR-2025-00001\",\n \"fieldValues\": { \"bike_type\": \"normales_rad\", \"brand\": \"Cube\" }\n },\n {\n \"name\": \"Bike 2\",\n \"frame_number\": \"FR-2025-00002\",\n \"fieldValues\": { \"bike_type\": \"lastenrad\", \"brand\": \"Riese & Müller\" }\n }\n]\n}"'
Response: HTTP 200 mit
{
"results": [
{ "index": 0, "status": 201, "bikeId": "...", "error": null },
{ "index": 1, "status": 201, "bikeId": "...", "error": null }
],
"importJobId": "job-uuid"
}Jede Zeile wird einzeln validiert — teilweise Erfolg ist möglich (z. B. Zeile 0 OK, Zeile 1 Duplicate-Frame-Number).
Bikes auflisten
Mit Cursor-Pagination und Filtern:
curl -X GET https://cb-dev.apps.xentralintelligence.com/api/public/v1/bikes?status=Neu%20eingegangen&limit=10
Query-Parameter:
status— Filter nach Bike-Status (z. B.Neu eingegangen)createdAfter/createdBefore— ISO-8601 Timestampslimit— max Items pro Seite (default: 10)cursor— Pagination-Token (leer für erste Seite)
Einzelnes Bike abrufen
curl -X GET https://cb-dev.apps.xentralintelligence.com/api/public/v1/bikes/bike-uuid
Bike aktualisieren (Partial Update)
curl -X PATCH https://cb-dev.apps.xentralintelligence.com/api/public/v1/bikes/bike-uuid \
-d '"{\n\"fieldValues\": {\n \"model\": \"Grand Canyon 2025\",\n \"frame_size\": \"XL\"\n}\n}"'
Nur übergebene Felder werden geändert. Status-Transitions müssen
supplier-erlaubt sein (z. B. Storniert durch Lieferant).
Bike löschen
Nur möglich, wenn das Bike noch im Status Neu eingegangen ist:
curl -X DELETE https://cb-dev.apps.xentralintelligence.com/api/public/v1/bikes/bike-uuid
Response: HTTP 204 (kein Body). Nach Status-Transition → HTTP 409 (Bike ist nicht mehr löschbar).
Change-Requests (Änderungsanträge)
Wenn ein Bike sein Status-Fenster verlassen hat (z. B. Neu eingegangen),
können Daten nicht mehr direkt via PATCH geändert werden. Stattdessen
stellst du einen Change-Request:
Change-Request anlegen
curl -X POST https://cb-dev.apps.xentralintelligence.com/api/public/v1/bikes/bike-uuid/change-requests \
-d '"{\n\"fieldChanges\": {\n \"model\": \"Grand Canyon 2.0\",\n \"customer_name\": \"Jane Doe\"\n},\n\"comment\": \"Kundenname und Modell wurden korrigiert\"\n}"'
Response: HTTP 201 + Change-Request-JSON mit status: "pending" + id.
Change-Request-Status prüfen (Polling)
curl -X GET https://cb-dev.apps.xentralintelligence.com/api/public/v1/bikes/bike-uuid/change-requests/cr-uuid
Response:
{
"id": "cr-uuid",
"bikeId": "bike-uuid",
"status": "approved",
"createdAt": "2025-05-12T10:00:00Z",
"decidedAt": "2025-05-12T11:30:00Z",
"fieldChanges": {
"model": "Grand Canyon 2.0",
"customer_name": "Jane Doe"
},
"comment": "Kundenname und Modell wurden korrigiert",
"decisionComment": null
}Status-Werte: pending, approved, rejected.
- Bei
approvedoderrejectedistdecidedAtgesetzt. - CB-Staff entscheidet über Approve/Reject (nicht du).
Rate-Limits
Pro API-Key gelten:
- 100 Requests/Minute (Sliding-Window)
- 1.000 Requests/Stunde (Sliding-Window)
Jede Antwort enthält 6 Rate-Limit-Header:
| Header | Bedeutung |
|---|---|
X-RateLimit-Limit-Minute | Max. Requests/Minute |
X-RateLimit-Remaining-Minute | Verbleibend in laufende Minute |
X-RateLimit-Reset-Minute | Sekunden bis Reset (nicht Unix-Timestamp!) |
X-RateLimit-Limit-Hour | Max. Requests/Stunde |
X-RateLimit-Remaining-Hour | Verbleibend in laufende Stunde |
X-RateLimit-Reset-Hour | Sekunden bis Reset |
Bei Überschreitung: HTTP 429 + Retry-After-Header.
Wichtig: X-RateLimit-Reset-Minute bedeutet z. B. 42 =
in 42 Sekunden ist das Minuten-Fenster vorbei, nicht ein Unix-Timestamp!
Idempotency
Alle POST-Requests erfordern einen Idempotency-Key-Header:
Idempotency-Key: bike-2025-00042Regeln:
- Format: opaque String, 8–64 Zeichen (UUID empfohlen)
- Gleiche Key + gleicher Body → Server cached die Response (24h TTL)
- Gleiche Key + anderer Body → HTTP 409
idempotency_conflict - Verhindert Duplikate bei Netzwerk-Retries
Fehler-Handling (RFC 7807)
Alle Fehler folgen dem RFC-7807-Standard (Problem Details JSON):
curl -X POST https://cb-dev.apps.xentralintelligence.com/api/public/v1/bikes \
-d '"{\n\"name\": \"Bike X\",\n\"frame_number\": \"FR-DUPLICATE\",\n\"fieldValues\": { \"bike_type\": \"normales_rad\" }\n}"'
Beispiel-Fehler (Rahmennummer bereits vergeben):
{
"type": "https://errors.baldux.dev/v1/duplicate-frame-number",
"title": "Frame-Number bereits für diesen Lieferant vergeben",
"status": 409,
"code": "duplicate_frame_number",
"detail": "Die Rahmennummer FR-DUPLICATE existiert schon.",
"instance": "/api/public/v1/bikes",
"requestId": "req-uuid"
}HTTP-Status-Übersicht
| Status | Bedeutung | Aktion |
|---|---|---|
| 2xx | Erfolg | Keine Aktion erforderlich |
| 4xx | Dein Fehler | Log + korrigieren + Retry mit Exponential-Backoff |
| 5xx | Portal-Fehler | Exponential-Backoff + später erneut versuchen |
Häufige Error-Codes
unauthorized— Fehlender/ungültiger API-Keymissing_api_key— Authorization-Header fehltvalidation_failed— Input-Validierung fehlgeschlagenduplicate_frame_number— Frame-Number already existsbike_not_found— Bike existiert nicht oder gehört anderem Supplierpending_change_request_exists— CR für dieses Bike existiert bereitsrate_limited— Rate-Limit überschrittenidempotency_conflict— Idempotency-Key mit anderem Body
Alle Codes sind stabil (lower_snake_case) und werden nicht mit Instanz-Details durchmischt.
Outgoing-Webhooks
Outgoing-Webhooks für Lieferanten sind aktuell admin-konfiguriert. Eine eigenständige Setup-UI für Lieferanten folgt in einer späteren Welle.
Weitere Ressourcen
- Interaktive Lieferanten-API-Doku — Live-Dokumentation via Scalar-UI, teste Calls mit deinem Key
- Eigene Daten — API-Key anlegen & verwalten
- Fehler verstehen — Detailliertes Error-Handling
Weiterlesen
- Eigene Daten — API-Keys verwalten
- Fehler verstehen — Fehlercodes + Lösungen
- Bikes anlegen — auch per API nutzbar