Get a structured ad pack back from one Sume Agent Completion
Bind an output_schema to a Sume Agent Completion to get hook, caption, CTA and a video URL as named fields, with the strict-subset rules and failure modes.

To get an ad pack back as fields instead of prose, bind a JSON Schema to the run with output_schema and name the deliverable with primary_output_key. Sume then returns output in your shape, with the generated video as a SumeMediaFile whose URL is checked against the media ledger. Keep every property listed in required and express optional values as nullable unions.
A schema for an ad pack
The schema below asks for three text fields and one video. Every property is required, the object closes with additionalProperties: false, and the optional caption uses a nullable union, which is how the strict subset says optional.
{
"name": "ad-pack/v1",
"strict": true,
"schema": {
"type": "object",
"additionalProperties": false,
"required": ["hook", "caption", "cta", "video"],
"properties": {
"hook": { "type": "string" },
"caption": { "type": ["string", "null"] },
"cta": { "type": "string" },
"video": { "$ref": "SumeMediaFile#" }
}
}
}What the strict subset allows
| Rule | Detail |
|---|---|
| Root | Must be an object |
| Objects | Every object sets additionalProperties: false |
| Properties | Every property is listed in required; optional means a nullable union |
| Nesting | 10 levels at most |
$ref | Only #/$defs/<name> or SumeMediaFile# |
| Banned keywords | oneOf, allOf, not, if/then/else, nullable: true |
Read the receipt in the right order
Check output_error before output. On a completed run, output carries your object and filled_by tells you who wrote it: agent means the run submitted the object itself, projection means a fallback pass filled it from what the run produced.
The projection also runs a URL gate. A media URL has to match media the run really generated, and a duration_ms inside a SumeMediaFile must agree with the actual file within 10%. A hallucinated link fails the projection and does not reach you.
Failure modes to plan for
For a pipeline, store the schema with the code that reads it. When the schema changes, version its name, for example ad-pack/v2, so a log line tells you which shape a run was asked for. Never loosen the subset to make a run pass: the rules exist so that the object you get is the object you asked for.
- A schema outside the subset is rejected at submit with
details.violations[]naming each broken rule. - If the run produces a valid object but the key named in
primary_output_keyis empty, the run isfailedwithprimary_output_missing. - A degraded run still bills and still has real media on it, but
outputisnull. The webhook marks thisoutcome: degraded. - If you want partial results to be legal, drop
minItemson arrays and make fields nullable.
Where the spend cap comes in
The Completion still needs generation_spend_cap_usd, and the schema does not change what the run may spend. Pair the schema with a cap that fits one pack, then branch on primary_output_url for the video and on output.hook and output.cta for the copy.
Sources
Related posts
More in Agents
- Agent Completion cost: cap, billable_amount_usd_micros, or usage?
Where to read what an Agent Completion cost: the required spend cap, the receipt's usage.billable_amount_usd_micros, and GET /v1/usage as the billing record.
- Claude Code 2.1.287 tool heartbeats and Sume jobs_wait slices
Claude Code 2.1.287 fixed tool heartbeats not reaching SDK hosts during a stalled response stream. Sume's jobs_wait holds up to 55 s, so heartbeats matter.
- Claude Code routine artifacts: link Sume media, don't paste it
Claude Code 2.1.292 lets Scheduled and Run now routines publish a private artifact without approval. Hand off Sume results as durable media.sume.com links.
- Claude Code scheduled task never fired? Compare with a Sume cron run
Claude Code 2.1.292 fixed scheduled tasks that never fired after /resume, /branch or /clear. A Sume schedule runs on Sume's clock, so check it separately.
Written by Sume