Maschinell übersetzt. Polnisch ist die kanonische Fassung.

Partner-API

HTTP /api/v1 — Menü, Shop-Konfiguration, Kasse, Zeitfenster, Reservierungen, Anfragen, Catering, ETA-Angebot und Bestellungen. Eine API-Beschreibung, abgestimmt mit OpenAPI 3.1.

Die Partner-API v1 ist die HTTP-Schnittstelle unter https://delieta.pl/api/v1. Der API-Schlüssel, den Delieta einer Firma ausgestellt hat, bezeichnet diese Firma: Keine Anfrage hat ein Firmenfeld. Das ist die einzige Beschreibung für Menschen; die Beschreibung für Maschinen ist GET /api/v1/openapi (OpenAPI 3.1, ohne Schlüssel).

Veröffentlichte Operationen: GET /menu, GET /shop-config, POST /shop-heartbeat, GET /checkout/slots, POST /checkout, POST /checkout/quote, GET /checkout/result, GET /events, POST /quotes, POST /orders, GET /orders/{id}, GET /orders/{id}/status, GET /floor-plan, GET /reservations/availability, POST /reservations, POST /inquiries, POST /catering-orders, GET /catering-orders und GET /catalog-images/{id}/{filename}.

flowchart LR
  bearer["Klucz API"] --> verify["Klucz jest firma"]
  verify --> scope{"scope"}
  scope -->|"catalog:read"| menu["GET /menu"]
  scope -->|"checkout:create"| checkout["POST /checkout"]
  scope -->|"orders:write"| handoff["POST /orders"]
  handoff --> same["to samo zamowienie co panel"]

Schlüssel und Scopes

Zwei gleichwertige Header. Der zuerst gefundene gilt; ein Schlüssel im Query-String wird nie akzeptiert.

Authorization: Bearer dlt_live_…
x-delieta-api-key: dlt_live_…

Reihenfolge der Prüfungen: Schlüssel → Scope → Testschlüssel (nur bei Schreibzugriff) → Limit. Fehlender oder falscher Schlüssel → 401 unauthorized.

ScopeSchlüsselartOperationen
catalog:readveröffentlichbarGET /api/v1/menu, GET /api/v1/shop-config, GET /api/v1/checkout/slots, GET /api/v1/events, GET /api/v1/orders/{id}/status, GET /api/v1/floor-plan, GET /api/v1/reservations/availability und POST /api/v1/shop-heartbeat. menu:read ist ein Alias für ältere Schlüssel.
checkout:createveröffentlichbarPOST /api/v1/checkout, POST /api/v1/checkout/quote, GET /api/v1/checkout/result, POST /api/v1/inquiries und POST /api/v1/reservations (eine web-Buchung).
eta:quotegeheimPOST /api/v1/quotes
orders:writegeheimPOST /api/v1/orders und GET /api/v1/orders/{id}
reservations:writegeheimPOST /api/v1/reservations aus dem eigenen System der Firma (eine api-Buchung)
catering:writegeheimPOST /api/v1/catering-orders und GET /api/v1/catering-orders

Ein veröffentlichbarer Schlüssel ist genau catalog:read + checkout:create und nichts weiter: Ihn hält der Shop, und der Shop bewahrt ihn serverseitig auf, nie im Browser. Ein veröffentlichbarer Schlüssel kann nicht orders:write, eta:quote, reservations:write oder catering:write bekommen. Eine leere Scope-Liste öffnet nichts — 403 scope_required. Eine Reservierung zählt den Scope nach Schlüsselart: veröffentlichbar braucht checkout:create, geheim reservations:write.

dlt_test_… liest die echten Produkte der Firma und berechnet Angebote. Jeder Schreibzugriff wird mit 403 test_key_readonly abgelehnt: POST /api/v1/checkout, /orders, /reservations, /inquiries, /catering-orders und /shop-heartbeat. Es gibt keinen separaten Testdatensatz.

Limits

Limits gelten pro Schlüssel in einem 60-s-Fenster. Standard: 60 Schreibzugriffe und 600 Lesezugriffe pro Minute, getrennt gezählt, damit häufiges Abfragen nicht das Schreiblimit verbraucht. Schreibzugriffe sind Bestellung anlegen, Kasse, Reservierung, Anfrage, Catering-Auftrag und Angebot. Lesezugriffe sind alles andere. Bei Überschreitung: 429 rate_limited; beachten Sie Retry-After und RateLimit-Limit / RateLimit-Remaining / RateLimit-Reset.

Einen veröffentlichbaren Schlüssel nutzen viele Besucher, daher zählt sein Limit pro Besucher. Senden Sie die Adresse des Gastes im Header x-delieta-visitor; ohne ihn zählt der Origin. Zusätzlich gilt eine gemeinsame Obergrenze vom 20-Fachen des Limits. Ein geheimer Schlüssel ignoriert diesen Header.

Fehler

Jede Ablehnung der v1 ist application/problem+json (RFC 9457). Erkennen Sie den Fehler an code, nicht am Text.

{
  "type": "https://delieta.pl/problems/unauthorized",
  "title": "Unauthorized",
  "status": 401,
  "code": "unauthorized",
  "detail": "Provide a valid API key as `Authorization: Bearer dlt_live_…`."
}

Ausnahme: GET /api/v1/catalog-images/{id}/{filename} antwortet bei Überschreitung des Limits mit einem einfachen { "error": "rate_limited" } und 429, nicht mit problem+json.

codestatuswann
unauthorized401fehlender oder falscher Schlüssel
scope_required403Schlüssel ohne den nötigen Scope
test_key_readonly403dlt_test_… versuchte einen Schreibzugriff
module_disabled403das Modul der Firma ist aus (Tarif oder Schalter des Inhabers): Bestellungen bei POST /checkout und GET /checkout/slots, Reservierungen, Catering. Der Status einer aufgegebenen Bestellung funktioniert weiter
invalid_request400Body ist kein JSON oder scheitert an der Validierung; Details in errors[] (z. B. unknown_field bei POST /orders)
idempotency_key_required400Schreibzugriff ohne Idempotency-Key (8–255 Zeichen)
line_price_missing / line_name_missing / total_out_of_range400eine Bestellzeile oder die Summe lässt sich nicht bepreisen
payload_too_large413Body einer Anfrage oder eines Catering-Auftrags über 64 KiB
not_found404keine solche Bestellung für diesen Schlüssel (eine fremde ID antwortet gleich)
tenant_not_found404die Firma des Schlüssels existiert nicht mehr
idempotency_key_conflict409gleicher Idempotenzschlüssel, anderer Body
conflict409z. B. die Anfrage ist schon mit einem anderen Auftrag verknüpft
venue_not_configured409Angebot, aber die Firma hat keine Standortkoordinaten
out_of_range409Preisangebot oder Checkout mit Lieferung: die Adresse liegt außerhalb des Liefergebiets der Firma (errors[] am Feld address). Bei einer Reservierung ist derselbe code ein 422 (Datum außerhalb des Bereichs)
delivery_unconfigured409Checkout mit Lieferung: das Lokal hat Kilometerstufen, aber keine Adresse oder keine eingestellte Lieferung. Abholung funktioniert
total_changed409Checkout: das angegebene expectedTotalGrosze stimmt nicht mit dem jetzt berechneten Betrag überein. Der Server hat es nicht zur Preisberechnung genutzt
product_outside_hours409Checkout: ein Artikel liegt zum gewählten Zeitpunkt außerhalb seiner Verfügbarkeitszeiten; Zeilen in errors[] an items.N.itemId
shop_closed409der Shop ist jetzt geschlossen und nimmt keine Bestellung „so schnell wie möglich“ an
shop_unconfigured409kein gespeicherter Shop-Origin für die Rücksprungadressen der Zahlung
connect_not_ready409das Konto für Online-Zahlungen kann noch keine Zahlungen annehmen
sample_mode409Online-Zahlung in einem Shop mit Beispieldaten, während Zahlungen live sind
slot_unavailable409requestedFor ist keiner der Zeitpunkte aus GET /checkout/slots; bei einer Reservierung: der Termin ist vergeben
table_taken409Reservierung: der Tisch ist vergeben (auch wenn jemand anders ihn kurz zuvor gebucht hat)
fulfilment_unavailable409der Shop bietet diese Übergabe nicht an (Lieferung oder Abholung)
payment_unavailable409der Shop akzeptiert diese Zahlung nicht (online oder bar)
duplicate_external_ref409dieses externalRef hat für die Firma schon eine Bestellung erzeugt
unprocessable422unbekannter oder nicht verfügbarer Artikel (errors[].code: product_unknown, product_unavailable); unbekanntes Catering-Format
below_minimum422Warenkorb unter dem Mindestbestellwert des Shops (nur Gerichte, ohne Verpackung und Lieferung; Feld items)
product_menu_only422Checkout: ein Artikel ist „Tylko w karcie“ (nur auf der Karte) und online nicht bestellbar; Zeilen in errors[] an items.N.itemId. Treffen beide Fälle zu, gewinnt dieser
address_not_found422Checkout mit Lieferung: die Adresse ließ sich nicht ermitteln (Feld address)
headcount_out_of_range422Catering-Anfrage: die Personenzahl liegt außerhalb des Bereichs des Formats (catering.headcount)
venue_not_offered422Catering-Anfrage: das Format bedient den gewählten Ort nicht (catering.venue)
unknown_add_on422Catering-Anfrage: der Zusatz gehört nicht zum gewählten Format (catering.addOns.N.key)
unknown_event, event_not_bookable, event_past, event_phone_only422Veranstaltungsanfrage: keine solche Veranstaltung, sie nimmt keine Anfragen an, sie hat schon stattgefunden oder die Anmeldung läuft nur telefonisch (event.eventId)
unknown_occurrence, event_in_past422Veranstaltungsanfrage: der Termin steht nicht in der Liste oder liegt in der Vergangenheit (event.occurrenceId, event.preferredDate)
participants_out_of_range422Veranstaltungsanfrage: die Teilnehmerzahl liegt außerhalb des Bereichs der Veranstaltung (event.participants)
option_invalid422unbekannte Option, fehlende Pflichtgruppe oder zu viele Auswahlen in einer Gruppe
validation_failed / party_too_large422Reservierung: schlechter Inhalt, Gruppe größer als der Raum fasst
rate_limited429Minutenlimit überschritten; siehe Limits
internal500ein Fehler auf unserer Seite; erneut versuchen
create_failed500POST /orders: die Bestellung ließ sich nicht speichern; mit demselben Idempotency-Key wiederholen
idempotency_unavailable503der Idempotenz-Speicher ist nicht verfügbar; mit demselben Schlüssel wiederholen
delivery_quote_unavailable503Checkout oder Preisangebot mit Lieferung: die Entfernung ließ sich gerade nicht berechnen; erneut versuchen oder Abholung wählen
module_unavailable503die Module der Firma ließen sich nicht lesen (das Modul ist nicht aus); gleich erneut versuchen (Retry-After)

Geld

Ausschließlich ganze Grosze. 3000 sind 30,00 PLN. Keine Floats, kein Währungsfeld an Beträgen. currency in den Antworten ist die Konstante "PLN".

GET /api/v1/menu

Die Produkte der Firma, zu der der Schlüssel gehört. Scope catalog:read. Nicht verfügbare Artikel sind weggelassen — im DTO gibt es kein available-Flag, das der Client behandeln müsste. Artikel „Tylko w karcie“ (nur auf der Karte, orderable: false) stehen in menuOnlyItems, nicht in items; die Verfügbarkeitszeiten stehen in availability. Die Antwort hat kein Flag „jetzt verfügbar“: Der Shop berechnet es selbst aus availability. Die Struktur ändert sich nicht, neue Felder können nur hinzukommen.

GET /api/v1/menu
Authorization: Bearer dlt_live_…
{
  "currency": "PLN",
  "generatedAt": "2026-08-26T12:00:00.000Z",
  "locale": "pl",
  "categories": [
    { "id": "c1", "slug": "pizza", "name": "Pizza", "sort": 0, "orderable": true, "availability": null }
  ],
  "items": [
    {
      "id": "i1",
      "slug": "margherita",
      "categoryId": "c1",
      "name": "Margherita",
      "description": null,
      "basePriceGrosze": 3200,
      "allergens": [],
      "modifierGroups": [],
      "imageUrl": null,
      "featured": false,
      "sort": 0,
      "orderable": true,
      "availability": null
    }
  ],
  "menuOnlyCategories": [],
  "menuOnlyItems": []
}

Ein leeres Array von Kategorien und Artikeln ist eine gültige Antwort, kein Fehler. Cache-Control: no-store. Die Antwort enthält den Header x-delieta-cache-tag; ein Shop mit eigenem Cache nutzt ihn als Schlüssel.

Das optionale ?locale= (pl, en, de, uk) liefert Namen und Beschreibungen in dieser Sprache, feldweise, und auf Polnisch, wenn eine Übersetzung fehlt. Für eine Sprache, die die Firma nicht aktiviert hat (oder eine unbekannte), bekommen Sie den Inhalt auf Polnisch; locale in der Antwort sagt, welche Sprache tatsächlich geliefert wurde. Dasselbe ?locale= lesen GET /api/v1/shop-config (Namen der Catering-Formate; liefert auch die aktivierten locales, Polnisch zuerst) und GET /api/v1/floor-plan (Zonennamen).

imageUrl ist die absolute Adresse des Gerichtfotos (die 800-px-Version) oder null, wenn das Gericht keines hat. featured: true heißt, der Inhaber hat das Gericht als „Empfohlen“ markiert.

orderable: false heißt „Tylko w karcie“ (nur auf der Karte): den Artikel mit Preis zeigen, ohne die Schaltfläche „Do koszyka“. Solche Artikel stehen nicht in items, sondern in menuOnlyItems, und eine Kategorie, in der jeder Artikel nur auf der Karte steht, steht in menuOnlyCategories, nicht in categories — ein Client, der diese Schlüssel nicht kennt, zeigt sie einfach nicht und bietet nie etwas an, das sich nicht bestellen lässt. @delieta/shop-runtime führt sie ab 1.8.0 wieder zusammen (withMenuOnly). Der Wert am Artikel berücksichtigt bereits seine Kategorie (Kategorie nur auf der Karte = jeder ihrer Artikel). availability sind die Verfügbarkeitszeiten: { "windows": [{ "days": [1,2,3,4], "from": "12:00", "to": "16:30" }], "fromDate": null, "toDate": null } — bis zu 7 Zeitfenster, Tage ab 0 = Montag, beide Grenzen inklusive, Zeitzone Europe/Warsaw. Der Artikel hat seine eigene Regel, die Kategorie ihre; beide gelten gleichzeitig. Ein Artikel nach seiner Saison (toDate vorbei) kommt gar nicht ins Menü. Das Menü wird gecacht, sagt also nicht, ob ein Artikel jetzt verfügbar ist — berechne das aus der Regel (@delieta/shop-runtime tut das ab 1.8.0: itemSaleState, liveMenu). Der Checkout prüft die Regel für den Erfüllungszeitpunkt: requestedFor oder jetzt + Zubereitungszeit bei „jak najszybciej“.

GET /api/v1/catalog-images//

Ein Foto eines Gerichts oder Catering-Formats. Ohne Schlüssel: Den Browser des Shop-Kunden öffnet die Adresse aus imageUrl, also darf kein Geheimnis verlangt werden. Sie müssen die id und den genauen Dateinamen kennen — ein nicht passendes Paar ist ein 404. ?size=card liefert die 800 px breite Version (ein schmaleres Foto wird unverändert geliefert); ohne den Parameter erhalten Sie das Original.

GET /api/v1/catalog-images/{id}/{filename}?size=card

Die Antwort ist ein 302 zum Dateispeicher oder die Bild-Bytes (image/jpeg, image/png, image/webp oder image/avif). Eine Foto-Adresse ändert nie ihren Inhalt — ein ersetztes Foto bekommt eine neue Adresse —, daher enthält die Antwort Cache-Control: public, max-age=31536000, immutable. Limit: 600 Anfragen pro Minute von einer IP (rate_limited).

GET /api/v1/shop-config

Marke und Regeln des Shops der Firma, zu der der Schlüssel gehört, so wie ihr Shop sie zeigt. Scope catalog:read — derselbe wie beim Menü, ein veröffentlichbarer Schlüssel hat ihn also schon. Die eigenen Markeneinstellungen des Shops haben Vorrang, Feld für Feld; wo sie fehlen, gelten Name, Logo und Farbe der Firma. Die Antwort enthält x-delieta-cache-tag.

GET /api/v1/shop-config
Authorization: Bearer dlt_live_…
{
  "name": "Bella Napoli",
  "tagline": "Pizza z pieca opalanego drewnem",
  "brandColor": "#e2574c",
  "logo": "https://delieta.pl/api/v1/catalog-images/{id}/{filename}",
  "banner": "https://delieta.pl/api/v1/catalog-images/{id}/{filename}",
  "icon": "https://delieta.pl/api/v1/catalog-images/{id}/{filename}",
  "currency": "PLN",
  "locale": "pl",
  "locales": ["pl", "en"],
  "layout": "grid",
  "links": {
    "phone": "+48000000000",
    "email": "kontakt@bella.example",
    "instagram": "https://instagram.com/bella.example",
    "facebook": "https://facebook.com/bella.example",
    "address": "Kwiatowa 5, Bydgoszcz",
    "mapUrl": "https://www.google.com/maps/dir/?api=1&destination=Kwiatowa%205%2C%20Bydgoszcz"
  },
  "modules": ["ordering", "reservations", "catering"],
  "ordering": {
    "fulfilmentModes": ["delivery", "pickup"],
    "paymentModes": ["online", "cash"],
    "onlineMethods": ["card", "blik"],
    "deliveryFeeGrosze": 500,
    "minimumOrderGrosze": 4000,
    "prepMinutes": 30
  },
  "hours": {
    "days": [
      { "weekday": 0, "closed": false, "open": "10:00", "close": "22:00" },
      { "weekday": 6, "closed": true, "open": "10:00", "close": "22:00" }
    ]
  },
  "closures": [
    { "from": "2026-12-24", "to": "2026-12-26", "note": "Święta" }
  ],
  "cateringFormats": [
    {
      "id": "f1",
      "name": "Lunch firmowy",
      "description": "Pizza i napoje dla zespołu.",
      "fromPriceGrosze": 3500,
      "minHeadcount": 10,
      "imageUrl": null,
      "items": [
        { "productId": "i1", "name": "Margherita", "quantity": 1, "perPerson": true, "note": null }
      ]
    }
  ],
  "generatedAt": "2026-08-26T12:00:00.000Z"
}
FeldBedeutung
bannerdas optionale 3:1-Banner der Firma oder null
icondas quadratische Icon der Firma (mindestens 512×512, PNG) für Favicon und App-Icon oder null: dann behält der Shop sein eigenes. Runtime 1.9: shopIcons(config)
localesvon der Firma aktivierte Sprachen, Polnisch zuerst
layoutgrid oder list
linksnur, was der Standort ausgefüllt hat; mapUrl wird aus der Adresse gebildet (eine Google-Maps-Route), wenn der Standort keine eigene angegeben hat
modulesdie Shop-Module, die die Firma an hat: ordering, reservations, catering, events. Was hier fehlt, zeigt der Shop nicht
orderingwie der Shop Bestellungen annimmt: fulfilmentModes, paymentModes (online nur, wenn der Shop eine Karte belasten kann; die Liste kann leer sein), onlineMethods (card, blik, p24: die auf dem Stripe-Konto aktiven Methoden; leer ohne online; nur diese nennen. Kann leer sein, obwohl online angeboten wird (Delieta hat noch nicht erfasst, welche Methoden aktiv sind): dann ein allgemeines «Płatność online» zeigen und keine Methode nennen), deliveryFeeGrosze, minimumOrderGrosze, prepMinutes. null, wenn das Bestellmodul aus ist: dann kein Kassenformular zeigen
hourswöchentliche Öffnungszeiten oder null, wenn der Standort sie nicht gesetzt hat — nehmen Sie dann keine Zeiten an
closureskommende geschlossene Tage (from, to, note oder null), Daten in Europe/Warsaw. Ein fehlendes Feld heißt: keine geschlossenen Tage
cateringFormatsCatering-Formate mit Produktliste (items) und Foto (imageUrl); nur bei eingeschaltetem Catering-Modul. Hier stehen nur Formate mit venue delivery oder both und priceBasis from — die, die ein Shop auf Paket 1.7 korrekt darstellt
cateringPackagesalle aktiven Formate mit allen Paketfeldern; nur bei eingeschaltetem Catering-Modul. Felder: slug, venue (onsite, delivery, both), priceBasis (from, per_person, from_per_person), minHeadcount/maxHeadcount, sections (Zeilen mit Produkt oder eigenem Namen), included („W cenie”), terms („Warto wiedzieć”) und addOns (key, name, amount, unit: szt, kg, g, l, ml oder porcja, priceGrosze, product?). Shop-Paket 1.8 liest dieses Feld statt cateringFormats

hours.days hat genau sieben Einträge, einen pro Tag (weekday 0 = Montag … 6 = Sonntag); oben auf zwei gekürzt. open und close sind HH:MM in der Ortszeit des Standorts und zählen nur bei closed: false. Module, ordering und links werden bei jeder Anfrage gelesen. Eine Firma, zu der der Schlüssel gehörte und die nicht mehr existiert → 404 tenant_not_found.

POST /api/v1/shop-heartbeat

Ein ausgerollter Shop meldet, mit welcher Runtime er gebaut wurde. Einmal pro Build, nie pro Anfrage. Scope catalog:read, kein eigener Scope. Der Schreibzugriff betrifft nur die Flottenspalten in der Shop-Zeile dieser Firma. Immer 204, auch wenn die Firma keine Shop-Zeile hat oder der Body unlesbar ist. Ein dlt_test_…-Schlüssel wird mit 403 test_key_readonly abgelehnt. delieta-shop-assert sendet das für Sie; Sie müssen es nicht selbst aufrufen.

POST /api/v1/shop-heartbeat
Authorization: Bearer dlt_live_…
Content-Type: application/json
{ "runtime": "1.6.0", "contract": "v3", "commit": null, "modified": false }

POST /api/v1/checkout

Der Warenkorb des Shops. Scope checkout:create (veröffentlichbarer Schlüssel). Braucht das Bestellmodul. Idempotency-Key ist Pflicht (8–255 Zeichen). Der Client sendet was, nie wie viel: { items: [{ itemId, quantity, options? }] }, wobei quantity 1–99 ist, höchstens 50 Zeilen, und options ist [{ group, option }] (Gruppen- und Optionsschlüssel aus dem Menü). Preise, Optionsaufschläge und die Summe berechnet Delieta aus den Produkten der Firma, zu der der Schlüssel gehört, in ganzen PLN-Grosze. Ein Feld unitPrice / total / companyId im Body wird ignoriert. Die Adressen nach erfolgreicher und abgebrochener Zahlung stammen aus der Shop-Konfiguration dieser Firma, nie aus der Anfrage.

Ein Shop, der die Gästedaten selbst erfasst, ergänzt: fulfilment (delivery oder pickup, Standard delivery), requestedFor (ein Zeitpunkt aus GET /api/v1/checkout/slots als ISO-Datum mit Offset oder null = so schnell wie möglich), customer (name, phone, email?), address (street, number, flat?, postalCode im Format 00-000, city, note?), invoice (nip mit Prüfsumme, companyName?, address?), note (bis 500 Zeichen), locale und payment (blik, card, p24 oder cash). Regeln: Abholung, Barzahlung und eine Adresse verlangen customer; Lieferung mit customer verlangt address; eine Abhol-Bestellung verwirft die Adresse. Das optionale expectedTotalGrosze ist der Betrag, den der Client auf dem Bildschirm sah. Der Server rechnet nie damit, er vergleicht ihn nur mit dem jetzt berechneten Betrag: weichen sie ab, antwortet er 409 total_changed. items allein ist das alte Format: Online-Zahlung, Lieferung, und Stripe fragt selbst nach Telefon und Adresse.

POST /api/v1/checkout
Authorization: Bearer dlt_live_…
Content-Type: application/json
Idempotency-Key: chk-2026-08-26-42
{ "items": [{ "itemId": "i1", "quantity": 2 }] }

Antwort 201 (Kasse)

{
  "url": "https://checkout.stripe.com/c/pay/cs_test_…",
  "totalGrosze": 6400,
  "currency": "PLN",
  "pricingSource": "catalog"
}

Eine Online-Zahlung antwortet mit url: Leiten Sie den Gast auf die Zahlungsseite um. Die Bestellung entsteht, wenn er zahlt; das Ergebnis lesen Sie in GET /api/v1/checkout/result. Eine Barzahlung (payment: "cash") antwortet sofort mit einer aufgegebenen, noch unbezahlten Bestellung, die auf die Annahme durch die Küche wartet:

{
  "orderShortId": "a1b2c3d4",
  "trackingUrl": "https://delieta.pl/o/a1b2c3d4",
  "totalGrosze": 6400,
  "currency": "PLN",
  "pricingSource": "catalog"
}

Geben Sie dem Gast die trackingUrl und fragen Sie den Status über GET /api/v1/orders/{id}/status ab. Barzahlung braucht kein Konto für Online-Zahlungen, aber customer. Derselbe Idempotency-Key liefert dieselbe Bestellung; eine wiederholte aufgegebene Barbestellung antwortet mit dieser Bestellung, bevor irgendeine Bedingung geprüft wird.

Ablehnungen: Bestellmodul aus → 403 module_disabled. Unbekannter oder nicht verfügbarer Artikel → 422 unprocessable (errors[].code: product_unknown, product_unavailable). Unbekannte Option, fehlende Pflichtgruppe oder zu viele Auswahlen → 422 option_invalid. Warenkorb unter dem Mindestwert des Shops → 422 below_minimum. Ein Artikel „Tylko w karcie“ → 422 product_menu_only. Ein Artikel außerhalb seiner Verfügbarkeitszeiten → 409 product_outside_hours. Lieferung an eine Adresse außerhalb des Gebiets → 409 out_of_range. Eine nicht gefundene Adresse → 422 address_not_found. Vorübergehend kein Lieferpreis → 503 delivery_quote_unavailable. Lieferung im Lokal nicht eingestellt → 409 delivery_unconfigured. Ein geänderter Betrag → 409 total_changed. Geschlossen und kein „so schnell wie möglich“ → 409 shop_closed. Zeit außerhalb der Liste → 409 slot_unavailable. Eine Übergabe, die der Shop nicht anbietet → 409 fulfilment_unavailable. Eine Zahlung, die der Shop nicht akzeptiert → 409 payment_unavailable. Online-Zahlung in einem Shop mit Beispieldaten bei Live-Zahlungen → 409 sample_mode (eine Vorschau zahlt nur im Testmodus). Kein Shop-Origin → 409 shop_unconfigured. Konto für Online-Zahlungen nicht bereit → 409 connect_not_ready (es gibt keine Schein-Zahlung).

GET /api/v1/checkout/slots

Wann der Shop eine Bestellung annimmt: „so schnell wie möglich“ und die Zeitpunkte, die ein Gast wählen kann. Scope catalog:read. Der Parameter fulfilment ist delivery (Standard) oder pickup. Die Zeiten werden aus Öffnungszeiten, geschlossenen Tagen, Vorbereitungszeit, Schritt und Horizont des Shops in Europe/Warsaw-Zeit berechnet und als ISO-Zeitpunkte geliefert. Die Kasse prüft kurz darauf dieselben Zeiten, daher endet eine Zeit außerhalb der Liste in 409 slot_unavailable. Nie gecacht. Ohne gesetzte Zeiten nimmt der Shop „so schnell wie möglich“ an, hat aber kein Zeitraster.

GET /api/v1/checkout/slots?fulfilment=pickup
Authorization: Bearer dlt_live_…
{
  "asap": { "available": true, "readyInMinutes": 30 },
  "slots": [
    { "startsAt": "2026-08-26T08:30:00.000Z" },
    { "startsAt": "2026-08-26T08:45:00.000Z" }
  ]
}

Ein ungültiges fulfilment → 400 invalid_request. Ein Shop, der diese Übergabe nicht anbietet → 409 fulfilment_unavailable. Bestellmodul aus → 403 module_disabled.

GET /api/v1/checkout/result

Das geprüfte Ergebnis einer Online-Zahlung, für die Bestätigungsseite des Shops. Scope checkout:create. Übergeben Sie die session_id aus der Rücksprungadresse (cs_test_… oder cs_live_…; die Zahlung hängt sie an die Erfolgsadresse an). Die Antwort stammt aus Bestellung und Zahlung in Delieta, nicht aus dem Browser: paid, processing (das Geld ist unterwegs oder die Bestellung wird noch gespeichert; in ein paar Sekunden erneut fragen), unpaid (der Gast ist gegangen oder die Sitzung ist abgelaufen) oder unknown (das ist keine Kasse dieses Shops). statementDescriptor ist der Text, den der Kunde auf dem Kontoauszug sieht; er ist null, wenn es keine Kartenzahlung ist. method ist blik, card, p24, cash, other oder null. Fehlende oder falsche session_id → 400 invalid_request. Nie gecacht.

GET /api/v1/checkout/result?session_id=cs_live_…
Authorization: Bearer dlt_live_…
{
  "status": "paid",
  "orderShortId": "K7M2QX",
  "trackingUrl": "https://bella.delieta.pl/o/K7M2QX",
  "totalGrosze": 5400,
  "merchantName": "Bella Pizza",
  "statementDescriptor": "BELLA* 3F9A12CD",
  "method": "blik",
  "livemode": true
}

POST /api/v1/checkout/quote

Ein Preisangebot für den Warenkorb, ohne Bestellung anzulegen: Gerichte, Verpackung, Lieferung und Summe. Scope checkout:create (veröffentlichbarer Schlüssel). Body: { items, fulfilment?, address? }, wie bei POST /checkout, ohne Gast- und Zahlungsdaten; Geldfelder werden ignoriert. Limit: 60 Angebote pro Minute und Besucher (rate_limited), getrennt von Menü-Lesezugriffen: jede neue Adresse ist ein kostenpflichtiges Geocoding. Der Shop berechnet Gebühren nicht selbst, er zeigt, was das Angebot liefert.

Antwort 200:

{
  "quote": {
    "currency": "PLN",
    "itemsGrosze": 4500,
    "packagingGrosze": 200,
    "packaging": [{ "kind": "item", "label": "Opakowanie", "quantity": 2, "unitGrosze": 100, "totalGrosze": 200 }],
    "delivery": { "status": "priced", "feeGrosze": 500, "free": false, "freeFromGrosze": 9000, "missingForFreeGrosze": 4500, "distanceMeters": 3200 },
    "totalGrosze": 5200,
    "minimum": { "minimumOrderGrosze": 3000, "missingGrosze": 0 }
  }
}

delivery.status ist none (Abholung), needs_address (Kilometerstufen und noch keine Adresse) oder priced. Bei priced kommen feeGrosze und, wenn der Preis von der Entfernung abhängt, distanceMeters hinzu. Die Felder fromGrosze und toGrosze beschreiben den Bereich der Gebühr bei entfernungsabhängigem Preis. Das Feld packaging[].kind ist item (Gebühr pro Stück) oder order (Gebühr pro Bestellung). freeFromGrosze und missingForFreeGrosze dienen dem Hinweis „bis zur kostenlosen Lieferung fehlen …“. totalGrosze ist null, solange eine Adresse nötig ist.

Unter dem Mindestwert ist das Angebot kein Fehler: die Lücke zeigt minimum.missingGrosze. Der Fehler erscheint erst in POST /checkout als below_minimum. Die Entfernung ist die Luftlinie vom Lokal, aufgerundet auf 100 m; kostenlose Lieferung und Mindestbestellwert zählen nur die Gerichte, ohne Verpackung und Lieferung (genau die Schwelle ist kostenlos). Ablehnungen des Angebots: out_of_range, address_not_found, delivery_quote_unavailable (Abholung wird weiter berechnet), delivery_unconfigured, fulfilment_unavailable. Das Angebot prüft „Tylko w karcie“ und Verfügbarkeitszeiten (product_menu_only, product_outside_hours) nicht: das macht der Checkout zur Erfüllungszeit. Die Codes stehen in der Fehlertabelle. Preisregeln: Shop.

POST /api/v1/quotes

Eine Fahrtschätzung, bevor eine Bestellung existiert. Scope eta:quote. Der Start ist der Standort der Firma; Sie geben nur das Ziel an. Das Ergebnis ist immer eine Spanne (minMinutes / maxMinutes). Das Feld guaranteed ist die Konstante false — das ist kein SLA. Nach expiresAt erneut fragen.

{ "destination": { "lat": 53.123456, "lng": 18.012345 } }
{
  "quote": {
    "currency": "PLN",
    "minMinutes": 35,
    "maxMinutes": 50,
    "guaranteed": false,
    "breakdown": {
      "prepMinutes": 15,
      "loadMinutes": 4,
      "travelMinutes": 12,
      "padMinutes": 8
    },
    "distanceMeters": 4200,
    "computedAt": "2026-08-26T12:00:00.000Z",
    "expiresAt": "2026-08-26T12:05:00.000Z"
  }
}

Zeigen Sie beide Enden des Bereichs. Eine einzelne Zahl in der Partner-UI führt in die Irre. Keine Standortkoordinaten → 409 venue_not_configured. Ziel außerhalb des Lieferradius der Firma → 409 out_of_range. Schlechter Body → 400 invalid_request. Die Firma, zu der der Schlüssel gehörte, existiert nicht → 404 tenant_not_found.

POST /api/v1/orders

Legt eine Bestellung für die Firma an, zu der der Schlüssel gehört. Scope orders:write. Der Server summiert die Zeilen und verwirft eine von Ihnen übergebene Summe. Die Einzelpreise stammen vom Aufrufer: pricingSource ist "caller". Das ist eine Bestellung aus einem Partnerkanal, kein Shop-Warenkorb; ein nach Katalog bepreister Warenkorb ist POST /api/v1/checkout.

Idempotency-Key

Ein Pflicht-Header, 8–255 Zeichen nach dem Entfernen der Leerzeichen. Ein Schlüssel pro logischem Versuch. Wiederholen Sie mit demselben Schlüssel und demselben Body nach einem Netzwerkfehler, 500 create_failed oder 503 idempotency_unavailable. Eine erfolgreiche 201-Antwort wird 24 Stunden gespeichert: Eine Wiederholung liefert dieselbe Antwort und Idempotent-Replayed: true. Derselbe Schlüssel mit anderem Body → 409 idempotency_key_conflict. Ist der Idempotenz-Speicher nicht verfügbar, bekommen Sie 503, nie ein Duplikat.

Body

Es gibt kein Firmenfeld. Ein typischer Aufruf mit den Preisen des Aufrufers:

{
  "customerName": "Jan Kowalski",
  "customerPhone": "+48123456789",
  "destinationAddress": "ul. Przykładowa 1, 85-000 Bydgoszcz",
  "destinationPoint": { "lat": 53.123456, "lng": 18.012345 },
  "items": [
    { "name": "Margherita 32cm", "qty": 1, "unitPrice": 3200 },
    { "name": "Cola 0,5l", "qty": 2, "unitPrice": 800 }
  ],
  "paymentMethod": "cash",
  "channel": "web",
  "externalRef": "your-storefront-order-42"
}
FeldPflichtHinweise
customerNameja1–200 Zeichen
customerPhoneja1–40 Zeichen
destinationAddressja1–500 Zeichen
destinationPointnein{ lat, lng } WGS84. Nicht destination oder destinationCoordinates — das ist 400 invalid_request mit errors[].code unknown_field, weil eine Bestellung ohne Koordinaten keine ETA bekommt
itemsja1–50 Zeilen; qty 1–99
items[].name / items[].unitPricejaGrosze; der Server berechnet totalGrosze neu
items[].menuItemIdneinProdukt-ID; options wird bei der Preisbildung ignoriert
detailsneinbis 4000 Zeichen
customerNoteneinbis 2000 Zeichen
paymentMethodneincash | card | online (Standard cash)
channelneinphone | web | pos | integration (Standard web)
scheduledForneinein Zeitpunkt als ISO-Datum
sourceVariantneinbis 64 Zeichen
externalRefneinbis 64 Zeichen; Dedup auf Ihrer Seite, eine Kollision → duplicate_external_ref
POST /api/v1/orders
Authorization: Bearer dlt_live_…
Content-Type: application/json
Idempotency-Key: ord-2026-08-26-storefront-42

Antwort 201 (Bestellung)

{
  "order": {
    "id": "1",
    "shortId": "a1b2c3d4",
    "status": "accepted",
    "createdAt": "2026-08-26T12:00:00.000Z",
    "tenantSlug": "bella-pizza",
    "externalRef": "your-storefront-order-42",
    "currency": "PLN",
    "totalGrosze": 4800,
    "lines": [
      { "name": "Margherita 32cm", "qty": 1, "unitPrice": 3200 },
      { "name": "Cola 0,5l", "qty": 2, "unitPrice": 800 }
    ],
    "pricingSource": "caller",
    "trackingUrl": "https://delieta.pl/o/a1b2c3d4"
  }
}

status ist accepted oder pending_acceptance, je nach Annahmemodus der Firma. Die trackingUrl geben Sie dem Kunden. Sie ist die einzige öffentliche Tracking-Adresse. Schreibfehler: 404 tenant_not_found, 409 duplicate_external_ref, 500 create_failed.

GET /api/v1/orders/

Liest eine Bestellung der Firma, zu der der Schlüssel gehört. Der Scope ist derselbe: orders:write — die Scope-Menge ist geschlossen und auf aktiven Schlüsseln bereits ausgegeben; ein neues orders:read würde bestehende Integrationen brechen. Das Abfragen zählt zum Lese-Limit, nicht zum Anlege-Limit.

id ist die order.id aus der 201-Antwort. Eine fremde oder nicht existierende ID → 404 not_found, die Antwort verrät also nicht, ob so eine Bestellung existiert. Die Antwort hat weniger Felder als die beim Anlegen. Der Partner bekommt den Bestellverlauf, keine internen Spalten:

{
  "order": {
    "id": "1",
    "shortId": "a1b2c3d4",
    "status": "pending_acceptance",
    "externalRef": "your-storefront-order-42",
    "createdAt": "2026-08-26T12:00:00.000Z",
    "promisedAt": null,
    "acceptedAt": null,
    "rejectedAt": null,
    "rejectionReason": null,
    "acceptanceDeadlineAt": 1756200000000
  }
}

acceptedAt, rejectedAt und acceptanceDeadlineAt sind Unix-ms oder null. Die Status, die Sie sehen, sind die aufeinanderfolgenden Bestellstatus: pending_acceptance, accepted, preparing, ready, on_the_way, delivered und rejected. Die Lieferung überspringt ready, die Abholung überspringt on_the_way.

GET /api/v1/orders//status

Wo die Bestellung ist, für die Tracking-Seite des Gastes. Scope catalog:read, ein veröffentlichbarer Schlüssel kann das also aus einem Shop abfragen. {id} ist der kurze Bestellcode (orderShortId aus der Kassenantwort, Groß-/Kleinschreibung egal), nicht order.id. Die Antwort enthält keine Kundendaten: nur Status, Übergabeart und Zeit. Ein nicht existierender, falsch geschriebener oder fremder Code antwortet gleich: 404 not_found.

GET /api/v1/orders/a1b2c3d4/status
Authorization: Bearer dlt_live_…
{
  "status": "preparing",
  "fulfilment": "pickup",
  "etaMinutes": 12,
  "promisedAt": "2026-08-26T08:45:00.000Z"
}

status ist einer von: pending_acceptance, accepted, preparing, ready (Abholung: „Abholbereit“), on_the_way, delivered, rejected. etaMinutes sind ganze Minuten bis promisedAt, nie negativ, und erscheint nur, solange die Küche die Bestellung hat (accepted, preparing, on_the_way). promisedAt ist die vom Personal versprochene Zeit, ohne sie die vom Gast gewünschte Zeit. readyAt erscheint, wenn eine Abhol-Bestellung ready ist.

Tischreservierungen

Sie brauchen das eingeschaltete Reservierungsmodul (Tarif oder Zuteilung und der Schalter des Inhabers). Modul aus: 403 module_disabled.

GET /api/v1/floor-plan

GET /api/v1/floor-plan

Zonen und Tische der Firma mit Geometrie (grid ist ein einheitenloses { width, height }-Raster, das der Shop auf seine Zeichnung skaliert). Scope catalog:read. ?locale= übersetzt Zonennamen. Die Antwort enthält x-delieta-cache-tag.

GET /api/v1/reservations/availability

GET /api/v1/reservations/availability?date=2030-06-14&partySize=2

Freie Startzeiten und für jede die freien Tische, die zur Gruppe passen: date, partySize, durationMinutes und slots[] mit startsAt, time und tableIds. time ist die Ortszeit in Europe/Warsaw, startsAt der zu buchende Zeitpunkt. Gibt es keine Zeiten, sagt das Feld closedReason warum: closed_day, closure oder hours_not_configured. Ein falsches date-Format oder partySize außerhalb 1–100: 422 validation_failed. Scope catalog:read. Nie gecacht.

POST /api/v1/reservations

POST /api/v1/reservations
Authorization: Bearer dlt_live_…
Idempotency-Key: 4b0b3f0e-6d21-4f0a-9c1c-0d6f0e0a7a11
Content-Type: application/json

{ "startsAt": "2030-06-14T16:00:00.000Z", "partySize": 2, "tableId": "…",
  "guest": { "name": "Ala Kowalska", "phone": "600100200", "email": "ala@example.pl" },
  "occasion": "birthday", "note": "przy oknie" }

Felder: startsAt (ein ISO-Datum mit Offset), partySize (1–100), tableId?, guest (name bis 80 Zeichen, phone, email?), occasion? (none, birthday, anniversary, date, business), note? (bis 500 Zeichen), locale? (pl, en, de, uk — in dieser Sprache geht die Bestätigung an den Gast). Ein Body über 8 KiB → 422 validation_failed.

Zwei Schlüsselarten. Ein veröffentlichbarer Schlüssel mit checkout:create macht eine web-Buchung: Der Start muss ein angebotener Zeitpunkt sein, der Status ist requested oder bei automatischer Bestätigung confirmed. Ein geheimer Schlüssel mit reservations:write macht eine api-Buchung aus dem eigenen System: zu jeder Stunde, der Tisch muss nur frei sein, der Status ist immer confirmed. Idempotency-Key (8–100 Zeichen) ist optional, wird aber beachtet: Derselbe Schlüssel liefert die erste Buchung. Das Feld website ist eine Bot-Falle, lassen Sie es leer.

201 liefert id, reference, status, startsAt, durationMinutes, tableIds. status ist requested, confirmed, seated, completed, cancelled oder no_show. Ablehnungen sind problem+json mit stabilem code:

Statuscode
409slot_unavailable, table_taken
422validation_failed, party_too_large, out_of_range
403module_disabled, scope_required

GET /api/v1/events

Die Veranstaltungen der Firma: Workshops, Verkostungen, Abende. Scope catalog:read. Braucht das Modul Veranstaltungen: aus → 403 module_disabled, nicht lesbar → 503 module_unavailable. Optional ?locale=.

Antwort 200: { "events": [...], "locale": "pl", "generatedAt": "..." }. Die Liste enthält nur veröffentlichte Veranstaltungen mit kommendem Termin, in der Reihenfolge sort, dann nach dem nächsten Termin. Jede Veranstaltung:

FeldBedeutung
id, slug, name, description, audience, scheduleNote, imageUrldie Beschreibung der Veranstaltung; description ist reiner Text, Zeilen mit - sind Aufzählungspunkte
priceMode, pricePerPersonGroszeper_person, free oder on_request; der Preis nur bei per_person
participants{ min, max } pro Anfrage
scheduleMode, occurrencesdated oder on_request („termin do uzgodnienia“, leere occurrences); Termine { id, date, time, endTime, note }
booking, phoneinquiry oder phone; das Telefon der Veranstaltung oder der Firma. Bei phone die Nummer zeigen: die API lehnt Anmeldungen ab (event_phone_only)

Die Antwort enthält den Header x-delieta-cache-tag (Tag tenant:{id}:events, alle 5 Minuten aufgefrischt), und der Zeitfilter läuft nach dem Cache, sodass vergangene Termine ohne Warten verschwinden.

POST /api/v1/inquiries

Eine Gästeanfrage: Kontakt, Catering oder Veranstaltung. Scope checkout:create (veröffentlichbarer Schlüssel), also rufen Sie sie vom Server des Shops auf, nicht vom Browser. Das Limit gilt pro Besucher (übergeben Sie seine Adresse in x-delieta-visitor). Das Feld website ist eine Bot-Falle: leer lassen. Das nötige Modul hängt von der Art ab: catering und contact brauchen das Catering-Modul, event das Modul Veranstaltungen. Ist das nötige Modul aus, lautet die Antwort 403 module_disabled. Ein Body über 64 KiB → 413 payload_too_large. Ein unbekanntes Feld → 400 invalid_request.

Felder: kind (contact, catering oder event), name, phone und/oder email (eines davon ist Pflicht, bei Catering phone), message (Pflicht bei contact), topic? (reservation, catering, order, other), locale? und, für catering, ein Objekt catering: formatId?, headcount, eventDate (JJJJ-MM-TT), eventTime? (HH:MM), deliveryAddress?, dietary? (vegetarian, gluten_free, lactose_free), dietaryNote?, company?, nip?, venue? (onsite oder delivery) und addOns? ([{ key, quantity }], bis zu 30 Positionen, quantity 1–99, jeder key einmal). Der Body enthält nie den Preis oder den Namen eines Zusatzes: sie stammen aus dem Format. Zusätze dürfen nur mit formatId gesendet werden.

Für event sind die Felder ein Objekt event: eventId, occurrenceId? (ein Termin aus GET /events), preferredDate? und preferredTime? (für eine Veranstaltung „Do uzgodnienia“; preferredDate ist dann Pflicht), participants und organization?. phone ist Pflicht, message optional. Der Body ist streng: ein unbekanntes Feld ist 400.

POST /api/v1/inquiries
Authorization: Bearer dlt_live_…
Content-Type: application/json
{
  "kind": "catering",
  "name": "Anna Nowak",
  "phone": "+48600100200",
  "catering": { "formatId": "f1", "headcount": 40, "eventDate": "2026-12-12", "company": "Acme", "nip": "5260250995" }
}

Erfolg: 201 { "inquiry": { "reference": "AB12CD", "status": "new" } }. Eine falsche NIP (Prüfsumme), ein fehlendes Telefon oder ein unbekanntes Feld → 400 invalid_request mit einer errors-Liste. Ein unbekanntes Format → 422 unprocessable. Eine Anfrage vor Ort für einen Tag, an dem das Lokal geschlossen ist → 422 venue_closed („W tym dniu lokal jest zamknięty.”).

Anmeldungen zu Veranstaltungen (kind: "event")

Eine Anmeldung zu einer Veranstaltung des Lokals (Modul Wydarzenia) ist ebenfalls eine Anfrage: kind: "event" mit einem event-Block. Eine Telefonnummer ist Pflicht. Eine Veranstaltung mit Terminen nimmt occurrenceId (einer der Termine aus GET /api/v1/events); eine Veranstaltung „termin do uzgodnienia“ nimmt preferredDate (optional preferredTime). Ist das Modul Wydarzenia aus, lautet die Antwort 403 module_disabled. Ablehnungen sind 422 unprocessable mit dem Code in errors[].code und polnischem Text am Feld: unknown_event, event_not_bookable, event_past, event_phone_only, unknown_occurrence, event_in_past, preferred_date_required, participants_out_of_range.

POST /api/v1/catering-orders

Die Firma erfasst einen Catering-Auftrag aus ihrem eigenen System. Scope catering:write (nur geheimer Schlüssel). Delieta erfasst den Verkauf: Der Body enthält den vereinbarten Betrag in Grosze (agreedAmountGrosze); die Zahlung ist optional (paid: true markiert bezahlt). Die Positionen (lines) verweisen per menuItemId auf Produkte der Firma; eine fremde oder unbekannte ID → 422 unprocessable. Der Auftrag hat source: api. Optionaler Idempotency-Key: eine Wiederholung liefert den ersten Auftrag (200, Idempotent-Replayed: true). Modul aus → 403 module_disabled. Eine belegte Verknüpfung mit einer Anfrage → 409 conflict. Ein Body über 64 KiB → 413 payload_too_large.

Felder: customer (name, phone?, email?, company?, nip?), eventDate (JJJJ-MM-TT), eventTime?, headcount?, deliveryAddress?, formatId?, lines[] (menuItemId, quantity, unitPriceGrosze?), agreedAmountGrosze, note?, status? (planned, confirmed, delivered, cancelled), paid?, inquiryId?.

{
  "customer": { "name": "Acme sp. z o.o.", "nip": "5260250995" },
  "eventDate": "2026-12-12",
  "headcount": 40,
  "lines": [{ "menuItemId": "i1", "quantity": 40 }],
  "agreedAmountGrosze": 240000
}

Erfolg: 201 { "order": { "id", "reference", "status": "planned", "source": "api", "paymentStatus": "unpaid", … } }. paymentStatus ist unpaid oder paid.

GET /api/v1/catering-orders

GET /api/v1/catering-orders?page=1&limit=50 liefert die Liste { orders, page, limit, total }, neueste zuerst (limit bis 100). Derselbe Scope catering:write.

Die Catering-Formate der Firma stehen in der Antwort der Shop-Konfiguration, nur bei eingeschaltetem Modul: cateringFormats (Lieferformate mit „ab“-Preis) und cateringPackages (alle Formate mit ihren Paketfeldern). Jedes Format hat imageUrl (Foto-URL oder null).

OpenAPI

GET /api/v1/openapi

Das öffentliche OpenAPI-3.1-Dokument, ohne Schlüssel. Erzeugen Sie daraus einen Client, wenn Sie kein handgeschriebenes curl wollen. Diese Seite wird damit abgeglichen — weichen sie ab, haben OpenAPI und der Test im Repository recht.

Es gibt keine Webhook-Operation von Delieta für den Bestellstatus. Den Status lesen Sie hier, per GET. Die einzige Kommunikation in die andere Richtung (von Delieta an den Shop) beschreibt Webhooks.