Idempotency
Retry safely without creating duplicate reward obligations.
An idempotency key identifies one intended write. Create it once, persist it with the original instruction, and reuse it for every retry of that write.
Slices requires Idempotency-Key on reward issuance and cancellation. The SDK accepts idempotencyKey in the method input and sends the header for you.
Key format and scope#
A key must contain 8–128 letters, digits, periods, underscores, colons, or hyphens. Opaque internal identifiers are appropriate; emails, names, and other personal information are not.
Keys are scoped to the project, environment, and operation. Use a distinct key for each intended cancellation and each intended issuance. Financial deduplication records remain for the lifetime of the associated economic records; there is no documented 24-hour window after which resending a reward becomes safe as a new payment.
Issuance behavior#
| Request | Result |
|---|---|
| New key and valid instruction | 201; one durable reward and one capacity reservation. |
| Same key and same semantic instruction | 200; original reward's current resource, with Idempotency-Replayed: true. |
| Same key and different instruction | 409 IDEMPOTENCY_CONFLICT; no second grant. |
| New key but existing campaign/event-type/event-ID tuple | 409 DUPLICATE_EVENT; no second grant. |
Wallet normalization and JSON key ordering do not create a different economic instruction. Event strings remain case-sensitive; Slices does not lower-case or reinterpret them.
A reliable partner-side workflow#
Persist the exact instruction, environment, and key in your own database when your backend decides the user earned a reward. A transactional outbox is a useful implementation pattern: commit the business decision and pending Slices instruction together, then send from a worker.
After acceptance, store the reward ID on that same record. If the process crashes between API acceptance and local persistence, the worker resends the original instruction with the same key and obtains the existing reward.
Do not recalculate token amounts during retries. A changed price, policy, or destination can turn the replay into a conflict. Persist the amount and wallet selected for the original decision.
Recover after a timeout#
A timeout does not establish whether Slices committed the request. Resend with the same key and body, or search your rewards by campaign and event ID. If you search by event ID, inspect event.type as well: uniqueness uses both fields.
If DUPLICATE_EVENT includes existingRewardId, retrieve that reward and compare its immutable fields before recording it as your expected instruction. Do not blindly treat every conflict as success.
Pauses, revoked keys, and rejected requests#
An accepted issuance can be replayed even if its campaign is now paused or has exhausted capacity. Authorization is still required: revoked or insufficiently scoped keys do not bypass access checks.
A validation or budget failure that committed no grant does not consume the key. After resolving the condition, resend the original intended allocation. Do not mistake a server error for confirmation that nothing was committed.
Cancelled rewards remain deduplicated#
Cancellation does not erase the event identity or permit it to be issued again under a fresh key. A deliberately authorized correction must use a new, explicit event identity in your system, with its relationship to the original recorded outside this strict request schema.
Related: Events and qualification, Cancel a reward, and Rate limits and retries.