跳转到内容
Maple

API 参考

Webhook 事件类型目录,以及每种事件携带的载荷。

每个 webhook 都以相同的签名信封投递;只有 data 会随 type 不同而变化。本页介绍每一种事件类型。有关签名、投递、重试和重放,请参阅Webhooks。

订单事件

订单 webhook 分为两类,分清两者是用好它们的关键:

  • order.notification 是您据以履约的事件。 它把订单内容交给您处理,在交接时触发一次,其投递被视为关键投递。请围绕它构建您的接受 / 拒绝 / 备好 / 完成流程。
  • order.created、order.paid 和 order.cancelled 是生命周期事件。 每个事件以摘要数据报告订单生命中的一个时刻,用于知悉和对账。由于 order.notification 只触发一次且不会更新,您要通过这些事件了解该快照之前或之后发生的事情,最重要的是取消,或稍后才完成的支付。

有关这些事件在一笔订单的整个生命周期中的触发顺序,请参阅Webhook 何时触发。

类型 触发时机 订阅它的目的 data
order.validation_requested 在通知之前,Maple 请您确认订单可以履约(仅当您订阅时) 在向顾客收款之前预先校验可售状态和价格 完整订单内容(与 order.notification 结构相同),另加 validation_id
order.notification 订单在校验和支付把关之后交给您履约 接收并履约订单,集成的核心 完整订单内容(见下文)
order.created 订单创建时,早于通知,且内容比通知更精简 为分析镜像新订单;发现从未到达您的订单(例如在校验阶段被拒绝) order_id、location_id、status、total、items、created_at
order.paid 支付完成,可能发生在交接_之后_(到店付款、链接支付) 无需轮询即可对账支付 order_id、location_id、status、amount、payment_method、payment_source
order.cancelled 顾客或门店取消,通常发生在您收到通知_之后_ 停止履约已取消的订单 order_id、location_id、status、reason

我应该订阅哪些订单事件?

  • 履约订单(POS 系统): 订阅 order.notification 和 order.cancelled,接收订单,并在订单被取消时停止。如果您需要预先校验,再加上 order.validation_requested。
  • 报表或对账(OMS、控制台、分析): 还需订阅 order.created 和 order.paid,以镜像订单和支付的生命周期。

order.notification 载荷

order.notification(以及 order.validation_requested)在 data 中携带订单内容,足以开始履约。它与订单资源使用相同的字段名和以整数美分表示的金额,但对象更小,包含以下键(与所有载荷一样,请忽略您不认识的键):

{
"order_id": "ord_...",
"location_id": "str_...",
"fulfillment_type": "delivery",
"scheduled_for": null,
"delivery_address": {
"street": "123 Main Street",
"unit": "Apt 4B",
"city": "New York",
"state": "NY",
"zip": "10001",
"notes": "Leave at the side door"
},
"customer": { "name": "Alex", "phone": "+14155551234", "phone_last_four": "1234" },
"line_items": [
{
"name": "Latte",
"menu_entity_id": "itm-latte",
"quantity": 1,
"base_price": 450,
"modifiers": [{ "name": "Oat milk", "menu_entity_id": "mod-oat", "quantity": 1, "price": 75 }]
}
],
"totals": { "currency": "USD", "subtotal": 525, "tax": 42, "surcharge": 0, "tip": 0, "delivery_fee": 599, "delivery_tip": 0, "total": 1166 }
}

order.validation_requested 携带相同的 data,另加一个 validation_id。请在您的 POST /v1/orders/{orderId}/validation_result 中原样回传它,使结果与本次尝试绑定;针对已过期或更早尝试的结果会被拒绝。参见接收订单。

这是订单的内容,而非实时状态,其中没有 status 或 payment。如需权威的当前状态(状态、支付、每项税额、时间戳),请获取 GET /v1/orders/{orderId}。生命周期事件只携带上面列出的摘要字段。

对于尽快(ASAP)订单,scheduled_for 为 null。如果有值(ISO 8601,UTC),则表示顾客选择了该取餐/配送时间。通知仍会立即到达,因此请按 scheduled_for 备餐,而不是在收到时就开始。

对于自取订单,以及没有存储地址的配送订单,delivery_address 为 null。存在时,六个键全部包含;notes 包含配送说明,unit 或 notes 可能为 null。

并非状态推送

Maple 不会为每一次状态变化发出 webhook。由您自己推动的状态变化(accept、ready、complete)不会回传,到达 IN_DELIVERY 或支付变为 refunded / voided / failed 也没有对应事件。请读取订单资源获取当前状态,参阅订单生命周期。

预订事件

预订事件会投递给每个已获授权访问该门店、其允许的权限范围包含 bookings:read 且订阅与事件类型匹配的活跃应用。它们不要求应用拥有 POS 连接。该门店的预订灰度发布开关必须已启用。

类型 报告的变化
booking.created 预订已创建,或首次从其提供方处观察到
booking.confirmed 请求已确认
booking.updated 预订已变更
booking.cancelled 预订已取消
booking.declined 请求已拒绝
booking.seated 客人已入座
booking.completed 服务已完成
booking.no_show 客人被标记为未到店

这八种事件使用相同的 data 结构。嵌入的 booking 与 GET 资源一致:

{
"location_id": "str_example",
"previous_status": null,
"booking": {
"object": "booking",
"id": "bkg_example",
"livemode": false,
"created": 1789063200,
"version": 1,
"location_id": "str_example",
"status": "confirmed",
"service_state": null,
"confirmation_code": "AB1234",
"starts_at": "2026-09-12T22:00:00.000Z",
"starts_at_local": "2026-09-12T18:00",
"service_date": "2026-09-12",
"duration_minutes": 90,
"party_size": 2,
"guest": { "first_name": "Alex", "last_name": "Quinn", "phone": "+12125551234", "phone_last_four": "1234", "email": null },
"notes": null,
"channel": "api_partner",
"provider": "maple",
"cancellation_policy": null,
"experience": null,
"updated_at": "2026-09-10T18:01:00.000Z"
}
}

载荷是首次分发时的最新预订状态,而不是该次状态变化的不可变快照。previous_status 为 null。因此,事件名称描述的变化可能早于嵌入预订的当前状态。某个接收方的事件一旦被记录,重试时会保持该载荷和事件标识不变。

每个原始 outbox 事件在每个应用/环境下都有稳定的标识。即使两次变更在同一预订版本上分发,对同一预订的两次变更仍然是各自独立的事件。请按事件 ID 去重,并按预订的 id/version 对账;不要依赖投递顺序。独立的开发者消费方不会推进宾客沟通游标。此版本不转发任何楼面事件;候位变化有自己的事件。

某个接收方入队失败,不会阻止其他符合条件的应用或订阅入队。重试会复用同一订阅的事件标识。预订事件的发布最多进行三次分发尝试,每次尝试都有有限次数的内部重试。格式错误的内部事件和已用尽分发尝试的事件会被保留,供运维人员排查,而不会阻塞后续事件或无限重试。这与 HTTP webhook 投递重试是两回事。投递出现缺口后,请使用 GET /v1/bookings?updated_since=… 对账当前预订状态。

候位事件

候位事件会送达与预订事件相同的应用:每个已获授权访问该门店、其允许的权限范围包含 bookings:read 且订阅与事件类型匹配的活跃应用。只要该门店的预订灰度发布开关已启用,Maple 原生门店就会发送这些事件。请参阅运行候位。

类型 报告的变化
waitlist_entry.created 一组客人加入候位
waitlist_entry.notified Maple 已发短信通知该组客人餐桌已备好
waitlist_entry.seated 该组客人已入座,生成一条散客(walk-in)预订
waitlist_entry.removed 客人自行离开(removed_by_guest),或店方将其移除(removed_by_venue)
waitlist_entry.expired 已通知的客人未在时限内回复

这五种事件使用相同的 data 结构。嵌入的 waitlist_entry 与 GET /v1/waitlist_entries/{entryId} 一致:

{
"location_id": "str_example",
"waitlist_entry": {
"object": "waitlist_entry",
"id": "bkw_example",
"livemode": false,
"created": 1789063200,
"location_id": "str_example",
"status": "seated",
"party_size": 2,
"position": null,
"quoted_wait": { "parties_ahead": 1, "wait_minutes": { "min": 15, "max": 30 } },
"joined_at": "2026-09-10T18:00:00.000Z",
"notified_at": "2026-09-10T18:20:00.000Z",
"booking_id": "bkg_example",
"channel": "api_partner",
"guest": { "first_name": "Alex", "last_name": "Quinn", "phone": "+12125551234", "phone_last_four": "1234", "email": null }
}
}

与预订事件一样,载荷是首次分发时的最新候位条目状态:在客人入座之后才送达的 waitlist_entry.created,显示的已经是 seated。请根据事件类型判断发生了什么,根据 waitlist_entry.status 判断条目当前所处的状态。每次变化在每个应用和环境下都有各自的事件 ID;请按事件 ID 去重,不要依赖投递顺序。投递尝试、重试以及格式错误内部事件的隔离,均遵循上述预订事件的规则。入座还会创建一条散客预订,该预订由您订阅的预订事件报告。

门店(location)事件

这些事件跟踪您对门店的访问权限,即连接生命周期:

类型 触发时机 data(示意)
store.provisioned 商户授予您的应用对某门店的访问权限 location_id
store.deprovisioned 授权被撤销;您已失去对该门店的访问权限 location_id
store.status.changed 您与某门店的连接发生变化 location_id、status(connected / disconnected)

菜单事件

类型 触发时机 data(示意)
menu.sync.completed 某门店的菜单同步完成 location_id
menu.sync.failed 某门店的菜单同步失败 location_id

请参阅发布菜单。

测试事件

webhook.test 通过 POST /v1/webhook_subscriptions/{id}/test 按需投递。请在任何真实流量到来之前用它验证您的处理程序。真实业务活动绝不会发出它。