Python requests Retry on POST: safe for Sume only with a key

urllib3 Retry skips POST by default. Allow it for a Sume submit only when every request carries an Idempotency-Key, and retry just 429 and 503.

4 min readSume
All posts

The default protects you

In urllib3 the Retry class retries only methods it considers idempotent: DELETE, GET, HEAD, OPTIONS, PUT and TRACE. POST is left out on purpose, since replaying a POST can do the work twice. status_forcelist is off by default, and respect_retry_after_header is on.

A Sume paid submit is a POST that bills. That is exactly why Sume gives it an Idempotency-Key: a retry with the same key returns the original job and does not bill another.

Which statuses to retry

Retry decisions from the Sume errors page, read 2026-10-05
StatusCodeRetry the submit
429rate_limitedYes, after retry-after, same key
503provider_capacity_exceededYes, later, same key
402insufficient_creditsNo, add funds first
400invalid_requestNo, fix the request

Session setup

Allow POST in the Retry, but force the key on every call so the allowance is safe. raise_on_status is set to False so you get the final Sume error body instead of a RetryError. It needs the requests package.

import os, uuid, requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

retry = Retry(
    total=3, backoff_factor=1, status_forcelist=(429, 503),
    allowed_methods=frozenset({"GET", "POST"}),
    respect_retry_after_header=True, raise_on_status=False,
)
s = requests.Session()
s.mount("https://", HTTPAdapter(max_retries=retry))
s.headers["Authorization"] = "Bearer " + os.environ["SUME_API_KEY"]

def submit(body, key=None):
    r = s.post(
        "https://api.sume.com/v1/image-1.0/generate",
        json={**body, "mode": "async"},
        headers={"Idempotency-Key": key or str(uuid.uuid4())},
        timeout=30,
    )
    return r.status_code, r.json()

The one rule

A fresh uuid per call, as in the default above, protects only within that call's own retries. If your process may crash and run the submit again, derive the key from your business item (an order id plus a version) so the second run lands on the same job. Reusing a key with a different payload returns 409 idempotency_conflict, so build the key and the body from the same inputs.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume