SumeMediaFile in a Format output_schema: fields and URL rules
Put a run's image or video in typed JSON with $ref SumeMediaFile#: the nine fields, which are nullable, and why url must be media the run generated.

To get a run's video or image into typed JSON, reference Sume's built-in media shape with { "$ref": "SumeMediaFile#" } inside your output_schema. It returns type, url, content_type, file_name, size_bytes, width, height, duration_ms and expires_at, and the url must be a file this run actually generated.
The shape comes from Structured output, read on 2026-10-02. The same page says the exact request and response schemas live in the live OpenAPI at https://api.sume.com/reference/json, so treat the tables below as a readable summary, not a second schema.
What fields does SumeMediaFile contain?
Every field is required in the object, and every field except type and url is nullable. That matters because the strict subset has no optional properties: a field the run could not measure comes back as null, not missing.
| Field | Type | Notes |
|---|---|---|
| type | image, video, audio or file | Always present |
| url | string (uri) | Must be a URL this run produced |
| content_type | string or null | For example video/mp4 |
| file_name | string or null | Name of the stored file |
| size_bytes | integer or null | Null when not measured |
| width, height | integer or null | Images and video |
| duration_ms | integer or null | Video and audio |
| expires_at | date-time or null | Null for durable media.sume.com URLs |
How do I use it in a schema?
Reference it by name wherever a field should hold media. The root must be an object, every object needs additionalProperties: false, and every declared property goes in required. Name the field you show in your UI with primary_output_key so the receipt also resolves primary_output_url.
{
"output_schema": {
"name": "acme/promo-hero/v1",
"strict": true,
"schema": {
"type": "object",
"additionalProperties": false,
"required": ["headline", "hero_image"],
"properties": {
"headline": { "type": "string" },
"hero_image": { "$ref": "SumeMediaFile#" }
}
}
},
"primary_output_key": "hero_image"
}Why is expires_at null?
Sume-hosted media is served from media.sume.com and does not expire, so expires_at is null for the normal case. It is only populated when a signed URL is returned. You can store the URL next to your own record and render it later, with no refresh step.
The same page warns that a durable URL is also a public URL. Anyone holding it can fetch the file, so if your product needs per-customer access control, copy or proxy the file rather than handing out the Sume URL.
What does the run check about the url?
Before output reaches you, every URL in it is compared with the set of media the run generated, using exact string equality. One pass collects every http(s) string at any depth. A second pass collects the url of every SumeMediaFile-shaped value whatever it contains, so a placeholder such as none or an empty string cannot slip through.
A plausible-looking media.sume.com URL that this run did not make fails the projection. You get output: null plus an output_error, not a schema-shaped guess. The gate also only admits media the run generated, so a file the run merely uploaded is not in the set, and a schema field holding an upload URL fails the whole projection.
What about duration_ms?
A duration_ms inside a SumeMediaFile comes from the same ledger that fills artifacts[]. Where the ledger recorded a length, the value in output must agree within 10 percent or the projection fails. Where nothing was recorded, nothing is checked, and null means not measured, not zero.
So a duration_ms you read back is either the artifact's own or unverified. A separate duration_seconds number you declared yourself is written by the projection pass and is not checked, so do not bill or schedule from it.
What does Sume not do here?
SumeMediaFile# is one of only two $ref targets that resolve, along with #/$defs/* declared at the root. External refs and $ref: "#" are rejected with 400 output_schema_invalid, which costs nothing because nothing runs. Read Errors and spend for the codes, and fall back to artifacts[] when output is null.
Checklist before you ship a schema with media
Walking this list once costs less than debugging an output_schema_unsatisfied receipt, because that failure arrives only after the run has already spent money on generation.
- Every object in the schema, including ones inside
$defs, hasadditionalProperties: false. - Every declared property appears in
required; use a nullable union for anything that may be missing. - Require only media the Format actually makes. A required image on a text-only Format fails on every run.
- Do not expect values from
inputto come back. The projection path never sees yourinput. - Handle
output: nullwithoutput_errorset, on bothfailedandcompletedruns, and fall back toartifacts[].
Which keys does the array form take?
A schema can hold several files by putting SumeMediaFile# inside an array with items, for example a list of clips next to an assembled cut. Declare items on every array; an array without it is a missing_items violation. Leave minItems off if you want to receive a partial list, because the keyword is enforced and a list that demands three clips rejects a run that made two.
Keep nesting under 10 levels and the whole document under 5000 properties. The total string length budget is 120,000 characters across names, keys and string values, so long descriptions on a big schema can use it up even when no single string is large.
What should I read when it still fails?
Look at output_error.code first. output_schema_unsatisfied with rejected_urls[] (the first ten only) means a URL was not produced by this run. With violations[] it is the shape. The harvested count by media type tells you how many images, videos, audio and files the run really made, so you can compare it with what the schema requires.
If the media exists, you still have it in artifacts[]. Showing that media and logging the shape failure is better than showing an error to a customer whose video exists.
Sources
Related posts
More in Formats
- Virtual try-on or virtual fitting: which Sume Format for apparel?
Both Formats start from a garment still and make a 9:16 video. Virtual try-on shows a creator changing into the garment; fitting shows its silhouette and drape.
- Serum drip, toner pour or cream squeeze: which Sume image Format?
Eight Sume catalog Formats make a single beauty hero image from a packshot. What each one shows, so you can pick one for holiday skincare ads.
- Ready-made Formats for product video: the Sume Format catalog
Sume ships ready-made Formats for product and UGC-style video and images, each callable from your backend with one HTTP request at the reserved sume handle.
- What is a Sume Format? Turn an agent thread into one API call
A Sume Format is a saved video recipe your backend calls by handle and slug. One POST runs it in a fresh sandbox and returns media plus optional typed JSON.
Written by Sume