{"openapi":"3.1.1","info":{"title":"Delieta Partner API","version":"1.0.0","description":"Headless ordering, menu and delivery-estimate API for Delieta tenants. A key resolves the company — no request ever names a tenant. Money is integer grosze; PLN is the only currency in v1."},"servers":[{"url":"https://delieta.pl/api/v1"}],"security":[{"apiKey":[]}],"paths":{"/menu":{"get":{"operationId":"getMenu","summary":"The catalog for the API key's company","description":"Requires the `catalog:read` scope (`menu:read` is a stored alias for keys minted before that name). A publishable key may hold this scope plus `checkout:create`. Unavailable items are omitted. The shape is frozen.","responses":{"200":{"description":"The tenant's menu.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Menu"}}}},"401":{"description":"No valid API key was presented (`unauthorized`).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The key is missing the required scope (`scope_required`).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limit exceeded for this key (`rate_limited`).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/checkout":{"post":{"operationId":"createCheckout","summary":"Price a cart from the catalogue and start Stripe Checkout","description":"Requires the `checkout:create` scope (publishable). The body is `{ items: { itemId, quantity }[] }`. The server prices from the tenant catalogue in grosze PLN and ignores any client `unitPrice` / `total`. Success and cancel URLs come from the shop's stored config, never from the request URL. When the connected account cannot charge, the response is `connect_not_ready`.","parameters":[{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutCreateRequest"}}}},"responses":{"201":{"description":"Stripe Checkout Session URL. Redirect the diner.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutResponse"}}}},"400":{"description":"`invalid_request` or `idempotency_key_required`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"No valid API key was presented (`unauthorized`).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The key is missing the required scope (`scope_required`).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"`shop_closed`, `shop_unconfigured`, or `connect_not_ready`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"`unprocessable` — unknown or unavailable product; see `errors[].code`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limit exceeded for this key (`rate_limited`).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"503":{"description":"`idempotency_unavailable` — the idempotency store is down; retry.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/quotes":{"post":{"operationId":"createQuote","summary":"Delivery time estimate, before an order exists","description":"Requires the `eta:quote` scope. Composed as prep + load + travel + pad from the company's own venue. Always a RANGE and never a guarantee (`guaranteed` is always false).","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteRequest"}}}},"responses":{"200":{"description":"An estimate range.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteResponse"}}}},"400":{"description":"`invalid_request` — body is not JSON or schema validation failed; see field errors.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"No valid API key was presented (`unauthorized`).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The key is missing the required scope (`scope_required`).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"`tenant_not_found` — the key's company no longer exists.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"`venue_not_configured` — the company has no venue coordinates.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limit exceeded for this key (`rate_limited`).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/orders":{"post":{"operationId":"createOrder","summary":"Create an order for the API key's company","description":"Requires the `orders:write` scope and an `Idempotency-Key`. The server sums and validates the total and rejects a caller-supplied total, but unit prices are taken from the caller in slice 1 (`pricingSource: \"caller\"`); catalog-authoritative pricing arrives with the menu in slice 2. The response envelope is frozen for 24 hours against the idempotency key.","parameters":[{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":8,"maxLength":255},"description":"Unique per logical order. Retrying with the same key returns the original envelope and `Idempotent-Replayed: true` instead of creating a duplicate."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderCreateRequest"}}}},"responses":{"201":{"description":"The created (or replayed) order.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderResponse"}}}},"400":{"description":"`invalid_request`, `idempotency_key_required`, `line_price_missing`, `line_name_missing` or `total_out_of_range`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"No valid API key was presented (`unauthorized`).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The key is missing the required scope (`scope_required`).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"`tenant_not_found` — the key's company no longer exists.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"`duplicate_external_ref` — that reference already created an order.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limit exceeded for this key (`rate_limited`).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"503":{"description":"`idempotency_unavailable` — the idempotency store is down; retry.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/orders/{id}":{"get":{"operationId":"readOrder","summary":"Read one order the API key's company owns","description":"Requires the `orders:write` scope — the scope set is closed and already minted onto live keys, and reading is strictly less than writing. Counts against the READ budget, not the order-creation budget, so polling for an acceptance decision never costs you the ability to place the next order. An order created while the company requires acceptance starts in `pending_acceptance` and leaves it only when a person accepts or rejects it, or when the acceptance timeout sweeps it — none of which the caller can observe any other way.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The `order.id` returned when the order was created."}],"responses":{"200":{"description":"The order's current state.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderReadResponse"}}}},"401":{"description":"No valid API key was presented (`unauthorized`).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The key is missing the required scope (`scope_required`).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"`not_found` — no such order for this API key. An order belonging to another company answers identically, so this is never an existence oracle.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limit exceeded for this key (`rate_limited`).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}}},"components":{"securitySchemes":{"apiKey":{"type":"http","scheme":"bearer","bearerFormat":"dlt_{live|test}_…","description":"Per-company API key. Scopes are checked per endpoint and an empty scope list is denied everywhere."}},"schemas":{"OrderCreateRequest":{"type":"object","properties":{"customerName":{"type":"string","minLength":1,"maxLength":200},"customerPhone":{"type":"string","minLength":1,"maxLength":40},"destinationAddress":{"type":"string","minLength":1,"maxLength":500},"destinationPoint":{"type":"object","properties":{"lat":{"type":"number","minimum":-90,"maximum":90},"lng":{"type":"number","minimum":-180,"maximum":180}},"required":["lat","lng"]},"details":{"type":"string","maxLength":4000},"customerNote":{"type":"string","maxLength":2000},"items":{"minItems":1,"maxItems":50,"type":"array","items":{"type":"object","properties":{"menuItemId":{"type":"string","minLength":1,"maxLength":64},"name":{"type":"string","minLength":1,"maxLength":200},"qty":{"type":"integer","minimum":1,"maximum":99},"options":{"maxItems":20,"type":"array","items":{"type":"string","minLength":1,"maxLength":64}},"unitPrice":{"type":"integer","minimum":0,"maximum":100000000}},"required":["qty"]}},"paymentMethod":{"default":"cash","type":"string","enum":["cash","card","online"]},"channel":{"default":"web","type":"string","enum":["phone","web","pos","integration"]},"scheduledFor":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"sourceVariant":{"type":"string","maxLength":64},"externalRef":{"type":"string","minLength":1,"maxLength":64}},"required":["customerName","customerPhone","destinationAddress","items"]},"QuoteRequest":{"type":"object","properties":{"destination":{"type":"object","properties":{"lat":{"type":"number","minimum":-90,"maximum":90},"lng":{"type":"number","minimum":-180,"maximum":180}},"required":["lat","lng"]}},"required":["destination"]},"CheckoutCreateRequest":{"type":"object","properties":{"items":{"minItems":1,"maxItems":50,"type":"array","items":{"type":"object","properties":{"itemId":{"type":"string","minLength":1,"maxLength":64},"quantity":{"type":"integer","minimum":1,"maximum":99}},"required":["itemId","quantity"]}}},"required":["items"]},"CheckoutResponse":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"totalGrosze":{"type":"integer"},"currency":{"const":"PLN"},"pricingSource":{"const":"catalog"}},"required":["url","totalGrosze","currency","pricingSource"]},"Problem":{"type":"object","description":"RFC 9457 problem detail.","properties":{"type":{"type":"string"},"title":{"type":"string"},"status":{"type":"integer"},"code":{"type":"string","description":"Stable machine code. Branch on this, never on `title`."},"detail":{"type":"string"},"errors":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"code":{"type":"string"},"message":{"type":"string"}},"required":["field","message"]}}},"required":["type","title","status","code"]},"OrderLine":{"type":"object","properties":{"name":{"type":"string"},"qty":{"type":"integer"},"unitPrice":{"type":"integer","description":"Grosze."}},"required":["name","qty","unitPrice"]},"OrderResponse":{"type":"object","properties":{"order":{"type":"object","properties":{"id":{"type":"string"},"shortId":{"type":"string"},"status":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"tenantSlug":{"type":"string"},"externalRef":{"type":["string","null"]},"currency":{"const":"PLN"},"totalGrosze":{"type":"integer"},"lines":{"type":"array","items":{"$ref":"#/components/schemas/OrderLine"}},"pricingSource":{"enum":["catalog","caller"]},"trackingUrl":{"type":"string","format":"uri"}},"required":["id","shortId","status","currency","totalGrosze","trackingUrl"]}},"required":["order"]},"OrderReadResponse":{"type":"object","properties":{"order":{"type":"object","description":"Deliberately narrower than the create envelope: a read publishes only the lifecycle fields a partner needs, never the tenant-internal columns on the row.","properties":{"id":{"type":"string"},"shortId":{"type":"string"},"status":{"type":"string"},"externalRef":{"type":["string","null"]},"createdAt":{"type":["string","null"],"format":"date-time"},"promisedAt":{"type":["string","null"],"format":"date-time"},"acceptedAt":{"type":["integer","null"],"description":"Unix ms."},"rejectedAt":{"type":["integer","null"],"description":"Unix ms."},"rejectionReason":{"type":["string","null"]},"acceptanceDeadlineAt":{"type":["integer","null"],"description":"Unix ms auto-reject deadline; null when there is no gate."}},"required":["id","shortId","status"]}},"required":["order"]},"QuoteResponse":{"type":"object","properties":{"quote":{"type":"object","properties":{"currency":{"const":"PLN"},"minMinutes":{"type":"integer"},"maxMinutes":{"type":"integer"},"guaranteed":{"const":false},"breakdown":{"type":"object","properties":{"prepMinutes":{"type":"integer"},"loadMinutes":{"type":"integer"},"travelMinutes":{"type":"integer"},"padMinutes":{"type":"integer"}},"required":["prepMinutes","loadMinutes","travelMinutes","padMinutes"]},"distanceMeters":{"type":"integer"},"computedAt":{"type":"string","format":"date-time"},"expiresAt":{"type":"string","format":"date-time"}},"required":["currency","minMinutes","maxMinutes","guaranteed","breakdown"]}},"required":["quote"]},"Menu":{"type":"object","properties":{"currency":{"const":"PLN"},"generatedAt":{"type":"string","format":"date-time"},"categories":{"type":"array","items":{"$ref":"#/components/schemas/MenuCategory"}},"items":{"type":"array","items":{"$ref":"#/components/schemas/MenuItem"}}},"required":["currency","generatedAt","categories","items"]},"MenuCategory":{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"name":{"type":"string"},"sort":{"type":"integer"}},"required":["id","slug","name","sort"]},"MenuModifierOption":{"type":"object","properties":{"key":{"type":"string"},"name":{"type":"string"},"priceDeltaGrosze":{"type":"integer"}},"required":["key","name","priceDeltaGrosze"]},"MenuModifierGroup":{"type":"object","properties":{"key":{"type":"string"},"name":{"type":"string"},"required":{"type":"boolean"},"min":{"type":"integer"},"max":{"type":"integer"},"options":{"type":"array","items":{"$ref":"#/components/schemas/MenuModifierOption"}}},"required":["key","name","required","min","max","options"]},"MenuItem":{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"categoryId":{"type":"string"},"name":{"type":"string"},"description":{"type":["string","null"]},"basePriceGrosze":{"type":"integer","description":"Grosze."},"allergens":{"type":"array","items":{"type":"string"}},"modifierGroups":{"type":"array","items":{"$ref":"#/components/schemas/MenuModifierGroup"}},"sort":{"type":"integer"}},"required":["id","slug","categoryId","name","basePriceGrosze","allergens","sort"]}}}}