Idempotency
Send a write again after a network failure without risking a duplicate, with the Idempotency-Key header.
API documentationGuides · Idempotency
The problem
A write request goes out, the connection drops, no response comes back. Did the write happen? Without precautions, sending it again may create a second contact, redeem a promo code twice or publish two replies.
The Idempotency-Key header solves this: a request sent again with the same idempotency key runs only once, and every attempt receives the same response.
Use an idempotency key
Pick a unique value per business operation, for instance a UUID or the operation's identifier in your tool, and keep it for every new attempt of that same operation:
curl https://api.mabellenote.com/v1/promo-codes/redeem \
-H "Authorization: Bearer $MBN_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: till-1-ticket-2026-10-25-0042" \
-d '{ "code": "BIS-7KQ4", "establishmentId": "kh2n8p5r3t6v9b1c4d7f0g2j5k8m1n3p", "amountCents": 4850 }'
- The key has 1 to 255 characters. Outside these bounds, the API answers
400 invalid_request. - It is specific to the API key: two API keys can use the same value without interfering.
- It is kept for 24 hours after its first use. Beyond that, the same value starts afresh.
What the API answers
| Situation | Response |
|---|---|
| First request with this key | Runs normally. |
| Same key, same request, already completed | The original response, replayed, with Idempotent-Replayed: true. |
| Same key, same request, still running | 409 idempotency_in_progress: try again a little later. |
| Same key, different request (other method, path or body) | 422 idempotency_key_reused. |
A request refused with an error, for instance 400, 404 or 409 promo_code_already_redeemed, does not keep its key: once fixed, sending it again with the same key runs it again. Only successful responses are replayed.
Operations concerned
| Operation | Idempotency-Key |
|---|---|
POST /v1/contacts | Optional |
PATCH /v1/contacts/{contactId} | Optional |
POST /v1/visits | Optional |
POST /v1/promo-codes/redeem | Optional |
POST /v1/reviews/{reviewId}/reply-drafts | Optional |
PUT /v1/reviews/{reviewId}/reply-draft | Optional |
POST /v1/reviews/{reviewId}/reply | Required |
Reads do not need it: they change nothing. POST /v1/webhook-endpoints does not accept it, because its response contains the signing secret, which must not be stored.
Special cases
- Visits: on top of the header, a visit is unique per
externalIdwithin a location. Sending the same ticket number twice only creates one visit, even withoutIdempotency-Key: the first response is201, the following ones200. - AI-written drafts: the generation does not happen in the same transaction as the key record. The guarantee is therefore “at most one generation per completed idempotency key”: a request interrupted mid-computation may, rarely, use a generation without a response.
- Publishing on Google: the key is required, so that a replayed call never publishes twice. Use the review identifier, or the reply's identifier in your tool.
Good practices
- Generate the key before the first attempt, and keep it with the operation until you get a response.
- Retry with the same key on a network error, a timeout,
409 idempotency_in_progress,429 rate_limitedor503 service_unavailable, respectingRetry-After. - Never reuse a key for another operation: you would get
422 idempotency_key_reused, or worse, the response of another operation if the bodies are identical.
Updated on October 25, 2026

