AI video client timeout: the Sume job still runs and still bills

A timeout on your HTTP client does not cancel a Sume job. Save the job id, poll the polling_url, and cancel only before generation starts. Python example.

4 min readSume
All posts

Does a client timeout cancel my Sume video job?

No. The job keeps running and still bills. A timeout on your side only means you stopped listening. Resubmitting is the costly reaction, because it creates a second job. The right reaction is to keep the job id and poll its status, or retry the submit with the same Idempotency-Key, which replays the original job.

Long clips make this easy to hit. ByteDance Seed describes up to 30 seconds per Seedance 2.5 generation and Alibaba's Wan 3.0 page says native 30 seconds. Sume's sync wait is capped at 30 seconds and is a budget for the HTTP request, not for the job.

So the question is never "how do I stop it" but "how do I find it again". Two handles do that: the job id from the 202 response, and the idempotency key you sent with the submit. Keep both in your own database next to the order, written before you start waiting, and a crash or a timeout becomes a lookup instead of a second charge.

What to do in each situation

Timeouts and cancellation on Sume jobs (docs.sume.com, read 2026-10-06)
SituationJob stateDo this
Your client timed out after submitStill runningPoll the status route
Sync wait ended with sync.timed_outStill runningPoll, do not resubmit
You lost the submit responseUnknownRetry submit with the same Idempotency-Key
You want to stop the jobOnly before generation startsCancel; later it is 409 job_generation_already_started

Submit once, poll the URL

The submit returns 202 with a polling_url and a status of pending. The poll uses the OpenRouter-shaped states pending, in_progress, completed, failed and cancelled. A timeout on a poll is harmless, so the loop below treats it as a reason to try again.

import json, os, time, urllib.request

H = {"x-api-key": os.environ.get("SUME_API_KEY", ""), "content-type": "application/json"}

def call(method, url, body=None, key=None):
    h = dict(H)
    if key:
        h["idempotency-key"] = key
    data = json.dumps(body).encode() if body else None
    req = urllib.request.Request(url, data, h, method=method)
    with urllib.request.urlopen(req, timeout=20) as r:
        return json.load(r)

def run(prompt: str, order_id: str) -> dict:
    body = {"model": "wan-3.0", "prompt": prompt, "duration": 30, "resolution": "720p"}
    job = call("POST", "https://api.sume.com/v1/videos", body, key=f"order-{order_id}")
    while True:
        try:
            s = call("GET", job["polling_url"])
        except (TimeoutError, OSError):
            s = {"status": "in_progress"}  # our timeout, not the job's
        if s["status"] in ("completed", "failed", "cancelled"):
            return s
        time.sleep(5)

Cancel is not a timeout handler

Cancel works only before generation starts. After that the answer is 409 job_generation_already_started with details.cancelable set to false, and the job finishes and bills. A job that completes after your client gave up is yours to collect: store the job id with your order so a later poll or a webhook can pick the result up.

Set the HTTP timeout on the submit shorter than you think. The /v1/videos submit returns a 202 with a polling_url, so a 20 second timeout is generous, and a long hang usually points at the network rather than at the generation. Reserve the long waits for the poll loop, where a timeout is cheap and safe to retry.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume