Zum Inhalt springen
RepairCockpit

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.

Basis-Adresse
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).

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üsselWofürGeheim?
Public Key
pk_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-Token
sk_…
Erlaubt das Anlegen von Aufträgen. Als Authorization: Bearer ….Ja. Nur auf deinem Server, nie im Browser.

1. Reparaturen abrufen#

GET/api/v1/repairsPublic Key

Liefert eine Zeile je Modell und Reparatur – genau das, was du für eine eigene Seite brauchst.

Anfrage
GET /api/v1/repairs?type=phone&brand=Apple&page=1&limit=200
X-RC-Public-Key: pk_live_…
Antwort
{
  "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_cents ist brutto und trägt bereits die Preisendung deines Betriebs (z. B. …9,00 €). Du musst nichts umrechnen – nur formatieren.
  • slug ist als Adresse deiner Seite gedacht: /reparatur/apple-iphone-16e-display-tausch.
  • model_numbers sind die aufgedruckten Nummern (z. B. A3212) – hervorragend für die Suche und als Text auf der Seite, weil danach gesucht wird.
ParameterWirkung
typeFilter: phone, tablet, laptop, smartwatch, console, desktop, escooter
brandFilter nach Marke, z. B. Apple
page + limitSeiten; limit höchstens 500

Dein Gerätekatalog zum Durchblättern#

Für eine Auswahl in Schritten gibt es zusätzlich:

WegLiefert
GET /api/v1/booking/catalogGerätetypen und Marken mit Anzahl (klein, ~2 KB)
GET /api/v1/booking/catalog/models?type=phone&brand=AppleModelle einer Marke mit Bild, Farben, Preisen
GET /api/v1/booking/catalog/search?q=A3293Suche nach Name, Marke oder Modellnummer

2. Bezahlte Bestellung anlegen#

POST/api/v1/ordersPublic Key + Shop-Token

Ruf das auf, nachdem die Zahlung eingegangen ist (bei WooCommerce z. B. im Haken woocommerce_payment_complete).

Anfrage
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."
}
Antwort · 201
{
  "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_id kannst du auch device_label schicken (z. B. "Apple iPhone 16e"), wenn das Gerät nicht aus unserem Katalog stammt.
  • tracking_url kannst 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:

WertBedeutung
vorbeibringenDer Kunde bringt das Gerät in den Laden. Vorgabe, wenn du das Feld weglässt.
einsendungDer 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/{reference}Public Key + Shop-Token
Anfrage
GET /api/v1/orders/WC-10423
X-RC-Public-Key: pk_live_…
Authorization: Bearer sk_…
Antwort
{
  "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 Key
Anfrage
POST /api/v1/checkout/quote
X-RC-Public-Key: pk_live_…

{
  "items": [
    { "device_model_id": "…", "offers": ["Displaytausch", "Akkutausch"] }
  ]
}
Antwort
{
  "total_cents": 33800,
  "discount_cents": 2000,
  "combo_discount_percent": 20,
  "payment": {"mollie": true, "vor_ort": true},
  "items": […]
}

POST/api/v1/checkout#

Public Key + Shop-Token
Anfrage
POST /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 zur checkout_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 → 422 payment; 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
ananmollie und vor_ort – der Kunde wählt
anausnur 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-Token
Anfrage
GET /api/v1/checkout/{token}
X-RC-Public-Key: pk_live_…
Authorization: Bearer sk_…
Antwort
{
  "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/linkPublic Key – auch aus dem Browser
Anfrage
POST /api/v1/booking/kundenkonto/link
X-RC-Public-Key: pk_live_…
Content-Type: application/json
Accept: application/json

{"email": "erika@example.de"}
Antwort · 202
{"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.
  • 422 bei fehlender oder ungültiger Adresse (errors.email), 429 nach 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 Key

GET /api/v1/booking/config liefert seit dem Widget-Shop zusätzlich:

Antwort (zusätzliche Felder)
{
  "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/warenkorbPublic Key
Anfrage
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_cents ist 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 zu checkout_url; nach der Zahlung hängt Mollie ?rc_zahlung=<token> an deine return_url an.
  • expected_total_cents ist bei online Pflicht und muss zum Server-Preis passen, sonst 409 {"grund":"preis_geaendert","total_cents":…}. return_url muss eine im Cockpit erlaubte Domain sein, und vorzeitig: true ist die ausdrückliche Zustimmung zur vorzeitigen Ausführung (§ 312j Abs. 3 BGB) – fehlt eines davon oder ist online gerade nicht möglich, kommt 422 {"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_url ist die Bezahlseite der noch offenen Zahlung – oder null, wenn gerade ein zweiter Aufruf derselben Sitzung läuft.
  • Schickt dieselbe Sitzung /warenkorb ein zweites Mal, während die vorherige Vorkasse desselben Vorgangs schon bezahlt ist (Doppelklick, zweiter Tab), antwortet der Server mit 200 und der vollen Stand-Form wie bei GET .../warenkorb/zahlung/{token} (checkout_url dann null) – nicht mit der schlanken {"status":"open",...}-Form von oben. Prüf status in 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:

Zusätzliche 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 bei POST /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_cents und der Zahlweg (zahlung) beziehen sich nur auf die Geräte MIT Festpreis – bleiben nach dem Abtrennen keine übrig, ist zahlung ü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 Pfad
Anfrage
GET /api/v1/booking/warenkorb/zahlung/{token}
X-RC-Public-Key: pk_live_…
Antwort
{
  "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 Pfad
Anfrage
POST /api/v1/booking/warenkorb/zahlung/{token}/erneut
X-RC-Public-Key: pk_live_…
Antwort · 200
{
  "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 Pfad
Anfrage
POST /api/v1/booking/warenkorb/zahlung/{token}/im-laden
X-RC-Public-Key: pk_live_…
Antwort · 201
{
  "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/widerrufPublic Key
Anfrage
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/anfragePublic Key
Anfrage
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#

FeldRegel
vorname, nachname1–120 Zeichen
emailPflicht
telefonhöchstens 40 Zeichen
geraethöchstens 160 Zeichen
nachricht10–2.000 Zeichen
consent.privacymuss angenommen sein
fotosoptional, 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"}.

Antwort · 201
{"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/trackPublic Key
Anfrage
GET /api/v1/booking/track?number=RT-629470&contact=erika@example.de
X-RC-Public-Key: pk_live_…
Antwort
{
  "ticket_number": "RT-629470",
  "tracking_url": "https://app.repaircockpit.de/kunde/NPhq…?auftrag=…&expires=…&signature=…"
}
  • number und contact sind beide Pflicht. contact ist 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-Key nötig – darf aus dem Browser kommen. 429 nach 30 Anfragen pro Minute je Adresse (wie bei der Preisabfrage); erst ab Tarif „Laden“ (sonst 403).

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.

CodeBedeutungWas tun
401Shop-Token fehlt oder falschToken prüfen (nur bei schreibenden Wegen nötig)
403Tarif des Betriebs enthält den Weg nicht (Wege unter /api/v1/booking/… gibt es erst ab „Laden“)Tarif des Betriebs prüfen
404Public Key unbekannt oder Bestellung nicht gefundenSchlüssel prüfen
422Eingabe unvollständigFeldfehler stehen in errors
423Zugang gesperrt (z. B. offene Rechnung)Betrieb informieren
429Zu viele AnfragenKurz 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).

PHP
// 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“ (sonst 403) – 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.

30 Tage kostenlos testenZurück zu Entwickler