BFL 402 and 429 retry rules, and the same split on Sume

BFL raises on 402 and backs off on 429. Sume splits the same way: 402 insufficient_credits is a stop, 429 queue_full or rate_limited means wait and retry.

4 min readSume
All posts

Use two rules: stop on 402 because credits are missing, and wait then retry on 429. BFL's error-handling example does exactly that (exponential backoff on 429, an exception on 402), and Sume's documented errors line up: 402 insufficient_credits is not retryable until the balance changes, while 429 means back off.

Sources: BFL's integration guidelines and Sume's Errors and credits, read 2026-10-01.

What does BFL's example do?

Its Python helper retries up to max_retries. On 429 it sleeps 2 ** attempt seconds and continues. On 402 it raises "Insufficient credits". Other 4xx and 5xx responses raise.

How does Sume classify the same errors?

Sume error handling as documented, read 2026-10-01.
Status and codeMeaning in the docsClient action
402 insufficient_creditsBalance is not sufficient for the requested generationStop; change plan, wait for balance, or submit a cheaper request
429 rate_limitedRequest volume exceeded a limitBack off, use retry-after when present
429 queue_fullNo accepted generation capacity left in the workspaceWait for jobs to finish or cancel queued ones, retry with the same key
409 idempotency_conflictKey reused for a different payloadReuse keys only for exact retries

How do I retry safely?

The docs say to back off on 429, use retry-after when present, and not retry unsafe submits without an Idempotency-Key. error.details.scope is read or write, so you can tell polling pressure from submit pressure. Details in 429 and retry-after.

async function submit(body, key) {
  for (let attempt = 0; attempt < 4; attempt++) {
    const res = await fetch("https://api.sume.com/v1/image-1.0/generate", {
      method: "POST",
      headers: {
        Authorization: "Bearer " + process.env.SUME_API_KEY,
        "Content-Type": "application/json",
        "Idempotency-Key": key,
      },
      body: JSON.stringify(body),
    });
    if (res.status === 402) throw new Error("insufficient credits: stop");
    if (res.status !== 429) return res.json();
    const wait = Number(res.headers.get("retry-after")) || 2 ** attempt;
    await new Promise((r) => setTimeout(r, wait * 1000));
  }
  throw new Error("still rate limited");
}

What should I do about 402?

Do not loop. Surface it, check GET /v1/balance, and only resubmit after the balance can cover the estimate.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume