Skip to main content
Networks fail mid-request. The question that matters is: if you retry, will something happen twice? With Maple, the writes you’ll retry most are built to be safe to repeat — so you can retry on a timeout without reconciling first.
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:
If you send 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 your externalIds:
  • 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 400 changes nothing, so a failed publish leaves the menu exactly as it was.
So if a publish times out, re-sending the same document is safe. See Publish a menu.

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 booking back, and nothing is booked, moved, or cancelled twice.
  • The same key with a different request (a different guest, slot, or note) answers 409 with code: "idempotency_key_reused". Generate a fresh key per intended write; a UUID is fine.
A retry returns the same booking identity without reapplying the mutation; the response is read back from the current booking. Keys have a 24-hour replay window from the first claim. Replays are checked before 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 returns 409 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.
An unresolved pending key is not recycled when its 24-hour automatic replay window ends. If details.reason is replay_window_expired, stop automatic retries and contact Maple with details.operation_id. Do not generate a new key to work around an uncertain result.
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 envelope id:
Make the work itself idempotent where you can — for example, key your own order records by Maple’s 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.

Summary