OrderKit-Schnittstelle — Doku für externe Systeme
Was ein externer MCP-Server an uns senden muss, damit Öffnungszeiten, Sondertage und Vorlaufzeiten im Shop-Ordering ankommen.
1. Grundlagen
Gilt für alle Endpunkte.
- Basis-URL:
https://ki-speisekarte.de/functions - Format: JSON,
Content-Type: application/json. Schreiben immer per POST. - Ein Token = ein Betrieb. Es gibt keine Betriebs-ID im Body — der Betrieb wird ausschließlich über den Token bestimmt.
- Token-Übergabe (eine Variante genügt): Header
x-api-key: <TOKEN>, Query?token=<TOKEN>oder Feld"token"im Body. Empfohlen: Header. - Voraussetzung: Der Betrieb muss die Anbindung in Simplefy freigeschaltet haben. Sonst:
403mitcode: "ORDERKIT_DISABLED". - Simplefy ist die führende Quelle. Der externe Dienst liest die komplette Konfiguration und schreibt nur gezielt einzelne Bereiche zurück.
- Zeiten immer als
"HH:MM"(24 h), Datum immer als"YYYY-MM-DD", jeweils in der Zeitzone des Shops (Feldtimezone, i.d.R.Europe/Berlin). - Wochentage: Schlüssel
"0"–"6", wobei0 = Sonntag…6 = Samstag. - CORS ist offen;
OPTIONSwird beantwortet.
2. Pflicht-Ablauf: erst lesen, dann schreiben
Ohne diesen Ablauf entstehen Überschreibungen und Endlos-Schleifen.
orderKitConfigaufrufen und die Antwort komplett übernehmen (kein Mergen mit altem eigenem Stand).- Die gelesene
config_versionmerken. - Beim Schreiben diese
config_versionmitsenden. - Kommt
409mitcode: "VERSION_CONFLICT", ist der eigene Stand veraltet: die im Fehler mitgelieferteconfigübernehmen und den Schreibvorgang mit der neuen Version wiederholen.
Wichtig: Alle Schreib-Endpunkte akzeptieren config_version optional — wird sie weggelassen, entfällt der Schutz gegen versehentliches Überschreiben. Bitte immer mitsenden.
3. Lesen — komplette Konfiguration
Der Einstiegspunkt für jeden Abgleich.
https://ki-speisekarte.de/functions/orderKitConfig?token=<TOKEN>Liefert alles: Zeitzone, allgemeine Öffnungszeiten, Liefer-/Abholzeiten, Vorlaufzeiten (global und je Kategorie), Sondertage sowie die Tagessperre. Alternativ als POST mit { "token": "..." } im Body.
Antwort
{
"config_version": "2026-08-18T09:41:02.113Z",
"restaurant": { "id": "abc123", "name": "Gasthaus Beispiel", "business_type": "restaurant" },
"timezone": "Europe/Berlin",
"accepting_orders": true,
"channels": { "delivery_offered": true, "pickup_offered": false },
"blocked_today": { "delivery": false, "pickup": false },
"business_hours": { "0": [], "1": [{ "from": "11:00", "to": "22:00" }] },
"delivery_hours": { "1": [{ "from": "17:00", "to": "21:00" }] },
"pickup_hours": { "1": [{ "from": "11:30", "to": "21:00" }] },
"max_days_ahead": 3,
"default_order_type": "delivery",
"lead_times": {
"delivery_lead_time_days": 0,
"delivery_lead_time_hours": 0,
"delivery_lead_time_minutes": 45,
"delivery_earliest_time": "",
"delivery_lead_time_mode": "calendar_days",
"pickup_lead_time_days": 0,
"pickup_lead_time_hours": 0,
"pickup_lead_time_minutes": 30,
"pickup_earliest_time": "",
"pickup_lead_time_mode": "open_days_only"
},
"categories": [
{ "id": "cat_1", "name": "Partyservice",
"delivery_lead_time_days": 2, "delivery_lead_time_hours": 0,
"delivery_lead_time_minutes": 0, "delivery_earliest_time": "10:00",
"pickup_lead_time_days": 2, "pickup_lead_time_hours": 0,
"pickup_lead_time_minutes": 0, "pickup_earliest_time": "10:00" }
],
"kartenarten": [
{ "id": "card_1", "name": "Partyplatte",
"category_ids": ["cat_1", "cat_7"] }
],
"special_days": [ /* alle Sondertage */ ],
"closures": [ /* nur is_closed = true */ ],
"lead_time_exceptions": [ /* nur is_closed = false */ ]
}categories enthält nur aktive Kategorien. Kategorien können über diese Schnittstelle NICHT angelegt oder gelöscht werden — nur deren Vorlaufzeiten geändert. channels sagt, welche Bestellarten der Betrieb überhaupt anbietet: steht delivery_offered oder pickup_offered auf false, darf für diese Bestellart NICHTS angeboten werden — Bestellungen darüber werden mit 403 und code: CHANNEL_OFF abgelehnt. channels ist nur lesbar und wird ausschließlich in Simplefy umgestellt. kartenarten listet die aktiven Kartenarten (z.B. 'Partyplatte') mit den Kategorien, die über ihre Artikel dazugehören — abgeleitet aus der Kartenzuordnung der Artikel (Hauptkategorie; die Zweitkategorie zählt bewusst nicht mit, da nur die Hauptkategorie die Vorlaufzeit- und Sondertag-Logik steuert). Damit lässt sich beim Schreiben eines Sondertags die passende category_ids-Liste füllen. Nur lesbar.
4. Schreiben — Sonderöffnungszeiten / Schließtage
Feiertage, Betriebsurlaub, abweichende Zeitfenster, abweichende Vorlaufzeiten.
https://ki-speisekarte.de/functions/orderKitSetSpecialDaysLegt Sondertage an, ändert sie oder löscht sie. Eintrag MIT id = ändern, OHNE id = neu anlegen. Es werden nur die übergebenen Einträge angefasst — die Liste ist kein Vollersatz.
Request Body
{
"token": "<TOKEN>",
"config_version": "2026-08-18T09:41:02.113Z",
"special_days": [
{
"date": "2026-12-24",
"date_to": "",
"label": "Heiligabend",
"applies_to": "both",
"category_ids": [],
"is_closed": false,
"windows": [{ "from": "09:00", "to": "13:00" }],
"lead_time_days": 2,
"lead_time_hours": 0
},
{
"id": "sd_9f2",
"date": "2026-12-27",
"date_to": "2027-01-04",
"label": "Betriebsurlaub",
"applies_to": "both",
"is_closed": true,
"windows": []
}
],
"delete_ids": ["sd_alt1"]
}Antwort
{
"success": true,
"created": 1, "updated": 1, "deleted": 1,
"config_version": "2026-08-18T11:02:44.907Z",
"special_days": [ ... ], "closures": [ ... ], "lead_time_exceptions": [ ... ]
}Feldregeln: date = Pflicht (YYYY-MM-DD). date_to leer = einzelner Tag, sonst Zeitraum und darf nicht vor date liegen. applies_to = both | delivery | pickup (Standard both). category_ids leer = gilt für alle Kategorien, sonst müssen es bestehende Kategorie-IDs aus orderKitConfig sein. is_closed true = an diesen Tagen keine Bestellung möglich. windows = abweichende Zeitfenster (leer = normale Wochentagszeiten gelten), to muss größer als from sein. lead_time_days / lead_time_hours = abweichende Vorlaufzeit für diese Tage (0 = keine Abweichung). Statt special_days können auch die getrennten Listen closures (immer is_closed=true) und lead_time_exceptions (immer is_closed=false) gesendet werden.
Es wird zuerst alles geprüft und erst dann geschrieben — bei einem Fehler (400) bleibt der Bestand unverändert. Unbekannte IDs melden sich als code: "UNKNOWN_SPECIAL_DAY", unbekannte Kategorien als Klartext-Fehler.
5. Schreiben — Liefer- und Abholzeiten
Wochenplan, Vorausbestell-Fenster, Standard-Bestellart.
https://ki-speisekarte.de/functions/orderKitSetHoursErsetzt die übergebenen Wochenpläne vollständig. Nur mitgesendete Felder werden geändert.
Request Body
{
"token": "<TOKEN>",
"config_version": "2026-08-18T09:41:02.113Z",
"business_hours": { "1": [{ "from": "11:00", "to": "22:00" }], "0": [] },
"delivery_hours": { "1": [{ "from": "17:00", "to": "21:00" }] },
"pickup_hours": { "1": [{ "from": "11:30", "to": "21:00" }] },
"max_days_ahead": 3,
"default_order_type": "delivery"
}Antwort
{ "success": true, "config_version": "…", "config": { /* komplette neue Konfiguration */ } }Ein Wochentag mit leerem Array = geschlossen. Ein NICHT übergebener Wochentag gilt ebenfalls als geschlossen — deshalb immer den vollständigen Wochenplan senden. max_days_ahead: 0–365. default_order_type: delivery | pickup.
6. Schreiben — Vorlaufzeiten
Global für den Shop und je Kategorie.
https://ki-speisekarte.de/functions/orderKitSetLeadTimesAllgemeine Vorlaufzeit des Shops. Nur übergebene Felder werden geändert.
Request Body
{
"token": "<TOKEN>",
"config_version": "…",
"delivery_lead_time_days": 0,
"delivery_lead_time_hours": 1,
"delivery_lead_time_minutes": 30,
"delivery_earliest_time": "",
"delivery_lead_time_mode": "calendar_days",
"pickup_lead_time_days": 2,
"pickup_lead_time_hours": 0,
"pickup_lead_time_minutes": 30,
"pickup_earliest_time": "11:30",
"pickup_lead_time_mode": "open_days_only"
}Antwort
{ "success": true, "config_version": "…", "lead_times": { ... } }*_lead_time_mode ist nur hier (am Betrieb) erlaubt, NICHT je Kategorie. Zulässig sind ausschließlich calendar_days und open_days_only — jeder andere Wert führt zu 400.
https://ki-speisekarte.de/functions/orderKitSetCategoryLeadTimesVorlaufzeiten einzelner Kategorien (z.B. Partyservice ab 2 Tagen). Nur bestehende Kategorie-IDs aus orderKitConfig.
Request Body
{
"token": "<TOKEN>",
"config_version": "…",
"categories": [
{ "id": "cat_1",
"delivery_lead_time_days": 2, "delivery_earliest_time": "10:00",
"pickup_lead_time_days": 2, "pickup_earliest_time": "10:00" }
]
}Antwort
{ "success": true, "updated": 1, "config_version": "…", "categories": [ ... ] }Unbekannte IDs → 400 mit code: UNKNOWN_CATEGORY.
Bedeutung der Felder
*_lead_time_days = Vorlauf in KALENDERTAGEN (1 = frühestens morgen, unabhängig von der Uhrzeit)
*_lead_time_hours = zusätzlicher Vorlauf in Stunden, rollend ab Bestellzeitpunkt
*_lead_time_minutes = zusätzlicher Vorlauf in Minuten, rollend ab Bestellzeitpunkt
*_earliest_time = früheste Uhrzeit am Termintag, "HH:MM" oder "" (keine Grenze)
*_lead_time_mode = Zählweise der Vorlauf-TAGE (nur am Betrieb, nicht je Kategorie):
calendar_days = jeder Kalendertag zählt mit (Standard)
open_days_only = nur Tage mit Zeitfenstern und ohne Schließtag
zählen mit ("nur Werktage")
Alle Zahlen: ganzzahlig und >= 0.Reihenfolge der Berechnung des frühesten Termins
1. Vorlauf-TAGE anwenden — Zählweise gemäß *_lead_time_mode.
Bei open_days_only werden geschlossene Tage (kein Zeitfenster ODER Schließtag
aus closures) übersprungen und zählen nicht als Vorlauftag.
2. Vorlauf STUNDEN + MINUTEN rollend ab Bestellzeitpunkt addieren
(davon ist *_lead_time_mode NICHT betroffen).
3. Kategorie-Vorlaufzeiten: pro Artikel gilt die HAUPTKATEGORIE; bei gemischtem
Warenkorb gewinnt die längste Vorlaufzeit. Zweitkategorien zählen nicht.
4. Abweichende Vorlaufzeiten aus lead_time_exceptions für den Zieltag anwenden.
5. *_earliest_time als untere Grenze der Uhrzeit am Termintag anwenden.
6. Termin muss in ein Zeitfenster (delivery_hours / pickup_hours bzw. windows
eines Sondertags) fallen und darf max_days_ahead nicht überschreiten.6b. Bestellarten — „nur Lieferung“ / „nur Abholung“
Nur lesbar. Wird ausschließlich in Simplefy umgestellt.
Feld in orderKitConfig
"channels": { "delivery_offered": true, "pickup_offered": false }- Steht ein Kanal auf
false, darf diese Bestellart dem Kunden gar nicht angeboten werden — keine Zeiten, keine Termine, keine Bestellung. - Wird trotzdem eine Bestellung dieser Art gesendet, wird sie abgelehnt:
403mitcode: "CHANNEL_OFF". - Mindestens einer der beiden Kanäle ist immer aktiv.
- Über die Schnittstelle nicht schreibbar — es gibt bewusst keinen Endpunkt dafür.
- Zusätzlich beachten:
accepting_orders: falsestoppt alle Bestellungen,blocked_todaynur den heutigen Tag (je Kanal).
7. Schreiben — Tagessperre („heute zu“)
Für Krankheit, Küche voll, spontane Pause.
https://ki-speisekarte.de/functions/orderKitBlockTodaySperrt den heutigen Tag. Gilt nur für heute (Zeitzone des Shops) und endet automatisch um Mitternacht — es muss nichts zurückgesetzt werden.
Request Body
{ "token": "<TOKEN>", "scope": "all", "blocked": true }Antwort
{ "success": true, "date": "2026-08-18", "blocked_today": { "delivery": true, "pickup": true } }scope: all | delivery | pickup. blocked: false hebt die Sperre auf. Dieser Endpunkt braucht keine config_version.
8. Antworten & Fehlerbehandlung
Was der externe Dienst auswerten muss.
Statuscodes
200 Erfolg — Antwort enthält success: true und die neue config_version
400 Ungültige Daten — "error" enthält den Klartext-Grund, ggf. "code"
(UNKNOWN_SPECIAL_DAY, UNKNOWN_CATEGORY). Es wurde NICHTS geschrieben.
401 Token fehlt
403 Token ungültig ODER Anbindung deaktiviert (code: ORDERKIT_DISABLED)
ODER Bestellart nicht angeboten (code: CHANNEL_OFF, siehe channels)
405 Falsche Methode (Schreiben nur per POST)
409 code: VERSION_CONFLICT — eigener Stand veraltet, "config" übernehmen und erneut senden
500 Serverfehler — später erneut versuchen- Nach jedem erfolgreichen Schreiben die zurückgegebene
config_versionals neuen eigenen Stand speichern. - Bei
409nicht blind erneut senden, sondern zuerst die mitgelieferteconfigübernehmen. - Bei
400nicht wiederholen — die Daten sind fehlerhaft; die Meldung inerrorist für Menschen lesbar. - Bei
500/ Netzfehler mit Abstand erneut versuchen (z.B. 5 s, 30 s, 2 min). - Keine Schreib-Schleifen: nur schreiben, wenn sich fachlich etwas geändert hat — nicht periodisch denselben Stand zurückschreiben.
9. Kurz-Checkliste für die Umsetzung
- Token pro Betrieb sicher hinterlegt (nicht im Client, nur serverseitig).
orderKitConfiggelesen,config_versiongespeichert.channelsausgewertet: nicht angebotene Bestellarten werden dem Kunden gar nicht erst angeboten.*_lead_time_modeausgewertet: beiopen_days_onlywerden geschlossene Tage bei den Vorlauftagen übersprungen.accepting_ordersundblocked_todayvor jedem Bestellangebot geprüft.- Beim Schreiben: nur den betroffenen Endpunkt, mit
config_version. - Wochenpläne immer vollständig senden, Sondertage nur als Delta (mit
idzum Ändern,delete_idszum Löschen). 409-Behandlung implementiert;400-Meldungen werden protokolliert und nicht wiederholt.