Format API

A Format is a saved production recipe: a house style, an output contract, a playbook for one kind of video. Your backend calls it by name, Sume runs it in a fresh sandbox with the generation tools, and you get back finished media on media.sume.com plus, when you ask for it, a JSON object in a shape you defined.

This page takes you from an API key to a finished run. The pages after it are the reference behind each step.

Your first run

You need an API key that carries the formats:read and formats:write scopes. Create one at API keys and keep it server-side.

1. List the Formats your key can call

You see what your key's workspace owns plus the ready-made Formats by Sume. vanity_invoke_url is the address you call next.

2. Start a run

202 means a fresh run was accepted. Store data.id. Everything else you need is a URL on the receipt, so you never build a path by hand. Full body reference: Create a run.

3. Take the result

When the run finishes, Sume POSTs the same receipt to your webhook_url as one signed format.run.terminal event. If you would rather poll, read the run until status is terminal:

A finished run reads:

primary_output_url is the one thing to show. artifacts[] is every file the run made. Media URLs are durable and public: store them. Bind an output schema and output comes back in your own shape instead of the built-in one.

That is the whole loop: create, then webhook or poll, then read. Runs that make video take minutes, not seconds. Long-form host video typically finishes in 15 to 30 minutes, so design for the asynchronous path from the start.

Two hosts, one contract

HostUse it forKeys
https://api.sume.comProduction. Runs spend real credits from your workspace.Created at API keys.
https://api.dev.sume.comIntegration and staging. Same routes, same receipts, same webhook delivery.Issued for a development workspace. Ask your Sume contact.

A key works only on the host it was created for; the other host answers 401 unauthorized. Both look like sume_live_…, so name your environment variables by host rather than by prefix. The examples on these pages use production. Swap the host and the key to point them at development.

How a run works

Four pieces are in play on every call:

PieceWhat it isWhere it lives
The recipeThe Format: a SKILL.md body plus reference files. The how: house style, branch rules, quality bar.Authored in the Agents dashboard, in chat, or over the Contents API.
The callYour instruction and input. The what: product URL, brief, script, prices.The request body.
The runOne fresh sandbox, one agent turn, one receipt. Never a partial delivery: a run that could not finish comes back failed.arun_…, at /v1/format-runs/{run_id}.
The resultDurable media plus output, either the built-in shape or one projected onto your schema.The terminal receipt.

Two properties follow. A run is one unit of work: a bulk request is a server-side queue of ordinary runs, not a different engine (Bulk runs). And the recipe is established before your instruction, so you are not re-sending a system prompt on every call and hoping it holds.

This is not chat

A Format run is one unattended turn with the Format attached. It does not stop to ask a person anything: approvals a chat-authored recipe would request are pre-granted, and the run carries on within its spend cap. The Agents chat UI at sume.com/agents is the surface for a human in the loop, and a chat turn does not necessarily attach a Format at all. Build partner integrations on runs, not on chat threads.

Find your Formats

Three reads, all needing formats:read:

CallReturns
GET /v1/formats?limit=50The Formats your key's workspace owns, plus the first-party catalog. Keyset pages: pass next_cursor back as cursor while has_more is true.
GET /v1/formats/{handle}/{slug}One Format by its address.
GET /v1/formats/{format_id}The same Format by its opaque skl_… id.

Visibility follows the key. A personal key lists your personal Formats; a team key lists that workspace's Formats, for every member; neither lists the other's. A Format outside your key's workspace is 404 format_not_found, the same answer as an id that does not exist. If a Format you expect is missing, you are holding the other key.

The fields that matter when you pick one:

FieldNotes
handle, slug, vanity_invoke_urlThe address to call. handle is the owning workspace's handle for a team Format and your own for a personal one; sume for the catalog.
invoke_urlThe opaque skl_… path. Permanent across renames: persist it if a stored URL must survive a handle or slug change. Renamed handles keep resolving for 90 days.
status, api_trigger_enabledBoth must allow API runs: inactive or false refuses a create with 409. A Format you have never run over the API may read inactive / false until its first run, and still runs. Do not gate your integration on polling them true.
ioWhat the Format takes and makes: input_kind is url, text, image or product; output_kind is video, image or text. null on Formats saved before this existed.
showcaseA real output the Format produced at registration, or null.
generation_spend_cap_usd_microsWhat a run inherits when it names no cap of its own. $400 for a Format that never set one.
versionBumps on every edit. The receipt's format.version says which one ran.
package_sha, contents_urlThe package behind the Format, for the Contents API.

The recipe body is deliberately not in this shape; it reaches the agent, not 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 called. See the Format catalog.

Every Format with an address also has a call sheet on this site at https://docs.sume.com/formats/{handle}/{slug}: a share link with the curl, scopes and poll loop for that Format, and nothing from its body.

Instruction composition

What the agent actually receives, in order:

The Format comes first because it is the how; your instruction comes after it, so where the two disagree the model follows what you asked for. Your input is written to /workspace/inputs/sume-action-input.json, whole at any size up to the cap, and the agent is told to read it as data, never as instructions. Open the run's thread_id in Agents and the first message is exactly this text, which is the first thing to read when a run did something you did not expect.

SKILL.md

There is no size limit on the body beyond the 100 MiB per file and per package that every package file shares. Size changes how reliably a recipe is followed, not whether it runs: keep SKILL.md a short index the agent can hold at once, and push detail into references/*, which sit beside it and cost nothing until opened. Authoring lives with the Contents API.

Attachments

A run can carry up to 30 images the agent can look at, as attachments[] on the create body:

FieldRequiredNotes
typeyesinput_image, the only type today.
image_urlone ofPublic HTTPS URL. Sume fetches it when you create the run, so it must be reachable without auth.
asset_idone ofAn image you uploaded through the Assets API, ready, in the same workspace.
filenamenoThe label the agent sees. Defaults to the URL's basename.

Sume fetches every attachment at create time, checks its real type and size, and copies it into durable storage, so a broken or private image fails the create with a 4xx/5xx you can act on instead of killing the run minutes later. An asset_id or a URL already on media.sume.com is not re-copied.

LimitValue
TypesJPEG, PNG, WebP, GIF, AVIF
Images per run30
Bytes per image30 MB
Bytes per run500 MB

input

Many Formats take their references through input fields instead: host_image_url, product_image_urls[], input_reference_image_urls[], narration URLs. Those count too, against one budget shared with attachments[]: 30 files per run in total, of which at most 30 images, 10 videos and 10 audio files. The check is by file type, not field name. Any HTTPS URL anywhere in input whose filename ends in a media extension counts, however deeply nested; a product page URL does not, and the same URL repeated counts once. Media the agent finds for itself during the run is not yours and does not count. Over any of these is 400 invalid_attachment on the create.

Attachment errors

StatusCodeCause
400invalid_attachmentWrong type, missing or non-HTTPS URL, both image_url and asset_id, too many items, or a source that is not an allowed image type.
400attachment_not_foundasset_id is unknown in this workspace.
413attachment_too_largeAn image is over 30 MB, or the set is over 500 MB.
502attachment_fetch_failedSume could not fetch the image: unreachable host, hotlink protection, or a non-2xx answer. details.index names the attachment.

Idempotency-Key covers attachments: replaying a key with a different image list is 409 idempotency_conflict, and a true replay does not re-fetch your images.

What the API does not do

  • No push channel for progress. There is no SSE or WebSocket stream. events_url is a polled phase timeline (preparing, running, finalizing), not agent output or logs. Completion is pushed; that is what the webhook is for.
  • No list of all runs. Runs are listed per Format (GET /v1/formats/{handle}/{slug}/runs) and read one at a time at /v1/format-runs/{run_id}. There is no GET /v1/format-runs.
  • Team Formats need a team key. A Format owned by a team workspace is callable, on both URL shapes, only with a key created in that workspace; a personal key fails with 403 workspace_key_required. See Create a run.
  • Images only as attachments. input_image is the only attachment type. Send documents by URL in input, and video or audio references 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