> ## Documentation Index
> Fetch the complete documentation index at: https://docs.maple.inc/llms.txt
> Use this file to discover all available pages before exploring further.

# 预订生命周期

> 预订状态、客人与场所的权限、提供方的限制，以及实时楼面。

预订是一组客人在某个门店的用餐安排。其 `status` 记录生命周期；`service_state` 是另一项独立的前厅细节，可能为 `null`。请使用生命周期动作接口，而不要直接写入这两个字段中的任何一个。

## 状态与权限

| 状态 | 含义 |
| - | - |
| `requested` | 场所必须接受或拒绝该请求 |
| `confirmed` | 预订已被接受 |
| `seated` | 客人已入座 |
| `completed` | 服务已结束 |
| `declined_by_venue` | 场所拒绝了该请求 |
| `cancelled_by_guest` | 客人，或代表客人操作的合作伙伴，取消了预订 |
| `cancelled_by_venue` | 场所取消了预订 |
| `cancelled_unattributed` | 提供方报告了取消，但未指明操作方 |
| `no_show` | 客人未到店 |

`bookings:write` 授权保留（hold）、创建、变更以及客人一侧的取消。它不授权场所操作、场所一侧的取消或散客入座。拥有 `bookings:read` 的应用可以读取其已获授权门店的所有预订，而不仅仅是它自己创建的预订。场所内部备注绝不会包含在内。

## 代表场所操作

这些接口需要 **`bookings:manage`** 和门店授权：

| `/v1/bookings/{id}` 的接口后缀 | 合法的状态转换 |
| - | - |
| `/confirm` | `requested` → `confirmed` |
| `/decline` | `requested` → `declined_by_venue` |
| `/seat` | `confirmed` → `seated` |
| `/complete` | `seated` → `completed` |
| `/no_show` | `confirmed` → `no_show` |

发送 `POST`，请求体为 `{}` 或 `{ "expected_version": 3 }`。每个响应都是更新后的完整预订。版本过期会返回 `409 stale_version`；非法的状态转换会返回 `409 illegal_transition`，并带有 `details.from_status`。审计记录会在 `api_partner` 渠道上记录代表场所操作的应用。客户端无法自行选择操作者，也无法提升 `bookings:write` 请求的权限。

OpenTable 不支持这些场所回写操作，会返回 `422 capability_unsupported`；在提供场所操作之前，请先检查该门店 profile 中的能力。Resy 和 SevenRooms 不属于提供服务的预订网关。

### 以场所身份取消

`POST /v1/bookings/{id}/venue_cancel`（`bookings:manage`）代表场所取消处于 `requested` 或 `confirmed` 的预订，并将其返回为 `cancelled_by_venue`，适用于迎宾台和 POS 应用。`POST /v1/bookings/{id}/cancel`（`bookings:write`）是客人的取消，无论应用持有哪些权限范围，结果始终是 `cancelled_by_guest`。

```json theme={null}
{ "expected_version": 1, "idempotency_key": "<unique cancellation key>" }
```

客人的取消时限不适用于场所。版本过期会返回 `409 stale_version`；已经入座或已结束的预订会返回 `409 not_cancellable`，并带有 `details.reason`。该 key 的有效范围是您的应用，因此在响应丢失后重试会重放该取消操作。目前仅适用于 Maple 原生预订：其他预订会返回 `422 capability_unsupported`。

### 安排散客入座

`POST /v1/locations/{locationId}/walk_ins`（`bookings:manage`）安排刚到店的一组客人入座，并返回新的预订，其中 `status: "seated"`、`channel: "walk_in"`：

```json theme={null}
{
  "party_size": 2,
  "guest": { "first_name": "Alex", "last_name": "Quinn", "phone": "+12125551234" },
  "notes": "High chair",
  "idempotency_key": "<unique walk-in key>"
}
```

Maple 会像场所自己的迎宾台一样，选择当前最早能容纳这组客人的桌位；不存在强制预订。当没有空闲桌位时，请求会返回 `409 slot_unavailable`，其消息会指明下一个空位；请改为把这组客人加入[候位](/zh/developer-api/guides/run-the-waitlist)。`phone` 必须是 Maple 可以发短信的号码。该 key 的有效范围是您的应用及其所有门店：使用相同 key 和相同请求重试会返回同一条预订，即使其桌位现在已被占用；相同的 key 搭配不同的请求或门店，则会返回 `409 idempotency_key_reused`。仅限 Maple 原生门店（否则返回 `422 capability_unsupported`）。

## 读取实时楼面

`GET /v1/locations/{locationId}/booking_floor` 需要 `bookings:read`，仅适用于已启用且已编写布局几何信息的 Maple 原生门店。

响应包含 `as_of`、`time_zone`、`tables`、`areas` 和 `summary`。桌位报告其当前状态（`free`、`reserved`、`held`、`seated` 或 `maintenance`）、在 `current` 中占用该桌的客人，以及在 `next` 中未来 24 小时内的下一次占用。

* 未来的预订不会使桌位当前处于占用状态：它可以是 `free`，同时 `next` 不为 null。
* `current.guest` 包含分开的名和姓以及 `phone_last_four`，绝不包含完整电话或场所备注。需要时请通过 `booking_id` 读取该预订。
* 保留（hold）没有预订 ID。其 `booking_id` 为 `null`；内部的保留 ID 不会在楼面中暴露。
* 当已入座的客人超过其计划用餐时长仍未离开时，`ends_at` 为 `null`；API 不承诺其离开的时间。
* `listed: false` 表示某个已被占用的桌位在从当前布局中移除后仍然可见。这类客人会计入 `off_plan_parties`。
* 当座位上下限或区域容量未知时为 `null`。组合桌的客人在区域占用中只计一次，而不是每张桌子各计一次。

请按需读取，或以**至少 15 秒**的间隔轮询。请把[预订 webhook](/zh/developer-api/webhook-events) 作为变化信号，把楼面作为对账读取。此版本没有楼面 webhook。散客队列有自己的接口；请参阅[运行候位](/zh/developer-api/guides/run-the-waitlist)。

## 事件描述变化，载荷描述分发时的状态

每次预订状态转换，对每个接收方的应用/环境都有各自稳定的事件标识。嵌入的预订是该事件首次为该接收方记录时的最新状态，而不是历史状态转换的快照。例如，延迟的 `booking.created` 事件中嵌入的预订可能已经被取消。在此版本中，`previous_status` 为 `null`。

请按事件 ID 对投递去重。请按 `id` 和 `version` 对账预订状态；不要仅凭事件名称推断历史状态，也不要假定投递顺序。


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.