Which Sume media routes have GET /:id, and which poll /v1/jobs

Video inspect, video frames, captions and reference ingest have GET /:id. Trim, detach, filter, timeline, audio and compose have none; poll /v1/jobs/:id/status.

4 min readSume
All posts

Not every Sume media route has its own read route. Video inspect, video frames, video captions and reference ingest have GET /v1/<name>/:id. Video trim, audio detach, video filter, Timeline 1.0 render, timeline audio and timeline compose do not, and the docs say so for each: poll GET /v1/jobs/:id/status and then GET /v1/jobs/:id/result. Because the job id is returned by the submit, one polling helper works for all of them.

This matters for a Shorts pipeline, where a single clip may go through a probe, a trim, a render and a caption pass in turn. If a client assumes a resource route for every step, the trim and render steps return a not-found response while the job is running normally.

The table

Taken from the model pages on docs.sume.com. All of them take Idempotency-Key on submit.

read routes by media surface (Sume docs read 2026-10-05)
SurfaceOwn GET routePoll with
video-inspectGET /v1/video-inspect/:idthat route or jobs status
video-framesGET /v1/video-frames/:idthat route or jobs status
video-captionsGET /v1/video-captions/:idthat route or jobs status
reference-ingestGET /v1/reference-ingest/:idthat route or jobs status
video-trimnoneGET /v1/jobs/:id/status, /result
audio-detachnoneGET /v1/jobs/:id/status, /result
video-filternoneGET /v1/jobs/:id/status, /result
timeline-1.0 render, audio, composenoneGET /v1/jobs/:id/status, /result

One polling helper

The jobs docs list the statuses queued, processing, completed, failed and canceled, the last three being terminal. They advise exponential backoff, and not to submit the original paid request again just because a local process timed out. The helper below does that and reads the key from the environment without printing it.

import json, os, time, urllib.request

def get(path):
    req = urllib.request.Request(
        "https://api.sume.com" + path,
        headers={"Authorization": "Bearer " + os.environ["SUME_API_KEY"]})
    with urllib.request.urlopen(req) as resp:
        return json.load(resp)

def wait(job_id, tries=12):
    delay = 2
    for _ in range(tries):
        status = get(f"/v1/jobs/{job_id}/status").get("status")
        if status in ("completed", "failed", "canceled"):
            return status
        time.sleep(delay)
        delay = min(delay * 2, 30)
    return "still running"

# print(wait("job_123"))

Fetching the result

After completed, GET /v1/jobs/:id/result returns the result. The docs say that if the job is not complete the API returns a conflict response and not an empty result, so call it only after the status is terminal. For a trim, the result has a new video_url, duration_seconds and actual_start_seconds. For a timeline render it has video_url, duration_seconds, segment_count, billable_minutes and optional warnings[].

Limits

Reads are scoped: an API key reads the jobs that its own member created in the key's workspace, and other reads return 404 not_found. So a 404 on a jobs route can mean the wrong key, not a missing job. Also, the docs mention that some surfaces differ in how they describe a finished job, so rely on the terminal status list above and not on a surface-specific word.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume