/v1/videos 409 job_failed vs job_not_completed in retry loops

On /v1/videos/{id}/content, 409 job_not_completed is retryable and means keep polling; 409 job_failed is not retryable. Branch on the code, not the 409.

4 min readSume
All posts

Both errors are HTTP 409 on GET /v1/videos/{id}/content, so a retry loop must read the code. job_not_completed says the job is still running: it advertises retryable: true and a poll_status next action. job_failed says the job ended in failure: retryable: false and next_action: "inspect_events".

The two 409s

The difference is the whole point of having two codes.

Sume /v1/videos 409 responses, read 2026-10-05
CodeMeaningretryableNext action
job_not_completedJob still runningtruepoll_status
job_failedTerminal failurefalseinspect_events
409 conflictIdempotency-Key reused with a different bodyn/aSend a new key

Why two codes

The docs say job_failed is intentionally not job_not_completed. Otherwise a client would poll forever for content that will never exist.

A retry-safe download

This script fetches the content and prints the error code if the answer is a 409. The code field is read defensively because the exact error body shape is not spelled out in the docs.

import asyncio, os
import httpx

async def main():
    headers = {"Authorization": f"Bearer {os.environ['SUME_API_KEY']}"}
    job_id = os.environ["JOB_ID"]
    async with httpx.AsyncClient(base_url="https://api.sume.com", headers=headers, follow_redirects=True) as c:
        r = await c.get(f"/v1/videos/{job_id}/content", params={"index": 0})
        if r.status_code == 409:
            body = r.json()
            err = body.get("error") if isinstance(body.get("error"), dict) else body
            print("409:", err.get("code"))
        else:
            r.raise_for_status()
            open("out.mp4", "wb").write(r.content)

asyncio.run(main())

Poll first

Better still, poll GET /v1/videos/{id} until the status is terminal and only then ask for content. On failed, read the poll error string, which is the public remap of the failure.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume