Handle 429 responses with coordinated queues, correct Retry-After parsing, bounded backoff, and a separate recovery path for uncertain write outcomes.
An agency bot starts syncing records for several clients. One service returns 429 Too Many Requests, and every worker immediately tries again. The queue now contains both the original work and a growing pile of retries.
A better response is to slow the affected work, preserve its state, and decide which actions are safe to repeat. This guide is an integration design checklist, not a statement of AllProfiles quotas or an automatic-retry feature.
1. Read the response without guessing the limit
HTTP 429 indicates too many requests within a period. The response may include Retry-After, but that header is optional. The standard does not define one universal counting rule or limit scope: a service can count by resource, credentials, server, or another mechanism. RFC 6585: 429 Too Many Requests
Check the provider's current documentation and the actual error details. Do not infer a requests-per-minute allowance from one failed request, or assume that every 429 blocks the whole client account.
Microsoft Graph illustrates why scope matters: throttling can depend on request type, application, and tenant. Writes can be restricted while reads remain available, and broader throttling is also possible. Treat this as a Graph-specific example, not a rule for every API. Microsoft Graph throttling guidance
2. Queue the work and coordinate the pause
Give each outbound job an identity and a recorded state before dispatch. A practical record includes the target service, client reference, intended operation, attempt count, next eligible time, and latest outcome. Keep tokens and full private message bodies out of ordinary operational logs.
When workers share a documented limit, coordinate their pause. Sleeping one failed worker does little if the others continue sending equivalent requests into the same limit. Conversely, do not stop an unrelated integration unless its work shares that limit or another documented constraint.
Illustrative example: several workers use one integration to sync client records. A shared scheduler delays affected jobs and retains their order and identifiers. The operator can see which jobs are waiting instead of restarting the entire sync. This describes a possible design, not an existing AllProfiles queue API.
3. Respect both forms of Retry-After
Retry-After accepts a nonnegative integer number of seconds after receipt or an HTTP date. RFC 9110: Retry-After
Illustrative header: Retry-After: 30 means wait 30 seconds.
Store the earliest retry time. Never let jitter or a local delay cap move it earlier. If the job expires first, stop it explicitly. Handle malformed values under the provider's recovery guidance, rather than retrying immediately.
4. Bound retries and choose one policy owner
When no usable waiting instruction is available, follow the provider's documented recovery guidance. Graph recommends exponential backoff when its response lacks Retry-After; that recommendation does not establish another service's contract.
Amazon's engineering guidance explains why retries need restraint: they add load, capped exponential backoff increases spacing up to a ceiling, and jitter spreads attempts that would otherwise happen together. Attempts still need a limit. Retries at multiple layers can multiply the downstream work. AWS: Timeouts, retries, and backoff with jitter
Choose which layer owns retries and inspect the HTTP client or SDK before adding another loop. Define an attempt budget, an overall deadline, and the state reached when either is exhausted. Increasing the delay forever is not a complete recovery policy.
5. Separate a delayed request from an unknown write outcome
After a write times out, its outcome can be unknown. HTTP discourages automatic retries of non-idempotent requests unless their actual semantics are known to be idempotent or the original is known not to have been applied. RFC 9110: Idempotent methods
Reconcile against provider records or use its supported idempotency mechanism. Keep the original job reference and route unresolved outcomes to an operator.
The following is an illustrative decision table, not a universal provider policy.
| Observed result | Next decision |
|---|---|
| 429 with valid Retry-After | Respect the wait, then retry only if the operation is safe to repeat |
| 429 without a usable wait instruction | Follow provider guidance and the configured bounded backoff policy |
| Timeout after a write was dispatched | Mark the outcome unknown and reconcile before repeating |
| Retry budget or deadline exhausted | Preserve the job and expose a clear review or failure state |
6. Test recovery before relying on it
Use controlled test data to exercise seconds and date headers, absent or malformed values, simultaneous workers, and a restart while work is waiting. Confirm that the next eligible time survives the restart and that canceled or expired work is not resumed accidentally.
Inspect individual operations as well as the outer response. In Graph JSON batching, the envelope can return HTTP 200 while individual requests return 429. Graph SDKs also include retry handlers, so account for their behavior in your total retry policy. Graph throttling and batching guidance
Finally, test an uncertain write outcome and an exhausted retry budget. The operator should be able to distinguish waiting, completed, failed, and unknown jobs. That distinction is more useful than a spinner that restarts the same action without explaining what happened.


