Retry hints in the body or a header: reading Sume's Retry-After

Notion repeats Retry-After in response bodies. Sume can send a retry-after header on 429s. Here is how to retry each Sume error code safely.

4 min readSume
All posts

Sume's public API responses can include a retry-after header alongside ratelimit-limit, ratelimit-remaining and ratelimit-reset. When you get a 429, wait for retry-after if it is present. Retry only calls that are safe, which for paid submits means sending the same Idempotency-Key.

What Notion changed

The Notion changelog entry for September 24, 2026 says any 429 or 529 response with a Retry-After header now repeats the wait in the body as additional_data.retry_after, so clients that cannot read headers, such as MCP clients, still see it. It also says page write timeouts now return 504 instead of 500. The lesson for any client is that the retry hint can live in a body or a header depending on the service, so read both.

Where Sume puts it

Sume's error body is a JSON envelope with code, message, request_id and details. The wait hint for HTTP rate limits is in the response headers. Failed jobs also expose retry metadata in their public error: category, stage, retryability, retry-after seconds, public reason and next action.

What to retry

Retrying everything is wrong, and so is retrying nothing.

Sume errors and the retry rule (read 2026-10-03)
Status and codeRetry?Rule
400 invalid_requestNoFix the request
402 insufficient_creditsNoAdd funds or lower cost
429 rate_limitedYesBack off, use retry-after when present
429 queue_fullLaterWait for an existing job to finish or cancel
503 provider_capacity_exceededYesRetry later with the same idempotency key
503 provider_not_configuredNot aggressivelyCheck catalog and runtime status

A retry helper

This helper retries only rate_limited and provider_capacity_exceeded, honors a numeric retry-after, and falls back to exponential backoff. It reuses one idempotency key so a replay returns the original job. queue_full and provider_not_configured are returned to the caller.

import os, time, uuid
import requests

def submit(payload, tries=5):
    key = str(uuid.uuid4())
    headers = {
        "Authorization": "Bearer " + os.environ["SUME_API_KEY"],
        "Idempotency-Key": key,
    }
    for attempt in range(tries):
        r = requests.post("https://api.sume.com/v1/videos", json=payload, headers=headers, timeout=60)
        try:
            code = r.json()["error"]["code"]
        except (ValueError, KeyError, TypeError):
            code = None
        if code not in ("rate_limited", "provider_capacity_exceeded"):
            return r
        ra = r.headers.get("retry-after", "")
        wait = float(ra) if ra.replace(".", "", 1).isdigit() else 2 ** attempt
        time.sleep(wait)
    return r

Do not resubmit a paid job on a timeout

If your own process times out, poll the job instead of submitting again. A queue_full response is not a rate limit: it means the workspace cannot take another paid job until a queued or processing one finishes or is canceled.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume