Format API
A Format is a saved production recipe: a house style, an output contract, and a playbook for
one kind of video. Your backend calls the Format by name. Sume runs it in a fresh sandbox with
the generation tools. You get finished media on media.sume.com. If you ask for it, you also
get a JSON object in a shape that you defined.
This page goes from an API key to a finished run. The pages after it give the reference for each step.
Your first run
You must have an API key that carries the formats:read and formats:write scopes. Create a
key at API keys. Keep the key server-side.
1. List the Formats your key can call
The list shows the Formats that your key's workspace owns, and the ready-made
Formats by Sume. vanity_invoke_url is the address that you call next.
2. Start a run
202 means that Sume accepted a fresh run. Store data.id. The receipt gives all the other
items that you need as URLs. Thus, you never build a path manually. For the full body
reference, refer to Create a run.
3. Take the result
When the run completes, Sume POSTs the same receipt to your webhook_url as one signed
format.run.terminal event. To poll instead, read the run until status is terminal:
The response for a finished run is:
primary_output_url is the one item to show. artifacts[] is every file that the run made.
Media URLs are durable and public. Store them. If you bind an
output schema, output comes back in your own shape, not in the
built-in shape.
That is the whole loop: create, then webhook or poll, then read. Runs that make video take minutes, not seconds. Long-form host video usually completes in 15 to 30 minutes. Thus, design for the asynchronous path from the start.
Two hosts, one contract
| Host | Use it for | Keys |
|---|---|---|
https://api.sume.com | Production. Runs spend real credits from your workspace. | Create them at API keys. |
https://api.dev.sume.com | Integration and staging. Same routes, same receipts, same webhook delivery. | Sume issues them for a development workspace. Get them from your Sume contact. |
A key works only on the host that it was created for. The other host answers
401 unauthorized. Keys for both hosts look like sume_live_…. Thus, name your environment
variables by host, not by prefix. The examples on these pages use production. To point them at
development, change the host and the key.
How a run works
Every call has four parts:
| Piece | What it is | Where it lives |
|---|---|---|
| The recipe | The Format: a SKILL.md body and reference files. The how: house style, branch rules, quality bar. | You write it in the Agents dashboard, in chat, or over the Contents API. |
| The call | Your instruction and input. The what: product URL, brief, script, prices. | The request body. |
| The run | One fresh sandbox, one agent turn, one receipt. A run never gives a partial delivery. A run that could not finish comes back failed. | arun_…, at /v1/format-runs/{run_id}. |
| The result | Durable media and output, in the built-in shape or in a shape projected onto your schema. | The terminal receipt. |
This gives two properties. A run is one unit of work: a bulk request is a server-side queue of ordinary runs, not a different engine (Bulk runs). Also, the recipe is set before your instruction. Thus, you do not send a system prompt again on every call with no guarantee that it holds.
This is not chat
A Format run is one unattended turn with the Format attached. The run does not stop to ask a person questions. Approvals that a chat-authored recipe asks for in chat are pre-granted, and the run continues in its spend cap. The Agents chat UI at sume.com/agents is the surface for a human in the loop. A chat turn can have no Format attached. Build partner integrations on runs, not on chat threads.
Find your Formats
Three reads are available. Each read must have formats:read:
| Call | Returns |
|---|---|
GET /v1/formats?limit=50 | The Formats that your key's workspace owns, and the first-party catalog. Keyset pages: while has_more is true, send next_cursor back as cursor. |
GET /v1/formats/{handle}/{slug} | One Format by its address. |
GET /v1/formats/{format_id} | The same Format by its opaque skl_… id. |
The key sets the visibility. A personal key lists your personal Formats. A team key lists the
Formats of that workspace, for every member. Neither key lists the Formats of the other key. A
Format outside your key's workspace gets 404 format_not_found, the same answer as an id that
does not exist. If a Format that you expect is missing, you have the other key.
These fields are important when you select a Format:
| Field | Notes |
|---|---|
handle, slug, vanity_invoke_url | The address to call. For a team Format, handle is the handle of the workspace that owns it. For a personal Format, it is your own handle. For the catalog, it is sume. |
invoke_url | The opaque skl_… path. It stays the same after a rename. If a stored URL must stay valid after a handle or slug change, persist this path. Renamed handles continue to resolve for 90 days. |
status, api_trigger_enabled | Both must allow API runs. inactive or false refuses a create with 409. A Format that you never ran over the API can show inactive / false until its first run, and it still runs. Do not gate your integration on a poll that shows them as true. |
io | What the Format takes and makes. input_kind is url, text, image or product. output_kind is video, image or text. It is null on Formats saved before this field existed. |
showcase | A real output that the Format produced at registration, or null. |
generation_spend_cap_usd_micros | The cap that a run inherits when it names no cap of its own. It is $400 for a Format that never set a cap. |
version | Sume bumps it on every edit. The receipt's format.version shows which version ran. |
package_sha, contents_url | The package behind the Format, for the Contents API. |
By design, the recipe body is not in this shape. The body goes to the agent, not to the caller.
Formats by Sume answer at the reserved sume handle, POST /v1/formats/sume/{slug}/runs,
with any key that carries the scopes. The run, its media and its spend belong to the key that
made the call. Refer to the Format catalog.
Every Format with an address also has a call sheet on this site at
https://docs.sume.com/formats/{handle}/{slug}. The call sheet is a share link with the curl,
scopes and poll loop for that Format. It shows nothing from the Format body.
Instruction composition
The agent gets these parts, in this order:
The Format comes first because it is the how, and your instruction comes after it. Thus,
where the two do not agree, the model does what you asked for. Sume writes your input to
/workspace/inputs/sume-action-input.json, whole at any size up to the cap. Sume tells the
agent to read it as data, never as instructions. If you open the run's thread_id in Agents,
the first message is this text, with no changes. When a run did something that you did not
expect, read this message first.
SKILL.md
The body has no size limit other than the 100 MiB per file and per package that applies to
every package file. Size changes how reliably the agent follows a recipe, not if the recipe
runs. Keep SKILL.md a short index that the agent can hold at one time. Put detail into
references/*. These files sit adjacent to the body and cost nothing until the agent opens
them. The Contents API covers authoring.
Attachments
A run can carry up to 30 images that the agent can look at, as attachments[] on the create body:
| Field | Required | Notes |
|---|---|---|
type | yes | input_image, the only type at this time. |
image_url | one of | Public HTTPS URL. Sume fetches it when you create the run. Thus, Sume must be able to get it without auth. |
asset_id | one of | An image that you uploaded through the Assets API. The image must be ready and in the same workspace. |
filename | no | The label that the agent sees. The default is the URL's basename. |
Sume fetches every attachment at create time. Sume examines its real type and size and copies
it into durable storage. Thus, a broken or private image fails the create with a 4xx/5xx
that you can act on. The image does not stop the run minutes later. Sume does not copy an
asset_id or a URL that is already on media.sume.com again.
| Limit | Value |
|---|---|
| Types | JPEG, PNG, WebP, GIF, AVIF |
| Images per run | 30 |
| Bytes per image | 30 MB |
| Bytes per run | 500 MB |
input
Many Formats take their references through input fields, not attachments: host_image_url,
product_image_urls[], input_reference_image_urls[], narration URLs. These references also
count against one budget that they share with attachments[]. The budget is 30 files per run
in total, with a maximum of 30 images, 10 videos and 10 audio files. Sume checks by file type,
not by field name.
An HTTPS URL at any location or depth in input counts if its filename ends in a media
extension. A product page URL does not count. The same URL counts one time, also if it occurs
more than one time. Media that the agent finds itself during the run is not yours and does not
count. If you go over any of these limits, the create fails with 400 invalid_attachment.
Attachment errors
| Status | Code | Cause |
|---|---|---|
400 | invalid_attachment | Wrong type, missing or non-HTTPS URL, both image_url and asset_id, too many items, or a source that is not a permitted image type. |
400 | attachment_not_found | asset_id is unknown in this workspace. |
413 | attachment_too_large | An image is over 30 MB, or the set is over 500 MB. |
502 | attachment_fetch_failed | Sume could not fetch the image. Causes: unreachable host, hotlink protection, or a non-2xx answer. details.index names the attachment. |
Idempotency-Key covers attachments. If you replay a key with a different image list, you get
409 idempotency_conflict. A true replay does not fetch your images again.
What the API does not do
- No push channel for progress. The API has no SSE or WebSocket stream.
events_urlis a polled phase timeline (preparing,running,finalizing), not agent output or logs. Sume pushes the completion through the webhook. - No list of all runs. You list runs per Format (
GET /v1/formats/{handle}/{slug}/runs) and read them one at a time at/v1/format-runs/{run_id}. There is noGET /v1/format-runs. - Team Formats need a team key. You can call a Format that a team workspace owns only with a key created in that workspace. This applies to both URL shapes. A personal key fails with
403 workspace_key_required. Refer to Create a run. - Images only as attachments.
input_imageis the only attachment type. Send documents by URL ininput. Send video or audio references in the same way. - Authoring is a separate surface. Create and edit the package over the Contents API, or in the dashboard. The run endpoints only execute.
Next
- Create a run: the request body, idempotency, spend caps, keys, and every create error
- Runs and results: the receipt, polls, webhooks, and how to continue and cancel a run
- Structured output: bind a schema and get typed JSON back
- Errors and spend: every code in one place, credits, rate limits
- Cookbook: copy-paste recipes for a real-shaped run, a webhook receiver, a scene retry, a batch
- Bulk runs: queue up to 100 runs with a concurrency window
- Format catalog: ready-made Formats by Sume
- Embed a Format in your product: key custody, spend tiers and artifacts for a multi-tenant product