Bulk create returns 429: wait retry-after, resend with the same key

A 429 on a Sume bulk create means the write budget is spent. Wait retry-after, then resend with the same Idempotency-Key; the same payload cannot double-queue.

4 min readSume
All posts

A 429 rate_limited on a Sume bulk create means your write budget for the minute is spent. Wait the retry-after seconds, then resend the same body with the same Idempotency-Key. If the first request had in fact gone through, the same key and the same payload returns 202 with the existing queue instead of making a second one.

What the API tells you

A 429 names the budget in error.details.scope (read or write) and adds retry-after. Bulk create spends the write budget; polls spend the read budget, which is separate and forty times larger. Each response carries ratelimit-limit, ratelimit-remaining and ratelimit-reset.

Bulk create retry rules (read 2026-10-06)
ResponseAction
429 rate_limited, scope writeWait retry-after, resend with the same key
503 studio_agent_upstream_unavailableRetry later; a Sume-side outage
409 idempotency_conflictYou changed the payload under a spent key; use a new key for a new batch
202 on a replayThe old queue; read its id and carry on

A safe retry loop

Keep the key stable across retries of one batch, and mint a new one only when you intend a new batch.

  • Generate the key from the batch identity, such as holiday-2026-10-06-batch-3, not from uuidgen inside the retry loop.
  • Honor retry-after instead of a fixed sleep, and cap the number of retries.
  • After a 202, save the queue id before you do anything else.

Why the same key is safe

A replay of the same key with the same { concurrency, items } returns 202 and the queue that already exists. The key is scoped to one Format, and the docs say the queue adds no extra lock, so a second identical request cannot start a second set of children.

A different payload under the same key is 409 idempotency_conflict, with details.queue_id naming the original. That is your signal that the retry loop rebuilt the body with a change, which is usually a bug.

Remember that a 429 can also hit a poll. That one comes from the read budget and does not mean the queue failed; back off and poll again.

Tradeoff

A replay returns 202 and the queue object has no idempotency_hit flag, so you cannot tell a fresh queue from an old one by the status. Compare created_at or your own records if it matters.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume