Skip to content

Idempotency and retries

A request can time out after the link is created but before the response arrives. The Idempotency-Key header makes it safe to send the request again.

POST /personal-links needs an Idempotency-Key header of up to 255 characters. Use a value that is unique to what the request does, and use the same value for every retry of that request.

For a personal link, build the key from the occasion and the player, such as birthday-2026:player-123. If a journey runs twice for the same player, it sends the same key, and the player gets one link.

POST /reward-store-orders also needs an Idempotency-Key header. Build it from your own order, such as shop-order-58213. Then a retry never places a second order or takes the player’s coins twice. For more information, see Rewards stores.

POST /v1/personal-links
Authorization: Bearer lxr_live_…
Idempotency-Key: birthday-2026:player-123
Content-Type: application/json

The following table shows how the API responds:

Request Response
New key The request runs. A 2xx response is stored.
Same key, same request, after a 2xx The stored response is replayed with Idempotent-Replayed: true. Nothing runs twice.
Same key, different request, after a 2xx 422 idempotency_key_reused. Nothing runs.
Same key, same request, while the first is still running 409 idempotency_request_in_progress. Retry in a few seconds.
No key 400 idempotency_key_required. Nothing runs.
Key longer than 255 characters 400 idempotency_key_invalid. Nothing runs.

The following rules also apply:

  • Same request means the same method, path, query, and JSON body content. The order of keys and the whitespace in the body don’t matter. A changed value, an added field, or a removed field makes it a different request.
  • Scope. An idempotency key belongs to one API key. Two API keys can use the same value.
  • Retention. Idempotency keys are kept for 7 days. After that, the same idempotency key runs as a new request. A personal link that you send again with it is a second link.
  • Stored responses. Only 2xx responses are stored. If a request returns 4xx or 5xx, or never arrives, a retry with the same key runs again. For example, if a link is refused because the campaign isn’t active, you can send it again with the same key after the cause is fixed.

The following calls don’t need an Idempotency-Key header:

Call Idempotency-Key
POST /personal-links/{linkId}:cancel Optional. You can repeat the call safely without a key: canceling a link that is already CANCELLED returns 200 and changes nothing. If you send a key, the rules on this page apply, and a retry with it replays the first response.
POST /webhooks:test Ignored. Every call sends a real test event, so a retry after you fix your receiver shows its new response.

If a request to create a link times out, do the following:

  1. Send the request again with the same key and the same body. You can rebuild the JSON if the values are the same.
  2. If the first request created the link, the retry returns the same 201 response and link, with Idempotent-Replayed: true. No second link is created.
  3. If the first request didn’t create the link, the retry creates it.

Use the following table to decide whether to retry:

Response Retry
Timeout or connection error Yes, with the same key and body.
429 rate_limited Yes, after the number of seconds in the Retry-After header.
409 idempotency_request_in_progress Yes, with the same key and body, after a few seconds.
5xx Yes, with the same key and body. Wait longer between retries: 1 second, 2 seconds, 4 seconds, up to a minute.
Other 4xx Not as it is. Fix the request or its cause first. You can use the same key again, because a refusal isn’t stored.

GET requests need no idempotency key, and you can always retry them safely.