Where a Recast result lives: the media.sume.com URL and how to keep it
A finished h3-max-recast job returns a media.sume.com video artifact. Read it at /v1/jobs/{id}/result, store the Sume URL and download your own copy.

A finished Recast job returns a Sume-hosted video artifact: a media.sume.com URL with type: "video" and content_type: "video/mp4", read from GET /v1/jobs/{id}/result. Sume mirrors generated outputs into its own media URLs before exposing them, and the docs tell integrations to store the Sume URL, not raw provider URLs (Media inputs, read 2026-10-03). Treat the URL as opaque: do not parse its path for workspace, job or provider identifiers.
If you need the file to outlive your own workflow, download it and keep your own copy as well as the URL.
What the result looks like
The artifact object has the same shape across Sume's video jobs. The example below follows the documented artifact envelope; fields beyond id, type, url and content_type can appear, so read defensively.
{
"id": "job_...",
"status": "completed",
"result": {
"artifacts": [
{
"id": "artifact_...",
"type": "video",
"url": "https://media.sume.com/artifacts/...",
"content_type": "video/mp4"
}
]
}
}Fetch and keep it
The script reads the result, picks the first video artifact and streams it to disk. It checks the job status first, because a result for a non-terminal job is not a video. On a /v1/videos job the same file is also reachable through the content endpoint, GET /v1/videos/{jobId}/content, which the Video generation docs describe, but the job result route works for jobs created on the Video Router too.
| Route | Use it when | Notes |
|---|---|---|
GET /v1/jobs/{id}/status | Polling for a terminal state | Use first |
GET /v1/jobs/{id}/result | You need the artifact list | Works for any job id |
GET /v1/videos/{jobId}/content?index=0 | The job was created on /v1/videos | Returns the video bytes |
unsigned_urls[0] on a poll response | You polled /v1/videos/{id} | Opaque URL, send your auth header |
The download script
This version is for a job created on the Video Router. It waits for completion with a bounded loop, then downloads. Remove the loop if a webhook already told you the job is done.
import asyncio
import os
import sys
import httpx
API = "https://api.sume.com"
async def main(job_id: str) -> None:
key = os.environ.get("SUME_API_KEY")
if not key:
raise SystemExit("set SUME_API_KEY")
async with httpx.AsyncClient(headers={"Authorization": f"Bearer {key}"}, timeout=60) as c:
for _ in range(60):
st = (await c.get(f"{API}/v1/jobs/{job_id}/status")).json()
status = st.get("status") or st.get("data", {}).get("status")
if status in ("completed", "failed", "canceled"):
break
await asyncio.sleep(10)
if status != "completed":
raise SystemExit(f"job ended as {status}")
res = (await c.get(f"{API}/v1/jobs/{job_id}/result")).json()
body = res.get("result") or res.get("data", {}).get("result") or {}
video = next(a for a in body["artifacts"] if a["type"] == "video")
data = await c.get(video["url"])
data.raise_for_status()
open(f"{job_id}.mp4", "wb").write(data.content)
print("saved", video["url"])
asyncio.run(main(sys.argv[1]))Common mistakes with Recast results
The first mistake is downloading a result before the job is terminal. A job that is still running has no artifact, and code that assumes one will crash on a missing key rather than wait. Check the status first, as the script does. The second mistake is treating the artifact URL as a permanent public address you can hand to customers; it is a Sume media URL for use in your workflow, and your own copy is what you control. The third is parsing path segments to find a job id; the docs ask you not to, and the job id is already in the response.
A fourth, quieter mistake is reusing the Recast output as the source of another Recast. That is allowed in the sense that it is a valid video, but each pass is another render at another price, and any artifacts from the first pass become part of the second. If you need two changes, check whether one call with more reference photos covers both.
Treat the first download as a handoff, not as storage. Copy the file into whatever system holds your finished work, record the source clip it came from, and note which reference photos were used. When a client asks for the same swap at another size next quarter, those three facts save you a search through old threads.
If you pass the result on to another Sume tool such as captions or trimming, use the media.sume.com URL you were given rather than re-uploading, because those tools accept URLs on that host and reject others. That keeps the pipeline short and avoids a second copy of the same large file.
What to store
Store three things per clip: the job id, the Sume artifact URL and your own file path or object key. The job id lets you ask Sume about the job later, the URL is what other Sume tools accept as input (captions, trim and inspect take media.sume.com URLs), and your copy is what you ship. Never store or publish a raw provider URL, since the docs say Sume does not expose it and does not guarantee it.
If a later step needs the clip, such as burning captions, pass the Sume URL straight to that step rather than re-uploading. See video captions and video trim for the two follow-ups people usually want.
- Download only after the status is
completed. - Keep the job id with the file.
- Do not parse artifact URLs.
Sources
Related posts
More in Developers
- Which episode finished? Map a Sume run id to your episode record
A Sume Format run does not echo your episode number. Keep a ledger keyed by queue index and run id, and match webhooks on request_id.
- Which limit stopped my agent: 402, queue_full or spend cap
Six different walls look alike from an agent loop. A diagnosis table that tells wallet, run spend cap, queue, request rate, scope and provider credits apart.
- Which Sume API errors should page an engineer: route by category
Route Sume API failures by category: fix-the-input errors go to the caller, quota to finance, queue to a retry, and only internal or unexpected 5xx to on-call.
- Which Sume image models accept the quality parameter?
Only five Sume image rows list quality: ChatGPT Image 2, both ChatGPT Image 2.5 ids, Ideogram V3 and Ideogram 4.5. Every other row returns 400 if you send it.
Written by Sume