There is no
Idempotency-Key header on this API. For orders, menus, and events, safety is a property of each
operation, described below — not something you opt into per request. The one place you do send a key is
booking and waitlist writes, which take a body-level idempotency_key (see below).Order decisions are replay-safe
Repeating an order decision —accept, deny, ready, complete, cancel, or status — returns the same acknowledgement without applying the side effect twice:
accept and the response times out, send it again. The order is accepted exactly once, and you get { "status": "received" } either way. This makes a simple retry-on-transient-error loop correct without any bookkeeping on your side.
Publishing a menu is a diff
A menu publish describes the desired state of the whole menu and is applied as a diff against what’s currently published, keyed by yourexternalIds:
- Re-publishing an identical document is a no-op.
- Object identities stay stable across publishes by
externalId, so republishing doesn’t recreate or churn objects. - Validation is all-or-nothing — a
400changes nothing, so a failed publish leaves the menu exactly as it was.
Booking writes carry an idempotency_key
Creating, changing, or cancelling a booking (POST /v1/bookings, POST /v1/bookings/{id}/change, POST /v1/bookings/{id}/cancel), cancelling one as the venue (POST /v1/bookings/{id}/venue_cancel), and seating a walk-in (POST /v1/locations/{locationId}/walk_ins) require an idempotency_key in the body, scoped to your app. Walk-in keys, like waitlist joins, are your app’s across all its locations. Keys must contain 1–255 characters. For Maple-native bookings, the ledger records the write and its replay outcome in one transaction:
- Retrying with the same key and the same request replays the original outcome — you get the same
bookingback, and nothing is booked, moved, or cancelled twice. - The same key with a different request (a different guest, slot, or note) answers
409withcode: "idempotency_key_reused". Generate a fresh key per intended write; a UUID is fine.
expected_version, which will often be stale after the original write succeeds.
Native and provider holds are persisted and owned by the app that acquired them. Repeating the same slot_token replays the app’s live hold without taking another lock. Another app cannot consume or release it, even at a jointly granted location. Unknown provider holds release their quota reservation after a conservative 24-hour inactivity quarantine, independently of their retained audit record; expired operations cannot be revived by retrying.
Provider-backed writes
For OpenTable, Maple durably claims the key and request digest before provider I/O and uses one stable provider request ID. A pending change or cancellation also reserves the mirrored booking against other partner writes. On success, Maple records the mirror and replay outcome together. Transient mirror failures are retried synchronously; a background reconciler repairs outstanding work. A provider timeout returns409 operation_in_progress while the outcome is unresolved. Retry the same request and key after details.retry_after seconds. Maple performs a reconciliation read before repeating a booking write with the original provider request ID. Completed writes replay without calling the provider again.
Booking configuration uses content-addressed publication instead: identical configuration is a no-op without an explicit key. The status venue verbs (confirm, decline, seat, complete, no-show) take expected_version, not an idempotency key; after an ambiguous response, read the booking before taking another action. Venue-side cancellation and walk-ins do take an idempotency_key, scoped to your app like every other key.
Replaying an event is idempotent
POST /v1/webhook_events/{eventId}/replay re-delivers an event only to subscriptions that haven’t already received it. Subscriptions that already got it are skipped, so replaying after an outage won’t double-deliver to healthy endpoints.
Your side: dedupe deliveries
The one place you must add idempotency is your webhook handler. Delivery is at-least-once, so the same event can arrive more than once. Dedupe on the envelopeid:
order_id so a duplicate order.notification updates rather than duplicates. Don’t rely on event ordering; reconcile against GET /v1/orders/{orderId} when sequence matters. See Webhooks.