v1/videos job statuses and a failed-job error handler

Map /v1/videos statuses (pending, in_progress, completed, failed, cancelled) to actions, and decide which failed-video errors deserve a retry. Python handler.

5 min readSume
All posts

On GET /v1/videos/{id}, pending and in_progress mean wait, completed means download, and failed or cancelled means stop and read the error. A failed job is a result, not an exception, so branch on the status and decide from the error category whether a retry makes sense.

The same job is visible at GET /v1/jobs/{id}/status with the Sume vocabulary: queued, processing, completed, failed, canceled. The two sets map one to one, so use whichever surface you started on.

The status map

The OpenRouter-style set on /v1/videos is what you poll. The Sume set is what webhooks and the jobs routes use. Note the spelling: cancelled on /v1/videos, canceled on the jobs routes.

Status vocabulary for one video job (read 2026-10-07)
/v1/videos/v1/jobsTerminalAction
pendingqueuedNoKeep polling, queued is normal
in_progressprocessingNoKeep polling
completedcompletedYesDownload the clip
failedfailedYesRead the error, retry by category
cancelledcanceledYesNothing to download

Which failures to retry

Failed jobs carry public error metadata with a category. The docs give a next action for each. Validation and generation-rejected errors need a changed input, so a retry only repeats the failure. Queue, generation-unavailable, and runtime-unavailable errors are worth a delayed retry.

Job error categories and what to do (read 2026-10-07)
CategoryRetry?Next step
validationNoCorrect the input
quotaNoAdd funds or lower the cost
generation_rejectedNoCheck events, fix the unsupported input
queueYes, laterSame idempotency key
generation_unavailableYes, laterWait and retry
generation_timeoutPoll firstPoll the status, then retry later
internalNoContact support with the request id

A handler

The function returns a short action string that your queue worker can act on.

import os, requests
H = {"Authorization": f"Bearer {os.environ['SUME_API_KEY']}"}
RETRY_LATER = {"queue", "generation_unavailable", "runtime_unavailable"}

def decide(job_id: str) -> str:
    r = requests.get(f"https://api.sume.com/v1/jobs/{job_id}", headers=H, timeout=30)
    r.raise_for_status()
    job = r.json()["data"]["job"]
    status = job.get("status")
    if status in ("queued", "processing"):
        return "wait"
    if status == "completed":
        return "download"
    if status == "canceled":
        return "drop"
    category = (job.get("error") or {}).get("category")
    return "retry-later" if category in RETRY_LATER else "fix-or-escalate"

print(decide("job_123"))

Sources

Related posts

More in Developers

All Developers posts

Written by Sume