Braze retries a 500: keep the Sume job submit idempotent
Braze sends 500 and 502 responses to retry logic, and a :retry option exists. Give every Sume submit a stable Idempotency-Key so a retry is not a second bill.

Can a Braze retry create two Sume jobs?
It can if your endpoint submits a paid job on every request. Braze's docs say 500 and 502 responses go to its retry logic and that a :retry option exists. A retry reaches your server as a new request, so your code has to recognize it as the same request.
Sume requires an Idempotency-Key on paid POSTs. Derive it from what makes the request unique, such as the campaign id plus the segment, never from the clock or a random value.
What does Braze do with each status?
| Status | Braze behavior |
|---|---|
| 2xx | Success |
| 404 | Renders an empty string |
| 500, 502 | Retry logic |
| 429 | Treated as an endpoint failure |
| 301, 302 | Not followed |
How do I derive a stable key?
Hash the inputs that define the clip: avatar handle, script, aspect ratio and quality. The same inputs give the same key, and a different script gives a different key. Sume's docs also say not to resubmit the original paid request only because a local process timed out; poll the job instead.
Rather than submitting inside the Connected Content request at all, submit from a background step and have the lookup read the stored URL.
import hashlib, json
def idem_key(campaign, body):
blob = json.dumps(body, sort_keys=True)
digest = hashlib.sha256(blob.encode()).hexdigest()[:24]
return "braze-" + campaign + "-" + digest
body = {"avatar_handle": "your_avatar_handle",
"script": "Two more days at this price.",
"aspect_ratio": "9:16", "quality": "standard"}
print(idem_key("bf26", body))What else should the endpoint do on a retry?
Return 2xx for a request you already accepted, even if the clip is not ready; give the fallback URL in the body. A 429 is also treated by Braze as a failure, so protect your own endpoint from bursts. See retrying with the same key on a 429.
Sources
Related posts
More in Integrations
- Cloudflare Worker: keep the image model id in KV and swap it live
A Worker that proxies POST /v1/images and reads the Sume model id from Workers KV, so replacing gpt-image-1 is a wrangler command, not a deploy.
- GitHub Actions repository variable for the image model id: no commit
Keep the Sume image model id in a GitHub Actions repository variable, so a gpt-image-1 replacement is a settings change or one gh command, not a pull request.
- Intercom outbound message with a Sume avatar clip: email or in-app
Intercom's create-message API sends in_app, email or whatsapp with an HTML or plain body. It documents no video field, so link a Sume clip. How to set it up.
- jobs_wait for 20 transcription jobs in one MCP call
The hosted MCP jobs_wait takes up to 20 job_ids, wait_for all or any, and include_results returns each finished transcript. Retry slices of 55 seconds.
Written by Sume