> ## 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.

# Take bookings

> Discover a location, search availability, hold capacity, and create or change a booking.

Bookings use your app's **location grants**, not its POS connection. A booking integration can coexist with another app receiving orders at the same location. The surface rolls out per location; ask Maple to enable your test location first.

Set `MAPLE_BASE` to your environment's base URL, including `/v1`, and `MAPLE_KEY` to a matching credential. See [Environments](/developer-api/concepts/environments). You need `bookings:read` for discovery and reads, and `bookings:write` for holds and guest-side writes.

## 1. Read the booking profile

```bash theme={null}
curl "$MAPLE_BASE/locations/$LOCATION_ID/booking_profile" \
  -H "Authorization: Bearer $MAPLE_KEY"
```

Check `enabled`, `provider`, and `capabilities`. Native locations have a `hold_ttl_seconds` of 300 by default. Provider-managed locations report `null` because the provider owns expiry; always use the hold's `expires_at`.

## 2. Search availability

`start` and `end` are venue-local wall-clock times, not UTC instants. Choose a future window no longer than 31 days:

```bash theme={null}
curl --get "$MAPLE_BASE/locations/$LOCATION_ID/booking_availability" \
  -H "Authorization: Bearer $MAPLE_KEY" \
  --data-urlencode 'party_size=2' \
  --data-urlencode "start=${BOOKING_DATE}T18:00" \
  --data-urlencode "end=${BOOKING_DATE}T21:00"
```

Each `data` entry contains an opaque `slot_token`, `starts_at` in UTC, `starts_at_local`, and any quoted cancellation policy. Tokens expire after 15 minutes. Save the selected token unchanged; never reconstruct it from the displayed time.

A `422` is a business outcome, not an empty result: inspect `code` and `details` for party-size bounds, booking-window restrictions, or a large-party inquiry contact.

## 3. Hold the slot

```http theme={null}
POST /v1/booking_holds
Content-Type: application/json

{ "slot_token": "<selected slot_token>" }
```

Save `id` as the hold ID. The hold claims capacity until `expires_at`; create the booking before then. If the guest abandons the flow, release a native hold with `DELETE /v1/booking_holds/{holdId}`. A consumed hold answers `409 hold_consumed` instead of reporting that its capacity was released.

Each app may have **ten live holds per location**, enforced atomically across concurrent requests. Native and provider holds count, including provider acquisitions still awaiting an outcome. A different app cannot release or consume your hold, even if both apps are granted the location; those requests return `404`.

If a provider hold response is lost, its quota reservation has a conservative 24-hour quarantine after the last possible provider attempt. Once that deadline passes, it no longer consumes quota. The original operation stays recorded and cannot restart after its replay window; this does not clear an uncertain booking create/change/cancel operation.

All partner hold IDs use `bkh_…`. Repeating the same `slot_token` replays your live hold rather than acquiring another lock. OpenTable release remains a no-op: the provider lock and its quota usage remain until expiry or consumption. Check `booking_profile.capabilities.hold_release` before promising an early release.

## 4. Create the booking

```http theme={null}
POST /v1/bookings
Content-Type: application/json

{
  "hold_id": "<hold id>",
  "guest": {
    "first_name": "Alex",
    "last_name": "Quinn",
    "phone": "+12125551234",
    "email": "alex@example.com"
  },
  "notes": "Window table if possible",
  "idempotency_key": "<unique key for this write>"
}
```

The response is the full `booking` resource. At native locations, its initial status is `confirmed` or `requested`, according to the venue's acceptance policy. Save its `id` and `version`. Guest phone is required; the current service accepts dialable North American numbers.

The persisted hold supplies the authoritative quote for both native and provider-managed bookings. You can omit `slot_token`; it remains accepted as an optional field for existing integrations.

<Warning>
  A timeout or `409 operation_in_progress` does not mean the provider rejected the booking. Retry with the **same key and body**, never a new key. Maple records the pending command before provider I/O and reconciles uncertain results using the same provider request identity. If `details.reason` is `replay_window_expired`, stop automatic retries and contact Maple with `details.operation_id`. See [Replay safety](/developer-api/concepts/idempotency).
</Warning>

## 5. Change or cancel

For a native change, search again with `changing_booking_id=<booking id>`. This excludes the booking's current capacity claim. Send the chosen token to `POST /v1/bookings/{id}/change`, with a new `idempotency_key` and optionally `expected_version`.

Provider-managed locations reject `changing_booking_id` with `422 capability_unsupported`. Their direct-change path takes a token from an ordinary availability search instead. OpenTable supports time/party changes, but not guest-note changes or structured `intake_answers`; those fields return `422 capability_unsupported` rather than being silently dropped.

```http theme={null}
POST /v1/bookings/{bookingId}/cancel
Content-Type: application/json

{ "expected_version": 0, "idempotency_key": "<unique cancellation key>" }
```

A partner cancellation lands as `cancelled_by_guest`. A stale version answers `409 stale_version` with `details.expected` and `details.actual`. Provider-backed writes claim the mirrored booking before provider I/O; a competing write can answer `409 operation_in_progress` while that claim is active. A successful replay runs before the version check, so its original `expected_version` does not prevent replay.

Read the booking again before deciding whether to submit a different change. Cancellation and reschedule policy refusals include a `reason` in `details`. Version claims serialize writes through Maple; they do not lock out changes made directly in the provider's own tools.

## Request limits

The default per-app, per-environment budgets are **60 availability searches/minute** and **300 other booking requests/minute**. The budgets are independent and apply across granted locations. Existing order/menu routes are not included. A `429` includes both a `Retry-After` header and `retry_after` in its JSON body; wait before retrying. Maple can adjust these deployment-level budgets.

## Follow changes

Subscribe to [booking webhooks](/developer-api/webhook-events#booking-events). Use `GET /v1/bookings/{id}` for current state, or the [incremental list](/developer-api/api-reference#listing-bookings) to catch up after downtime. Venue operations and the live-floor read are described in [Booking lifecycle](/developer-api/concepts/booking-lifecycle).
