Alert on Sume API errors by category and stage, not 4xx (Python)
Sume error envelopes carry category, stage and public_reason for dashboards. A Python tally pages on quota and auth, tickets bad input, watches 429s.

Every Sume error body has the same shape: code, message, request_id, category, stage, retryable, retry_after_seconds, public_reason, next_action and details. The docs split their jobs. Branch your control flow on the HTTP status and then on code. Use category, stage and public_reason for the coarser labels on dashboards and alerts. This post is about the second half, because it is where teams tend to page the wrong people.
If a Recast or video client alerts on every 4xx, a busy hour of queue_full and rate_limited responses wakes someone up for something your retry loop already handled. Alerting on category fixes that without parsing messages.
What each category looks like
| Category | Stage | Example code | Who acts |
|---|---|---|---|
| quota | usage_reservation | insufficient_credits | A person: add funds or raise a cap |
| auth | auth | unauthorized | A person: fix or rotate the key |
| rate_limit | queue | rate_limited | Your retry loop |
| rate_limit | runtime | rate_limit_unavailable | Your retry loop, longer wait |
| queue | queue | queue_full | Your retry loop, same key |
| job_state | job_state | job_not_completed | Your poll loop |
| validation | validation | invalid_request | A developer: fix the request |
| media | media | attachment_fetch_failed | A developer: fix the input URL |
A severity function and a tally
The code below maps a category to a severity and counts errors by severity, category, stage and public reason. Feed it the error bodies your client already logs. The public_reason strings in the sample are placeholders, so substitute the values you see in your own logs. The sample at the bottom runs as written and prints one row per distinct combination, so a flood of identical queue_full rows collapses into a single counted line.
import json
from collections import Counter
PAGE = {"quota", "auth", "internal"} # a human has to act
TICKET = {"validation", "media"} # a code or data bug
# everything else (rate_limit, queue, runtime_unavailable, job_state): code retries
def severity(error: dict) -> str:
if error["category"] in PAGE:
return "page"
return "ticket" if error["category"] in TICKET else "watch"
def tally(bodies: list[str]) -> Counter:
seen = Counter()
for body in bodies:
e = json.loads(body)["error"]
seen[(severity(e), e["category"], e["stage"], e["public_reason"])] += 1
return seen
sample = [
'{"error":{"code":"queue_full","category":"queue","stage":"queue","public_reason":"queue_full"}}',
'{"error":{"code":"insufficient_credits","category":"quota","stage":"usage_reservation","public_reason":"insufficient_balance"}}',
'{"error":{"code":"queue_full","category":"queue","stage":"queue","public_reason":"queue_full"}}',
]
for key, n in tally(sample).most_common():
print(n, *key)Rules that keep the alerts quiet
- Page on
quotaandauth. Retryinginsufficient_creditsnever works, and a revoked key fails every call after it. - Ticket
validationandmedia. A 4xx at create means nothing ran and nothing was charged, so the fix is in your code or data. - Watch the rest as a rate. A rising
queuecount means you are submitting faster than your plan drains, which is a pacing problem rather than an outage. - Always log
request_id, which is also thex-sume-request-idheader, next to the tally so support can find the exact request. - Keep
retryablein your retry code. It is the field that says whether resending the same request can succeed.
The envelope table and the per-code advice live in the errors reference. The rate limit budgets that decide how often you see rate_limited are in the authentication guide.
Sources
Related posts
More in Developers
- Alert when a Sume image model price changes: Python snapshot script
Compare the billed price of every Sume image model against a saved snapshot with two endpoints and a JSON file, and print only the rows that changed.
- Amazon Sponsored Brands video: Sume fps 24-30 fit; 60 and 4K do not
Amazon lists 23.976 to 30 fps and 1280x720, 1920x1080 or 3840x2160. Sume trim offers 24, 25, 30 or 60 fps and stops at 2160 per edge. Which settings line up.
- Android adaptive icon: 108 dp layers, 66 dp safe zone, from Sume
Adaptive icon layers are 108 x 108 dp with a 66 x 66 dp visible zone and 18 dp margins. Generate a transparent foreground on Sume and scale it inside the zone.
- Animate a picture with Kling 3 via API: Python first-frame request
To animate one picture with Kling 3 on Sume, send it as a first_frame in frame_images to POST /v1/videos with model kling-3. Full Python script included.
Written by Sume