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

# Idempotency and replay safety

> How Maple makes retries safe without an idempotency key — replay-safe decisions, diff-applied menus, idempotent replay, and dedupe on your side.

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.

<Note>
  There is **no `Idempotency-Key` header** on this API. You don't generate or send idempotency keys. Safety is a
  property of each operation, described below — not something you opt into per request.
</Note>

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

```json theme={null}
{ "object": "order_decision", "order_id": "ord_...", "decision": "accept", "status": "received" }
```

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 `externalId`s:

* 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](/developer-api/guides/publish-menu).

## 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`:

```ts theme={null}
async function handleEvent(event: { id: string; type: string; data: unknown }) {
  if (await alreadyProcessed(event.id)) return; // no-op on a repeat
  await process(event);
  await markProcessed(event.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](/developer-api/concepts/webhooks#delivery-guarantees).

## Summary

| Operation          | Safe to retry? | Why                                                          |
| ------------------ | -------------- | ------------------------------------------------------------ |
| Order decisions    | Yes            | Replay-safe; repeats return `received` with no double effect |
| Menu publish       | Yes            | Diff-applied; identical re-publish is a no-op                |
| Event replay       | Yes            | Skips subscriptions already delivered to                     |
| Receiving webhooks | You dedupe     | At-least-once delivery — dedupe on event `id`                |
