Idempotency and retry budgets
Make repeated requests safe with action identity, atomic result storage and retries that respect capacity and deadlines.
On this page
Before you start
- Business action identity
- A durable outcome store
- Destination retry semantics
A repeated activation request
The action key and request fingerprint resolve an uncertain outcome without scheduling another activation.
Scroll across the diagram to see all four systems.
POST + action key
Submit the activation with one identity for the intended business action.
Reserve key + fingerprint
Atomically establish ownership or find the previous outcome.
Execute permitted action
Send one authorized destination operation under its supported identity contract.
Record final outcome
Persist the business result and response representation.
Retry same request
Reuse the original action key after a lost response.
Return stored outcome
Replay the recorded result without scheduling another activation.
Identify the intended business action
A network request identifier identifies an attempt. An idempotency key identifies the business operation that repeated attempts should share. Scope the key to the authenticated tenant and operation so one tenant cannot collide with another’s work.
Store a canonical request fingerprint with the key. If the same key arrives with different meaningful input, return a conflict rather than treating the new body as the original request. Document which headers and fields contribute to the fingerprint.
POST /api/v1/campaign-activations HTTP/1.1
Host: api.example.test
Authorization: Bearer <access_token>
Idempotency-Key: tenant_a:campaign_19:revision_4
Content-Type: application/json
{
"campaign_id": "campaign_19",
"revision": 4,
"audience_id": "audience_28"
}Reserve and complete the outcome atomically
A read followed by an unconstrained insert can allow two concurrent requests to execute. Use a uniqueness constraint or equivalent atomic reservation around the tenant, operation and key. Represent in progress and completed outcomes separately.
The action ledger alone cannot make an external side effect exactly once. If a worker crashes after a destination accepted the write but before the ledger was updated, recovery must use the destination’s idempotency support or reconcile its current state.
| Ledger state | Repeated request behavior | Recovery requirement |
|---|---|---|
| Key absent | Reserve the operation atomically. | One owner begins execution. |
| In progress | Return a defined pending state. | Do not launch a second worker for the same action. |
| Completed, same fingerprint | Return the recorded outcome. | Preserve the original business result. |
| Same key, different fingerprint | Reject the conflict. | Use a new action identity only for an intended new action. |
| Outcome uncertain | Reconcile the destination. | Do not assume a timeout means no write. |
Retry only when repetition is safe
HTTP method idempotence concerns the intended effect, not identical response bytes. RFC 9110 warns against automatically retrying a non idempotent request unless the client knows that repetition is safe or that the original request was not applied.
Separate a failed transport attempt from a business rejection. Validation errors, denied permissions and payload conflicts need correction. Temporary capacity errors may justify a delayed retry when the operation remains within its deadline.
Give retries a finite budget
Use exponential backoff with jitter, a maximum delay and an overall deadline. Retry-After can be a delay in seconds or an HTTP date; parse both supported forms and respect the destination’s documented behavior. A 429 response may include this header but is not required to.
Coordinate rate limits by the provider’s actual boundary, such as account, app or connection. Thousands of workers each implementing their own local limit can still overload the same shared credential. Queue work fairly and surface delayed items to their owner.
Retain identity for the actual replay horizon
Choose retention from retry windows, manual replay expectations and the consequence of duplicate action. After an idempotency record expires, the same key may no longer protect an old operation. Document the behavior rather than implying protection lasts forever.
Test concurrent identical requests, changed payloads under one key, worker crash after destination acceptance, lost responses, expired records and repeated rate limiting. Recovery should preserve the business action identity while creating a new attempt record.
Resolve a repeated operation
Change the key state and fingerprint to see when work is replayed, held or rejected.
/api/v1/campaign-activationsExpected outcome
Activation created
A new action identity is reserved before execution.
{
"activation_id": "activation_42",
"state": "completed"
}Location: /api/v1/campaign-activations/activation_42Decision path
- Scope the key to tenant and operation
- Reserve the key atomically
- Execute the permitted action
- Persist its result
Input schema 4 fields
| Field | Type | Meaning |
|---|---|---|
ledger_stateRequired | string | Durable state for this action key.Allowed: absent, in_progress, completed |
request_fingerprintRequired | string | Fingerprint of the submitted meaningful input. |
stored_fingerprintRequired | string | Fingerprint reserved with the action key. |
destination_limitedRequired | boolean | Whether the provider is currently rate limiting this operation. |
Standards and documentation
Explore the protocol specifications and platform guidance for this topic.
Bring the contract into your operating environment.
Discuss an implementation