Skip to main content
这是 Maple 集成的核心。当顾客在您已连接的门店下单时,Maple 会把订单推送到您的 webhook;由您决定是否履行订单,并在订单推进时回报进度。整个流程不涉及支付,支付由 Maple 负责。 一个可用的订单集成包含两部分工作: 如果还没看过,请先浏览 Maple 如何运作 了解对象模型,并运行 快速入门 获取密钥并连接一个测试门店。

步骤 1:连接门店

只有当您的应用成为某个门店的已连接接收方后,订单才会路由给您:
每个环境下的连接是独占的:如果其他应用已占用该门店,您会收到 409。对同一路径使用 GET 和 DELETE 可以查看和移除您的连接。

步骤 2:订阅 webhook

注册一个 HTTPS 端点以及您需要的事件类型。完整目录见 GET /v1/webhook_event_types;订单流程通常需要以下事件:
响应中包含一个一次性签名密钥(mwhsec_…)。请妥善保存,它不会再次显示。URL 必须是公开的 HTTPS 地址,私有和内部地址会被拒绝。
以上是订单相关事件。目录中还包括 order.created、order.paid、store.provisioned、 store.deprovisioned、store.status.changed 以及菜单同步事件。只订阅您会处理的事件。完整列表和负载请见 Webhooks。

步骤 3:验证每一次推送

每次推送都是 Stripe 风格的信封:
每次推送带有两个请求头:maple-webhook-id(事件 ID)和 maple-webhook-signature,格式为 t=<unix_seconds>,v1=<hex_hmac>。被签名的字符串是 {timestamp}.{subscription_id}.{notification_url}.{raw_body}。请对原始、未解析的请求体进行验证:
上面的检查会拒绝过期的时间戳(超过约 5 分钟),以防重放。除此之外,请按信封中的 id 去重,因为推送保证至少送达一次。完整的可靠性约定,包括重试计划和事件记录,见Webhooks。

停机后补齐订单

如果您的接收端曾不可用(本地软件关闭或网络中断),请按以下步骤对账:
  1. 使用您上一次成功的检查点调用 GET /v1/orders?since=<timestamp>&limit=100(不含该时间点,ISO 8601 UTC)。使用 since 时,结果按从旧到新排序,has_more 表示还有下一页。
  2. 当 has_more 为 true 时,把 starting_after 设为上一页最后一个订单 ID 并重复请求。直到积压处理完毕,再推进您的检查点。
  3. 当您需要 Maple 为某个错过 webhook 的有效订单重新发布一条 order.notification 时,调用 POST /v1/orders/{orderId}/resend。它需要 webhooks:write 权限范围,会创建一次新的、已签名且带重试的推送,并且不会改变订单状态。终态订单(REJECTED、CUSTOMER_CANCELLED 或 STORE_CANCELLED)无法重发或恢复,会返回 400;请通过 GET /v1/orders?since=... 和 GET /v1/orders/{orderId} 对账。
  4. 如果需要保留原始事件身份,请使用事件记录,而不是 resend。
对于短时间的中断,等待也可以:重试计划会在大约 10 小时内重新投递失败的事件,之后才算彻底失败。
在有真实流量之前,POST /v1/webhook_subscriptions/{id}/test 会发送一条已签名的 webhook.test 事件, 让您验证处理程序能否正确验签并响应。

步骤 4:读取订单

order.notification 负载中的 data 是订单内容,包括 ID、顾客、商品明细和合计,因此您可以直接根据 webhook 开始备餐,无需再次调用。它遵循 GET /v1/orders/{orderId} 的结构,但不含实时的 status 和 payment。您可以随时获取订单资源,以得到权威的当前状态,包括 status 和 payment:
请务必牢记以下几点:
  • 金额是以美分为单位的整数(USD)。 450 即 $4.50。切勿将其解析为浮点数。totals 和商品明细中的所有金额都遵循这一约定。
  • 合计已预先计算。 totals.total 是权威值,您无需重新计价。
  • 商品明细通过 menu_entity_id 引用您的菜单,其值是您为该菜品发布的 externalId。先发布菜单,这些值就能与您自己的商品目录对应。(菜单负载使用 camelCase;订单和 webhook 负载使用 snake_case,见约定。)
  • 加料选项(modifier)是直接选择的第一级选项。 更深层嵌套的选项在 v1 中不会展开到订单资源里。
  • 顾客数据刻意保持精简。 您会得到顾客的姓名和电话号码(phone 为 E.164 格式,另有 phone_last_four 用于显示)。外送订单还包含 delivery_address,内有街道、单元、城市、州、邮编和配送说明;自取订单或 Maple 没有已存地址时,其值为 null。只要该块有内容,六个地址键就都会存在。
  • 出单前先检查 scheduled_for。 ASAP 订单该值为 null。有值时(ISO 8601,UTC),表示顾客选定了取餐/送达时间;您会立即收到订单,因此应按 scheduled_for 安排备餐,而不是在收到订单时就开始。

步骤 5:做出决定并回报进度

随着订单推进,通过决定端点作出响应。除特别说明外,都不需要请求体:
Response
如果您更喜欢使用单个端点,POST /v1/orders/{orderId}/status 接受明确的状态转换:
有效值:ACCEPTED、READY、IN_DELIVERY、FULFILLED、REJECTED、STORE_CANCELLED。各状态的含义及合法的状态转换,请参阅订单生命周期。
决定调用可安全重放。 重复调用会返回 { "status": "received" },不会产生重复的副作用,因此遇到网络波动时随时可以放心重试。见幂等性与重放安全。

可选:预先验证订单

预先验证是可选的,通过订阅 order.validation_requested 来开启:
  • 如果您不订阅,就没有验证步骤。Maple 直接发送 order.notification,您的 accept/deny 是唯一的关卡。
  • 如果您订阅,Maple 会在发送通知之前,请您确认每笔订单是否可履行(菜品供应、价格可行性、能否写入 POS),并等待您的答复。因此选择启用就是一项承诺:您未及时验证的订单会被拒绝(见下文)。
机制就是这些:订阅即开关。 订阅后,请对每个 order.validation_requested 回复结果:
若要阻止该订单:
valid 结果会让订单继续进入通知阶段;invalid 会在向顾客收款之前拦下订单。您有约 5 分钟的时间答复,请求随后过期(资源中带有 expires_at,约 300 秒后)。如果过期,Maple 会再请求一次验证;若第二次请求仍无答复,订单会被拒绝且不发送通知,因此请在您的处理程序能够可靠地按时答复之后再订阅。这与您在接单时进行的可用性检查相同,只是提前了,这样顾客就不会为您做不出的东西付款。

“完成”是什么样子

一个 webhook 加上少量决定调用。支付和定价由我们负责,Maple 团队在您的整个构建过程中都会提供支持。

下一步

发布菜单

让每个商品明细上的 menu_entity_id 都对应到您自己的商品目录。

深入了解 Webhooks

投递保证、重试、事件记录和重放。