Delieta文档

机器翻译。波兰语为规范文档。

Partner API

HTTP /api/v1 — 菜单、结账、ETA 报价、创建和读取订单。契约来自 OpenAPI 3.1。

Partner API v1 是 https://delieta.pl/api/v1 下的 HTTP 表面。Delieta 签发给一家公司的 API 钥匙决定租户。已发布操作为 GET /menuPOST /checkoutPOST /quotesPOST /ordersGET /orders/{id}。机器描述:GET /api/v1/openapi(OpenAPI 3.1,无需钥匙)。

flowchart LR
  bearer["Authorization Bearer"] --> verify["钥匙就是公司"]
  verify --> scope{"scope"}
  scope -->|"catalog:read"| menu["GET /menu"]
  scope -->|"checkout:create"| checkout["POST /checkout"]
  scope -->|"orders:write"| handoff["POST /orders"]
  handoff --> same["和面板同一张订单"]

钥匙与范围

Header:

Authorization: Bearer dlt_live_…

缺少或错误钥匙 → 401 unauthorized

Scope操作
catalog:readGET /api/v1/menu (可发布)。menu:read 是旧钥匙别名。
checkout:createPOST /api/v1/checkout (可发布)。除 catalog:read + checkout:create 以外没有。
eta:quotePOST /api/v1/quotes (秘密)
orders:writePOST /api/v1/orders and GET /api/v1/orders/{id} (秘密)

空 scope 列表什么也不开 — 403 scope_required。可发布钥匙 不能 拿到 orders:write。秘密钥匙不会从静态店调用结账。

dlt_test_… 真实地读和报价。POST /api/v1/orders 拒绝 403 test_key_readonly。没有单独测试数据集:测试读公司的生产目录。

错误

每个 v1 拒绝都是 application/problem+json。按 code 分支。

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

OpenAPI 记载、路由使用的代码:

codestatus何时
unauthorized401缺少或错误钥匙
scope_required403钥匙没有所需 scope
test_key_readonly403dlt_test_… 试图写入
invalid_request400body 不是 JSON 或校验失败;细节在 errors[]
idempotency_key_required400创建订单没有 Idempotency-Key(8–255 字符)
idempotency_key_conflict409同一幂等钥匙,不同 body
rate_limited429每分钟配额;遵守 Retry-After 以及 RateLimit-Limit / RateLimit-Remaining / RateLimit-Reset
not_found404GET /orders/{id}对这把钥匙没有这张订单(别人的 id 回答相同)
tenant_not_found404钥匙的公司已不存在
venue_not_configured409报价,而公司没有地点坐标
shop_closed409已设营业时间且店现在关门
shop_unconfigured409没有为 Stripe 返回 URL 保存的店铺 origin
connect_not_ready409Connect 账户还不能收款
duplicate_external_ref409这个 externalRef 已经为这家公司创建过订单
line_price_missing / line_name_missing / total_out_of_range400一行或合计无法计价
idempotency_unavailable503幂等存储宕了;用同一把钥匙重试

限额按钥匙,60 秒窗口。写入(创建订单、报价)和读取(菜单、GET 订单)有分开的配额,免得轮询吃掉整个晚上。

只有整 grosz。3000 是 30.00 兹罗提。没有浮点,金额上没有货币字段。响应里的 currency 是常量 "PLN"

GET /api/v1/menu

钥匙所属公司的目录。Scope catalog:read。不可用条目被省略 — DTO 没有给客户端遵守的 available 标志。形状冻结。

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

空的分类和条目数组是有效响应,不是错误。Cache-Control: no-store

POST /api/v1/checkout

店铺购物车。Scope checkout:create(可发布钥匙)。顾客发送是什么,从不发送多少钱{ items: [{ itemId, quantity }] }。价格、附加费和合计由 Delieta 按钥匙所属公司目录、以整 grosz PLN 计算。body 里的 unitPrice / total / companyId 被忽略。成功和取消 URL 来自租户上的店铺配置,从不来自请求。

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

201

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

把客人重定向到 url。未知或不可用条目 → 422 unprocessable。关门 → 409 shop_closed。缺少店铺 origin → 409 shop_unconfigured。Connect 账户未就绪 → 409 connect_not_ready(没有假支付)。

POST /api/v1/quotes

订单存在之前的路程估计。Scope eta:quote。起点是公司地点;你只发送目的地。结果永远是区间(minMinutes / maxMinutes)。guaranteed 字段是常量 false — 这不是 SLA。expiresAt 之后再问。

{ "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"
  }
}

两端都展示。合作方 UI 里一个数字是对契约撒谎。缺少地点坐标 → 409 venue_not_configured。坏 body → 400 invalid_request

POST /api/v1/orders

为钥匙所属公司创建订单。Scope orders:write。服务器加总各行并拒绝你送来的合计。今天单价可以来自调用方(pricingSource: "caller");当计价来自目录时,响应会说 "catalog"

Idempotency-Key

必填头,trim 后 8–255 字符。每个逻辑尝试一把钥匙。网络错误或 503 idempotency_unavailable 后用同一钥匙和同一 body 重试。成功的 201 被冻结:重复返回同一信封和 Idempotent-Replayed: true。同一钥匙、不同 body → 409 idempotency_key_conflict

Body

没有租户字段。带调用方计价的典型调用:

{
  "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"
}
字段必填备注
customerName1–200 字符
customerPhone1–40 字符
destinationAddress1–500 字符
destinationPoint{ lat, lng } WGS84
items1–50 行;qty 1–99
items[].name / items[].unitPricewith caller pricinggrosz;服务器重算 totalGrosze
items[].menuItemId从菜单计价时的目录 id
paymentMethodcash | card | online (默认 cash
channelphone | web | pos | integration (默认 web
externalRef你这边去重;冲突 → duplicate_external_ref
POST /api/v1/orders
Authorization: Bearer dlt_live_…
Content-Type: application/json
Idempotency-Key: ord-2026-08-26-storefront-42

201

{
  "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"
  }
}

statusacceptedpending_acceptance,取决于公司接受模式。trackingUrl 是你给顾客的。那是唯一的公开跟踪 URL。

GET /api/v1/orders/

读取钥匙所属公司拥有的一张订单。scope 相同:orders:write — scope 集合已关闭并已发到活钥匙上;新的 orders:read 会弄坏现有集成。轮询花的是读取配额,不是创建。

id 是 201 响应里的 order.id。别人的或不存在的 id → 404 not_found,没有存在神谕。

响应比创建信封更窄。合作方拿到生命周期,不是内部列:

{
  "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
  }
}

acceptedAtrejectedAtacceptanceDeadlineAt 是 unix 毫秒或 null。你会看到的状态:pending_acceptanceacceptedpreparingon_the_waydeliveredrejected

OpenAPI

GET /api/v1/openapi

公开 OpenAPI 3.1 文档。不想手写 curl 时从它生成客户端。本页与它保持一致 — 若漂移,OpenAPI 和仓库测试赢。

没有 webhook 操作。你在这里用 GET 读状态。见 Webhook