Sume Format structured output: typed JSON from a JSON Schema
Bind a JSON Schema as output_schema and a Sume Format run returns output in that shape, with each media URL checked against what the run made.

To get typed JSON from a Sume Format run, send a JSON Schema as output_schema on the run request. The finished run's output comes back in that shape, with every media URL checked against the media the run actually produced, or it comes back null with an output_error that says why.
Every rule below is from Sume's Structured output and Create a run docs pages, read on 2026-09-25.
How do I bind a JSON Schema to a Format run?
Add output_schema to the body of POST /v1/formats/{handle}/{slug}/runs, the call described in What is a Sume Format?. It takes name (required, 1–64 characters; namespace it, because it shows up on every receipt), strict (defaults to true), and schema (required). A per-request schema overrides any default schema bound to the Format.
Clients built on OpenAI Chat Completions can send response_format with type: "json_schema" instead. The Responses API's flattened text.format shape is not accepted, and sending both fields is 400 invalid_request.
curl -sS -X POST "https://api.sume.com/v1/formats/acme/product-promo/runs" \
-H "Authorization: Bearer $SUME_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-8823-hero-v1" \
-d '{
"instruction": "Make one hero image for the linked product.",
"input": { "product_url": "https://shop.example.com/p/8823" },
"output_schema": {
"name": "acme/promo-hero/v1",
"strict": true,
"schema": {
"type": "object",
"additionalProperties": false,
"required": ["headline", "hero_image", "alt_text"],
"properties": {
"headline": { "type": "string" },
"hero_image": { "$ref": "SumeMediaFile#" },
"alt_text": { "type": ["string", "null"] }
}
}
},
"primary_output_key": "hero_image"
}'Which JSON Schema keywords does Sume accept?
Schemas must fit the OpenAI strict-mode subset, enforced from an allowlist: a keyword off the list is a violation, not ignored. A schema outside the subset fails at submit with 400 output_schema_invalid, details.violations[] names every problem, and nothing is charged. The rules that catch most schemas, from Supported schemas:
- The root's
typemust be exactlyobject. Wrap a top-level array in an object. - Every object, including those in
itemsand$defs, needsadditionalProperties: false. - Every declared property must be in
required. Make a field optional with a nullable union:"type": ["string", "null"]. - Every node needs a
type,$ref, oranyOf. UseanyOf, notoneOf;allOfandnullable: trueare rejected. $refresolves only to root#/$defs/*entries andSumeMediaFile#.- Limits: 10 levels of nesting, 5000 properties, 1000 values per enum, and 120,000 characters of strings in total.
| Group | Accepted keywords |
|---|---|
| Structure | type, properties, required, additionalProperties, items, $defs, $ref, anyOf |
| Values | enum, const |
| Strings | format, pattern, minLength, maxLength |
| Numbers | minimum, maximum, exclusiveMinimum, exclusiveMaximum, multipleOf |
| Arrays | minItems, maxItems |
| Annotation | title, description, default, examples, $schema, $id |
Where does the JSON object come from?
On the preferred path, filled_by: "agent", your schema is handed to the run as a tool it must call before finishing, so the model doing the work fills your object. If the run ends without a valid object, a fallback pass, filled_by: "projection", builds one with an OpenAI-strict json_schema completion at temperature 0.
That projection sees only the media the run generated and the first 8000 characters of its closing text, never your input or instruction. So an order id you sent does not round-trip on that path: keep identifiers on your side, keyed by the run id or your Idempotency-Key, and require only what the Format actually makes.
How do I get media URLs into the output?
Reference { "$ref": "SumeMediaFile#" } wherever you want a piece of the run's media. Every field of that shape is required, and every field but type and url is nullable.
- Every URL in a custom
outputmust exactly match media this run generated. Anything else fails the projection, including a plausiblemedia.sume.comURL or a file the run merely uploaded. - Name the one thing your UI shows with
primary_output_key(up to 64 characters) and the receipt resolvesprimary_output_url.
| Field | Value |
|---|---|
type | image, video, audio, or file. |
url | A URL this run actually produced. |
content_type, file_name, size_bytes, width, height | File metadata, or null. |
duration_ms | Video and audio length. Where the run recorded a length, it must agree within 10%. |
expires_at | null for durable media.sume.com URLs, the normal case. |
What happens when the output does not match the schema?
Check output_error before reading output. Over the API, a projection failure is a run failure: status is failed, and artifacts[] still lists every file the run made. A failed run can report a partial result on output only if your schema allows one, so use nullable fields and leave minItems off arrays you want back partially. Statuses and webhooks: Sume Format run lifecycle.
The documented codes are below, from When output cannot be produced; treat the set as open.
output_schema_unsatisfied: the object did not match your schema, or referenced media this run did not produce.output_extraction_failed: the projection could not run. Read the run once more; that alone clears aharvest_unavailable.deliverable_missing: the Format declares media the run never made.primary_output_missing: the schema was satisfied, but yourprimary_output_keyhas no value.unattended_blockedandagent_reported_failure: the run itself reports it did not deliver.
What does Sume structured output not do?
- No JSON mode. Bind a schema, or take the built-in
sume/action-run-output/v1: a nullabletextplusimages,videos,audio, andfilesarrays, filled deterministically with no model involved, so it cannot fail the way a custom schema can. - No escape hatch.
strict: falseis accepted and stored, and changes nothing about the subset. - No streamed partial JSON.
outputappears once, on the terminal receipt. - No control over what the run makes. The schema constrains how a finished run is read back, so it cannot make the Format produce a video.
Sources
Related posts
Written by Sume