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.

6 min readSume
All posts

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.

Ways to read a finished video job, read 2026-10-03
RouteUse it whenNotes
GET /v1/jobs/{id}/statusPolling for a terminal stateUse first
GET /v1/jobs/{id}/resultYou need the artifact listWorks for any job id
GET /v1/videos/{jobId}/content?index=0The job was created on /v1/videosReturns the video bytes
unsigned_urls[0] on a poll responseYou 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

All Developers posts

Written by Sume