EntwicklerAPI-Dokumentation
API-Dokumentation
Damit bindest du deine eigene Website oder deinen Shop an: Reparaturen mit Preisen abrufen, bezahlte Bestellungen als Auftrag anlegen und den Stand abfragen.
Inhalt
Überblick#
Typischer Einsatz: Du erzeugst für jedes Modell und jede Reparatur eine eigene Seite („iPhone 15 Display Reparatur“), kassierst in deinem Shop – und die bezahlte Bestellung landet automatisch als Auftrag im Cockpit.
https://app.repaircockpit.de/api/v1
Alle Endpunkte auf einen Blick#
Jeder Eintrag führt zur Beschreibung mit Beispiel und nennt den Zugang, den der Endpunkt verlangt (siehe Zugangsdaten).
- GET/api/v1/repairsPublic KeyReparaturen mit Preisen abrufen – eine Zeile je Modell und Reparatur
- GET/api/v1/booking/catalogPublic KeyGerätetypen und Marken mit Anzahl
- GET/api/v1/booking/catalog/modelsPublic KeyModelle einer Marke mit Bild, Farben, Preisen
- GET/api/v1/booking/catalog/searchPublic KeySuche nach Name, Marke oder Modellnummer
- POST/api/v1/ordersPublic Key + Shop-TokenBezahlte Bestellung als Auftrag anlegen
- GET/api/v1/orders/{reference}Public Key + Shop-TokenStand einer Bestellung abfragen
- POST/api/v1/checkout/quotePublic KeyPreise und Kombi-Rabatt vom Server rechnen lassen
- POST/api/v1/checkoutPublic Key + Shop-TokenBuchung starten: vor Ort bezahlen oder Vorkasse über Mollie
- GET/api/v1/checkout/{token}Public Key + Shop-TokenStand der Vorkasse abfragen
- POST/api/v1/booking/kundenkonto/linkPublic KeyZugang zum Kundenportal per E-Mail schicken („Meine Aufträge“)
- GET/api/v1/booking/configPublic KeyKonfiguration des Widgets, u. a. Zahlweisen und Rechtliches
- POST/api/v1/booking/warenkorbPublic KeyWarenkorb des Widgets bestellen, auch mit Online-Zahlung
- GET/api/v1/booking/warenkorb/zahlung/{token}Public Key + token im PfadStand einer Warenkorb-Zahlung abfragen
- POST/api/v1/booking/warenkorb/zahlung/{token}/erneutPublic Key + token im PfadZahlung nach einem Fehlschlag erneut versuchen
- POST/api/v1/booking/warenkorb/zahlung/{token}/im-ladenPublic Key + token im PfadDoch im Laden bezahlen
- POST/api/v1/booking/widerrufPublic KeyVertrag widerrufen (§ 356a BGB)
- POST/api/v1/booking/anfragePublic KeyAnfrage stellen („Frage stellen“)
- GET/api/v1/booking/trackPublic KeyLink ins Kundenportal zu Auftragsnummer und Kontakt („Reparatur verfolgen“)
Zugangsdaten#
Du findest beide im Cockpit unter Einstellungen → Online-Buchung, Karte „Schlüssel für eigene Anbindungen“.
Wisch zur Seite für alle Spalten →
| Schlüssel | Wofür | Geheim? |
|---|---|---|
Public Keypk_live_… oder pk_test_… | Identifiziert deinen Betrieb. Wird bei jeder Anfrage im Kopf X-RC-Public-Key mitgeschickt. Die Vorsilbe ist nur ein Name: beide Formen gelten gleich, einen Testmodus gibt es nicht. | Nein – darf im Quelltext deiner Seite stehen. |
Shop-Tokensk_… | Erlaubt das Anlegen von Aufträgen. Als Authorization: Bearer …. | Ja. Nur auf deinem Server, nie im Browser. |
1. Reparaturen abrufen#
Liefert eine Zeile je Modell und Reparatur – genau das, was du für eine eigene Seite brauchst.
GET /api/v1/repairs?type=phone&brand=Apple&page=1&limit=200 X-RC-Public-Key: pk_live_…
{
"total": 32,
"page": 1,
"limit": 200,
"has_more": false,
"repairs": [
{
"id": "8f89d1ce-…:display-tausch",
"device_model_id": "8f89d1ce-…",
"slug": "apple-iphone-16e-display-tausch",
"title": "Apple iPhone 16e Display-Tausch",
"type": "phone",
"brand": "Apple",
"model": "iPhone 16e",
"repair": "Display-Tausch",
"price_cents": 15900,
"currency": "EUR",
"duration_minutes": 60,
"warranty_months": 12,
"model_numbers": ["A3212", "A3409"],
"image": "https://app.repaircockpit.de/api/v1/booking/models/…/image?key=pk_live_…"
}
]
}price_centsist brutto und trägt bereits die Preisendung deines Betriebs (z. B. …9,00 €). Du musst nichts umrechnen – nur formatieren.slugist als Adresse deiner Seite gedacht:/reparatur/apple-iphone-16e-display-tausch.model_numberssind die aufgedruckten Nummern (z. B.A3212) – hervorragend für die Suche und als Text auf der Seite, weil danach gesucht wird.
| Parameter | Wirkung |
|---|---|
type | Filter: phone, tablet, laptop, smartwatch, console, desktop, escooter |
brand | Filter nach Marke, z. B. Apple |
page + limit | Seiten; limit höchstens 500 |
Dein Gerätekatalog zum Durchblättern#
Für eine Auswahl in Schritten gibt es zusätzlich:
| Weg | Liefert |
|---|---|
GET /api/v1/booking/catalog | Gerätetypen und Marken mit Anzahl (klein, ~2 KB) |
GET /api/v1/booking/catalog/models?type=phone&brand=Apple | Modelle einer Marke mit Bild, Farben, Preisen |
GET /api/v1/booking/catalog/search?q=A3293 | Suche nach Name, Marke oder Modellnummer |
2. Bezahlte Bestellung anlegen#
Ruf das auf, nachdem die Zahlung eingegangen ist (bei WooCommerce z. B. im Haken woocommerce_payment_complete).
POST /api/v1/orders X-RC-Public-Key: pk_live_… Authorization: Bearer sk_… Content-Type: application/json Accept: application/json { "reference": "WC-10423", "customer": { "first_name": "Maria", "last_name": "Schmidt", "email": "maria@example.de", "phone": "0170 1234567", "marketing_opt_in": false, "address_line1": "Bahnhofstraße 1", "postal_code": "12345", "city": "Musterstadt", "country": "DE" }, "delivery": "einsendung", "items": [ { "device_model_id": "8f89d1ce-…", "repair": "Display-Tausch", "price_cents": 15900 }, { "device_model_id": "8f89d1ce-…", "repair": "Akku-Tausch", "price_cents": 4900 } ], "note": "Kunde sendet das Gerät ein." }
{
"reference": "WC-10423",
"orders": [
{
"number": "RT-629470",
"status": "waiting",
"tracking_url": "https://app.repaircockpit.de/kunde/NPhq…?auftrag=…"
}
]
}- Je Gerät entsteht ein Auftrag, mit einer Position je Reparatur – so, wie es der Werkstatt-Alltag verlangt: ein Gerät, ein Zettel, mehrere Arbeiten darauf.
- Statt
device_model_idkannst du auchdevice_labelschicken (z. B."Apple iPhone 16e"), wenn das Gerät nicht aus unserem Katalog stammt.
tracking_urlkannst du dem Kunden direkt schicken – er sieht dort den Stand und kann Nachrichten schreiben, ganz ohne Konto.
Einsendung oder Abgabe vor Ort#
delivery sagt, wie das Gerät zu uns kommt:
| Wert | Bedeutung |
|---|---|
vorbeibringen | Der Kunde bringt das Gerät in den Laden. Vorgabe, wenn du das Feld weglässt. |
einsendung | Der Kunde schickt es ein. |
Bei einsendung sind address_line1, postal_code und city Pflicht. Ohne Absenderanschrift druckt DHL kein Retourenlabel – die Bestellung würde einen Auftrag erzeugen, zu dem nie ein Label kommt, und der Kunde wartet auf Post, die niemand losgeschickt hat. Fehlt eines der Felder, antwortet die Schnittstelle mit 422.
Bei vorbeibringen bleibt die Anschrift freiwillig. Schick sie trotzdem mit, wird sie als Rechnungsanschrift übernommen – eine bereits hinterlegte Anschrift bleibt unangetastet.
Eine Einsendung landet im Cockpit in der Spalte „Auf dem Weg zu uns“, nicht in der Annahme: es liegt ja noch nichts auf dem Tisch. Der Status ist entsprechend waiting.
Hat die Werkstatt unter Einstellungen → Integrationen die DHL-Anbindung aktiv und den Schalter „Label direkt bei Online-Buchung“ gesetzt, entsteht das Retourenlabel automatisch – kurz nach der Bestellung, nicht während sie läuft. Es taucht am Auftrag auf; scheitert es, steht dort der Grund.
Doppelte Zustellungen sind unschädlich#
reference ist dein Schlüssel (die Bestellnummer). Wird derselbe Aufruf zweimal zugestellt – Netzwerkfehler, Webhook-Wiederholung – entsteht kein zweiter Auftrag; du bekommst denselben zurück. Du brauchst also keine eigene Absicherung dagegen.
3. Stand einer Bestellung#
GET /api/v1/orders/WC-10423 X-RC-Public-Key: pk_live_… Authorization: Bearer sk_…
{
"reference": "WC-10423",
"orders": [
{
"number": "RT-629470",
"status": "intake",
"device": "Apple iPhone 16e",
"repairs": "Display-Tausch, Akku-Tausch",
"tracking_url": "https://app.repaircockpit.de/kunde/NPhq…?auftrag=…"
}
]
}Damit zeigst du im Kundenkonto deines Shops „Deine Reparatur läuft“, ohne dass sich jemand zusätzlich anmelden muss.
4. Checkout für ein eigenes Buchungs-Widget (Preise vom Server, Vorkasse über Mollie)#
Für Websites, die selbst buchen lassen, statt eine schon bezahlte Bestellung zu übergeben. Die Website schickt nur Gerät und Reparaturen – Preise und Kombi-Rabatt rechnet RepairCockpit.
POST/api/v1/checkout/quote#
Public KeyPOST /api/v1/checkout/quote X-RC-Public-Key: pk_live_… { "items": [ { "device_model_id": "…", "offers": ["Displaytausch", "Akkutausch"] } ] }
{
"total_cents": 33800,
"discount_cents": 2000,
"combo_discount_percent": 20,
"payment": {"mollie": true, "vor_ort": true},
"items": […]
}POST/api/v1/checkout#
Public Key + Shop-TokenPOST /api/v1/checkout X-RC-Public-Key: pk_live_… Authorization: Bearer sk_… { "reference": "LF-M1ABC2-XY7Q9", // eigene Kennung, macht den Aufruf wiederholbar "payment": "mollie", // oder "vor_ort" "return_url": "https://deine-seite.de/danke/", // Pflicht bei mollie; bekommt ?rc_token=… angehängt "expected_total_cents": 33800, // optional: weicht der Server ab → 409 preis_geaendert "price_after_diagnosis": false, // optional: true, wenn der Preis erst nach der Diagnose feststeht "delivery": "einsendung", "customer": {"first_name":"…","last_name":"…","email":"…","address_line1":"…","postal_code":"…","city":"…"}, "consent": {"privacy": true}, "items": [{"device_model_id":"…","offers":["Displaytausch","Akkutausch"]}] }
vor_ort→ 201, Auftrag sofort angelegt:{"status":"confirmed","orders":[{"number","tracking_url"}],…}mollie→ 200{"status":"open","token":"…","checkout_url":"https://www.mollie.com/checkout/…"}. Schick den Kunden zurcheckout_url. Der Auftrag entsteht erst nach bestätigter Zahlung (Mollie-Webhook an RepairCockpit), genau einmal, mit dem Vermerk „VORKASSE ONLINE BEZAHLT …“. Beim Kassieren rechnet die Kasse die Vorkasse selbst an (unbare Zahlung an der Rechnung, nur der Rest wird kassiert); ist der Auftrag billiger geworden, steht die Überzahlung im Dashboard zum Erstatten in Mollie.- Nicht buchbare Reparatur →
422; Zahlweg nicht erlaubt oder Online-Zahlung nicht eingerichtet →422payment; Mollie lehnt ab →502.
Welcher Zahlweg geht, bestimmt der Betrieb unter Einstellungen → Online-Buchung – dieselbe Einstellung wie im Widget:
| „Online bezahlen“ | „Bezahlen im Laden erlauben“ | erlaubt |
|---|---|---|
| aus | (ohne Wirkung) | nur vor_ort |
| an | an | mollie und vor_ort – der Kunde wählt |
| an | aus | nur mollie – immer online |
Die Preisabfrage nennt die erlaubten Wege unter payment; zeig im Bezahlschritt nur diese. Einen anderen Weg weist /checkout mit 422 payment ab. „Online bezahlen“ braucht ein verbundenes Mollie-Konto und einen Tarif mit Online-Zahlung.
Steht der Preis erst nach einer Diagnose fest (etwa bei einer Datenrettung), schick "price_after_diagnosis": true. Dann gilt vor_ort auch bei einem Betrieb, der sonst immer online bezahlen lässt, und mollie wird abgewiesen – einen offenen Preis kann niemand vorab bezahlen.
GET/api/v1/checkout/{token}#
Public Key + Shop-TokenGET /api/v1/checkout/{token} X-RC-Public-Key: pk_live_… Authorization: Bearer sk_…
{
"status": "paid",
"orders": [{"number": "RT-…", "tracking_url": "…"}],
"total_cents": 33800,
…
}Die Rückkehrseite fragt hier nach; ist der Webhook noch nicht angekommen, zieht dieser Aufruf den Stand selbst bei Mollie nach und legt den Auftrag an.
5. „Meine Aufträge“ – Kundenkonto-Link per E-Mail#
Damit bekommt deine Website einen Login für Kunden, ganz ohne Passwort: der Kunde gibt seine E-Mail-Adresse ein und erhält den Zugang zum Kundenportal per Mail. Dort sieht er alle seine Aufträge, Rechnungen, Fotos und Kostenvoranschläge.
POST /api/v1/booking/kundenkonto/link X-RC-Public-Key: pk_live_… Content-Type: application/json Accept: application/json {"email": "erika@example.de"}
{"status": "gesendet"}- Die Antwort ist immer
202 {"status":"gesendet"}– auch wenn die Adresse bei dir gar nicht bekannt ist. So lässt sich über deine Website nicht herausfinden, wer dein Kunde ist. Zeig deshalb immer denselben Satz, z. B. „Wenn wir Aufträge zu dieser Adresse haben, ist der Link unterwegs.“ - Gefunden wird jeder Kunde mit dieser Adresse (Groß-/Kleinschreibung egal). Stehen mehrere Kundenkonten unter derselben Adresse, kommt eine Mail mit je einem Link.
- Der Link ist signiert und 7 Tage gültig (danach einfach neu anfordern). Adresse, Telefon und Rechnungs-PDFs schaltet das Portal wie gewohnt erst nach der kurzen Code-Prüfung frei.
- Keine Mail geht an Kunden ohne Auftrag, Rechnung oder Angebot, an gelöschte Kunden und an Adressen, die ein Kunde nur selbst im Portal eingetragen hat (erst wenn du die Adresse im Cockpit speicherst).
- Absender ist dein Betrieb (Name, Antwortadresse bzw. dein eigener SMTP-Server) – wie bei jeder Kundenmail.
422bei fehlender oder ungültiger Adresse (errors.email),429nach 5 Anfragen pro Minute je Anschluss oder 5 Anfragen pro Stunde je E-Mail-Adresse.
6. Warenkorb des eingebetteten Widgets (Online-Zahlung, Widerruf)#
Diese Wege nutzt das eigene RepairCockpit-Widget (/widget.v2.js) für seinen Warenkorb mit mehreren Geräten und den Online-Zahlungsschritt darin – nicht zu verwechseln mit Abschnitt 4 (/api/v1/checkout), der für eine selbst gebaute Oberfläche mit Shop-Token gedacht ist. Hier reicht wie bei /config, /quote und /submit allein X-RC-Public-Key: eine Bestellung entsteht erst am Ende des ganzen Sitzungs-Ablaufs (/session → /quote → /slots/hold → /warenkorb), nie aus einem einzelnen Aufruf.
GET/api/v1/booking/config#
Public KeyGET /api/v1/booking/config liefert seit dem Widget-Shop zusätzlich:
{
"zahlung": {"online": true, "im_laden": false},
"diagnose": {"regel": "immer", "hinweis": "…", "je_art": {"phone": 2900}, "standard_cents": 1900},
"rechtliches": {
"knopf": "Zahlungspflichtig bestellen",
"haekchen": "…",
"belehrung": [{"text": "… {adresse} …"}],
"preis_hinweis": "Alle Preise inkl. MwSt.",
"agb_url": "https://…"
}
}rechtliches kommt nur, wenn online bezahlt werden kann, sonst null – ohne Online-Zahlung ist „im Laden“ eine gewöhnliche Anmeldung, kein Fernabsatzvertrag, und eine unbenutzte Belehrung würde nur verwirren. {adresse} darin ersetzt das Widget durch seine eigene Seite plus ?rc-widerruf=1.
Bestellen#
POST /api/v1/booking/warenkorb X-RC-Public-Key: pk_live_… { "session": "…", "items": [{"device_label": "Apple iPhone 13", "device_type": "phone", "offers": ["Displaytausch"]}], "contact": {"first_name": "…", "last_name": "…", "email": "…", "phone": "…"}, "delivery": "vorbeibringen", "zahlung": "online", "expected_total_cents": 15900, "return_url": "https://deine-seite.de/warenkorb/", "vorzeitig": true, "consent": {"privacy": true}, "started_at": 1759160000, "website": "", "turnstile_token": "" }
Dazu gehören dieselben drei Bot-Schutz-Felder wie bei Abschnitt 7: started_at (Pflicht), das leere versteckte Feld website und – wenn der Betrieb es verlangt – turnstile_token.
zahlung: "laden"oder eine Summe von 0 (gleich welcher Zahlweg) legt die Aufträge sofort an:201 {"status":"confirmed","total_cents":0,"orders":[{"number":"…","tracking_url":"…"}]}–total_centsist die Summe, hier 0.zahlung: "online"mit einer Summe über 0 startet die Vorkasse bei Mollie:200 {"status":"open","token":"…","checkout_url":"https://www.mollie.com/checkout/…"}. Schick den Kunden zucheckout_url; nach der Zahlung hängt Mollie?rc_zahlung=<token>an deinereturn_urlan.expected_total_centsist beionlinePflicht und muss zum Server-Preis passen, sonst409 {"grund":"preis_geaendert","total_cents":…}.return_urlmuss eine im Cockpit erlaubte Domain sein, undvorzeitig: trueist die ausdrückliche Zustimmung zur vorzeitigen Ausführung (§ 312j Abs. 3 BGB) – fehlt eines davon oder ist online gerade nicht möglich, kommt422 {"grund":"zahlung"}, nie ein gewöhnlicher Validierungsfehler.- Legt derselbe Kunde dasselbe Gerät zweimal in den Warenkorb, entstehen zwei Aufträge.
- Ein inzwischen anderweitig vergebener gehaltener Termin meldet
409 {"grund":"termin"}. - Läuft für denselben Vorgang noch eine andere Zahlung bei Mollie und lässt sie sich nicht abbrechen (typisch: eine Überweisung ist schon unterwegs), entsteht bewusst keine zweite – der Server meldet
409 {"grund":"zahlung_laeuft","checkout_url":"…"}.checkout_urlist die Bezahlseite der noch offenen Zahlung – odernull, wenn gerade ein zweiter Aufruf derselben Sitzung läuft. - Schickt dieselbe Sitzung
/warenkorbein zweites Mal, während die vorherige Vorkasse desselben Vorgangs schon bezahlt ist (Doppelklick, zweiter Tab), antwortet der Server mit200und der vollen Stand-Form wie beiGET .../warenkorb/zahlung/{token}(checkout_urldannnull) – nicht mit der schlanken{"status":"open",...}-Form von oben. Prüfstatusin der Antwort, statt sie ungeprüft als „neu gestartet“ zu behandeln.
Geräte ohne Festpreis werden zur Anfrage#
Nur, wenn der Betrieb den Schalter „Anfragen“ eingeschaltet hat (GET /config meldet das über anfragen, siehe Abschnitt 7). Ein Gerät im Warenkorb, dessen Summe 0 oder weniger ergibt – ein freies Gerät ohne Katalogmodell, nur Reparaturen „auf Anfrage“ oder eine Fehlerdiagnose ohne Pauschale – wird nicht zum Auftrag, sondern zu einer eigenen Anfrage im Posteingang des Betriebs. Zwei zusätzliche, optionale Felder im Rumpf:
{
"beschreibung": "Das Display ist seit dem Sturz gesprungen und reagiert kaum noch.",
"fotos": ["data:image/jpeg;base64,/9j/4AAQ…"]
}beschreibung(10–2.000 Zeichen) ist Pflicht, sobald der Warenkorb mindestens ein solches Gerät enthält – fehlt sie, kommt ein gewöhnlicher Validierungsfehler (422 {"errors":{"beschreibung":[…]}}). Alle Anfrage-Geräte desselben Warenkorbs teilen sich dieselbe Beschreibung.fotos: 0–3 Bild-Daten-Adressen, wie beiPOST /api/v1/booking/anfrage(Abschnitt 7) – höchstens 3 MB je Foto, JPEG oder PNG, wird neu kodiert (kein EXIF). Liegen mehrere Anfrage-Geräte im Warenkorb, bekommt nur das erste die Fotos; die weiteren verweisen im Verlauf auf dessen Nummer.expected_total_centsund der Zahlweg (zahlung) beziehen sich nur auf die Geräte MIT Festpreis – bleiben nach dem Abtrennen keine übrig, istzahlungüberflüssig (wird ignoriert) und die Antwort kommt sofort:201 {"status":"confirmed","total_cents":0,"orders":[],"anfragen":[…]}.- Jede Erfolgsantwort (sofortiger Abschluss, offene Vorkasse, schon bezahlt) trägt zusätzlich
"anfragen": [{"nummer":"A-2026-0002","device_label":"Fairphone 5"}]– leer, wenn keine Anfrage dabei war. Ohne den Schalter fehlt das Feld ganz, die Antwort bleibt unverändert. - Ein erneuter Aufruf mit demselben Warenkorb (Doppelklick, Netzwerk-Wiederholung) legt je Gerät höchstens eine Anfrage an – die vorhandene Nummer kommt zurück, keine zweite E-Mail geht hinaus. Liegt dagegen dasselbe Gerät zweimal im selben Warenkorb (z. B. zwei baugleiche Handys), zählt das als zwei eigenständige Anfrage-Wünsche: es entstehen zwei Anfragen mit unterschiedlicher Nummer, beide in
anfragen.
Stand, erneuter Versuch, doch im Laden zahlen#
Der token aus der Bestellantwort – bzw. der Wert von ?rc_zahlung nach der Rückkehr von Mollie – ist die einzige Zugangsvoraussetzung für die folgenden drei Wege (kein Shop-Token nötig; den Public Key im Kopf schickst du wie bei jeder Anfrage mit). Er wirkt damit wie ein Bearer-Token für genau diese eine Zahlung: Wer ihn kennt, kann ihren Stand abfragen und einen neuen Versuch oder „doch im Laden bezahlen“ auslösen. Gib ihn nicht an Dritte weiter und lass ihn nicht in Logs oder Analytics landen – anders als der Public Key ist er kein für jeden Besucher unbedenkliches Merkmal.
GET/api/v1/booking/warenkorb/zahlung/{token}#
Public Key + token im PfadGET /api/v1/booking/warenkorb/zahlung/{token} X-RC-Public-Key: pk_live_…
{
"status": "paid",
"token": "…",
"total_cents": 15900,
"orders": [{"number": "RT-…", "tracking_url": "…"}],
"checkout_url": null
}Fragt bei status=open selbst den Stand bei Mollie nach, bevor sie antwortet – deine Rückkehrseite kann also direkt fragen, ohne auf den Mollie-Webhook zu warten.
POST/api/v1/booking/warenkorb/zahlung/{token}/erneut#
Public Key + token im PfadPOST /api/v1/booking/warenkorb/zahlung/{token}/erneut X-RC-Public-Key: pk_live_…
{
"status": "open",
"token": "…",
"checkout_url": "https://www.mollie.com/checkout/…",
"total_cents": 15900
}Nur möglich, solange die Zahlung failed, canceled oder expired ist (sonst 409 {"grund":"zahlung_status","status":"…"}); eine noch bei Mollie offene alte Zahlung wird dabei bestmöglich abgebrochen und durch eine neue ersetzt. Ist ein zweiter Aufruf derselben Sitzung noch nicht fertig, kommt 409 {"grund":"zahlung_laeuft","checkout_url":null}.
POST/api/v1/booking/warenkorb/zahlung/{token}/im-laden#
Public Key + token im PfadPOST /api/v1/booking/warenkorb/zahlung/{token}/im-laden X-RC-Public-Key: pk_live_…
{
"status": "confirmed",
"orders": [{"number": "RT-…", "tracking_url": "…"}]
}Wechselt von online zu „doch im Laden bezahlen“ und legt die Aufträge sofort an – nur wenn der Betrieb das erlaubt (zahlung.im_laden aus /config), sonst 422 {"grund":"zahlung"}. Ist eine andere Zahlung derselben Sitzung noch offen oder schon bezahlt (oder ein zweiter Aufruf noch nicht fertig), kommt 409 {"grund":"zahlung_laeuft","checkout_url":null} – „im Laden“ würde sonst parallel zu einer laufenden oder bezahlten Zahlung einen Auftrag anlegen.
Vertrag widerrufen (§ 356a BGB)#
POST /api/v1/booking/widerruf X-RC-Public-Key: pk_live_… { "name": "…", "email": "…", "number": "RT-629470", "nachricht": "…", "started_at": 1759160000, "website": "", "turnstile_token": "" }
Wie bei Abschnitt 7 gehören started_at (Pflicht), das leere versteckte Feld website und – wenn der Betrieb es verlangt – turnstile_token dazu.
Die Antwort ist immer 202 {"status":"eingegangen","eingang":"…"} – unabhängig davon, ob Name, E-Mail und Auftragsnummer zueinander passen. So lässt sich von außen nicht ablesen, ob es den Auftrag überhaupt gibt. Passt der Kontakt und läuft die Frist noch, wird der Vertrag widerrufen und die Werkstatt informiert; passt er nicht (falsche Nummer, andere Adresse), bekommt die Werkstatt trotzdem eine Mail mit den eingegebenen Angaben, damit eine falsch getippte Nummer nicht spurlos verloren geht. 429 nach 5 Anfragen pro Minute je Anschluss, 60 pro Stunde je Schlüssel oder 5 pro Stunde je E-Mail-Adresse (wie beim Kundenkonto-Link).
7. Anfrage stellen („Frage stellen“)#
Ersetzt das klassische Kontaktformular der Website: statt einer E-Mail landet die Anfrage im Posteingang „Anfragen“ des Cockpits. Nur verfügbar, wenn der Betrieb den Schalter „Anfragen“ eingeschaltet hat (GET /config meldet das über anfragen und entry_points.anfrage) – sonst antwortet der Endpunkt mit 404.
POST /api/v1/booking/anfrage X-RC-Public-Key: pk_live_… { "vorname": "Erika", "nachname": "Muster", "email": "erika@example.test", "telefon": "", "geraet": "Fairphone 5", "nachricht": "Display nach Sturz gesprungen und lässt sich nicht mehr einschalten.", "fotos": ["data:image/jpeg;base64,/9j/4AAQ…"], "consent": {"privacy": true}, "started_at": 1759160000, "website": "", "turnstile_token": "" }
Regeln für die Felder#
| Feld | Regel |
|---|---|
vorname, nachname | 1–120 Zeichen |
email | Pflicht |
telefon | höchstens 40 Zeichen |
geraet | höchstens 160 Zeichen |
nachricht | 10–2.000 Zeichen |
consent.privacy | muss angenommen sein |
fotos | optional, höchstens 3 Einträge – jeder eine Datenadresse data:image/jpeg|png;base64,…, dekodiert höchstens 3 MB; der Server prüft den Bildtyp, verkleinert auf höchstens 1.600 px Kante und schreibt sie als JPEG neu (dabei fallen EXIF- und Standortdaten weg). Eine ungültige Datei antwortet 422 am betroffenen Index (fotos.0, …). |
Bot-Schutz wie beim Warenkorb: ein leeres verstecktes Feld (website), eine Mindestzeit zum Ausfüllen (started_at) und – wenn der Betrieb es verlangt – ein Cloudflare-Turnstile-Token. Erfüllt die Anfrage eine der drei Prüfungen nicht, kommt 422 {"grund":"sicherheit"}.
{"nummer": "A-2026-0001"}Die Nummer läuft fortlaufend je Kalenderjahr. Der Kunde bekommt sofort eine Bestätigungsmail mit einem Link zur eigenen, öffentlichen Kundenseite (https://app.repaircockpit.de/anfrage/{token} – Verlauf, Fotos, ein Antwortfeld, ohne Konto), die Werkstatt eine Mail an ihre Kontaktadresse. 429 nach 5 Anfragen pro Minute je Anschluss, 60 pro Stunde je Schlüssel oder 5 in 10 Minuten je E-Mail-Adresse.
Anfragen werden 90 Tage nach der letzten Aktivität automatisch endgültig gelöscht, samt Fotos und Verlauf (Datenschutz) – auch solche, aus denen ein Auftrag geworden ist.
8. „Reparatur verfolgen“ – Link zu einem Auftrag#
Der Kunde nennt die Auftragsnummer und dazu die E-Mail-Adresse oder Telefonnummer, die im Auftrag steht – die Antwort enthält sofort den Link ins Kundenportal, ohne Mail dazwischen. Die Nummer allein genügt nicht, denn sie steht auf jedem Zettel am Tresen.
GET /api/v1/booking/track?number=RT-629470&contact=erika@example.de X-RC-Public-Key: pk_live_…
{
"ticket_number": "RT-629470",
"tracking_url": "https://app.repaircockpit.de/kunde/NPhq…?auftrag=…&expires=…&signature=…"
}numberundcontactsind beide Pflicht.contactist die E-Mail-Adresse (Groß-/Kleinschreibung egal) oder die Telefonnummer (nur die Ziffern zählen, mindestens sechs; „+49 170 …“ und „0170 …“ sind dieselbe Nummer).- Bei jedem Fehlschlag antwortet die Schnittstelle mit
404– auch wenn die Nummer existiert und nur der Kontakt nicht passt. So lässt sich über deine Website nicht herausfinden, welche Auftragsnummern es gibt. - Der Link ist signiert und 7 Tage gültig, auch wenn das Portal des Kunden inzwischen abgelaufen ist.
- Nur
X-RC-Public-Keynötig – darf aus dem Browser kommen.429nach 30 Anfragen pro Minute je Adresse (wie bei der Preisabfrage); erst ab Tarif „Laden“ (sonst403).
Fehler#
Antworten kommen immer als JSON, sofern du Accept: application/json mitschickst – bitte immer setzen, sonst antwortet der Server bei Eingabefehlern mit einer Weiterleitung statt mit einer Fehlermeldung.
| Code | Bedeutung | Was tun |
|---|---|---|
401 | Shop-Token fehlt oder falsch | Token prüfen (nur bei schreibenden Wegen nötig) |
403 | Tarif des Betriebs enthält den Weg nicht (Wege unter /api/v1/booking/… gibt es erst ab „Laden“) | Tarif des Betriebs prüfen |
404 | Public Key unbekannt oder Bestellung nicht gefunden | Schlüssel prüfen |
422 | Eingabe unvollständig | Feldfehler stehen in errors |
423 | Zugang gesperrt (z. B. offene Rechnung) | Betrieb informieren |
429 | Zu viele Anfragen | Kurz warten und erneut versuchen |
Weitere Codes stehen direkt bei den Endpunkten: 409 (Preis, Termin oder Zahlungsstand haben sich geändert, oder eine andere Zahlung läuft noch) und 502 (Mollie lehnt ab).
Beispiel: WooCommerce anbinden#
Sobald WooCommerce eine Zahlung meldet, legt dieser Haken die Bestellung als Auftrag an (Abschnitt 2).
// In functions.php oder einem kleinen Plugin. add_action('woocommerce_payment_complete', function (int $order_id): void { $order = wc_get_order($order_id); $items = []; foreach ($order->get_items() as $item) { $items[] = [ // Lege beim Anlegen des Produkts die Modell-Id als Meta ab. 'device_model_id' => $item->get_product()->get_meta('rc_model_id') ?: null, 'repair' => $item->get_name(), 'price_cents' => (int) round($item->get_total() * 100), ]; } wp_remote_post('https://app.repaircockpit.de/api/v1/orders', [ 'headers' => [ 'X-RC-Public-Key' => get_option('rcc_public_key'), 'Authorization' => 'Bearer ' . get_option('rcc_shop_secret'), 'Content-Type' => 'application/json', 'Accept' => 'application/json', ], 'body' => wp_json_encode([ 'reference' => 'WC-' . $order->get_order_number(), 'customer' => [ 'first_name' => $order->get_billing_first_name(), 'last_name' => $order->get_billing_last_name(), 'email' => $order->get_billing_email(), 'phone' => $order->get_billing_phone(), ], 'items' => $items, 'note' => $order->get_customer_note(), ]), 'timeout' => 20, ]); });
Grenzen#
- Lesende Wege: 30 Anfragen pro Minute je Adresse, dazu 300 pro Minute je Schlüssel.
- Schreibende Wege: 5 pro Minute je Adresse, 60 pro Stunde je Schlüssel.
- Checkout (Abschnitt 4): 120 Anfragen pro Minute je Schlüssel, lesend wie schreibend – statt der Grenzen oben.
- Kundenkonto-Link: 5 pro Minute je Adresse, 5 pro Stunde je E-Mail-Adresse; wie „Reparatur verfolgen“ erst ab Tarif „Laden“ (sonst
403). - Die Wege unter
/api/v1/booking/…gibt es erst ab Tarif „Laden“ (sonst403) – nur der Widerruf (Abschnitt 6) bleibt in jedem Tarif erreichbar. - Höchstens 20 Positionen je Bestellung (
POST /api/v1/orders); im Checkout und im Warenkorb höchstens 5 Geräte, je Gerät höchstens 12 Reparaturen.
Schlüssel holen und loslegen.
Die Schlüssel stehen ab dem ersten Tag in deinen Einstellungen – auch während der Testphase.