---
title: Product promo
description: Call the Product promo Format by Sume from your backend to turn a product URL into ad images or a promo video in a fixed house style.
---

**The job:** hand it a product or brand URL and a short brief, get back ad images or a promo
video. The Format decides the branch — talking-head UGC or product-motion image-to-video — pulls
real product imagery from the URL rather than inventing it, and carries the house style so you do
not restate it on every call.

**Use it when** the task is the same each time and only the product changes. If the task itself
varies per call, use [Agent Completions](/agents/completions) instead.

First-party slug: `sume-product-promo`.

## 1. Address it

Call it at `sume/sume-product-promo` with any key that carries the scopes below. Nothing to fork,
nothing to install: the catalog Format is shared and unowned, and the run, its media and its spend
belong to the key that called.

Forking is still available when you want to *change* the Format — open
[Product promo in the Format library](https://www.sume.com/agents/format) and press **Fork** for an
editable copy owned by you. The fork keeps the body and the spend cap, and takes a new slug (the
dashboard suggests `sume-product-promo-custom`, since a fork must not reuse its source's slug); its
detail page shows it as `{your_handle}/{slug}`. That is a customization step, not a prerequisite
for calling.

## 2. Scopes

| Scope | Needed for |
|---|---|
| `formats:read` | Read the Format, read and list its runs. |
| `formats:write` | Start a run, cancel a run. |

Keys created before Formats shipped do not carry these, and scopes cannot be added to an existing
key — mint a new one at [API Keys](https://www.sume.com/dashboard/api-keys) and rotate to it.
Service-account keys cannot start Format runs.

## 3. Call it

```bash
export SUME_API_KEY="sume_live_..."

curl -sS -X POST "https://api.sume.com/v1/formats/sume/sume-product-promo/runs" \
  -H "Authorization: Bearer $SUME_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "instruction": "Make three square ad images for this product, benefit-led copy, no faces.",
    "input": {
      "product_url": "https://example.com/products/trail-runner",
      "brand": "Northbound",
      "aspect_ratio": "1:1",
      "count": 3
    },
    "generation_spend_cap_usd": 20
  }'
```

The opaque `skl_…` path stays valid for clients that already store it; new integrations should
use `{handle}/{slug}`.

An accepted run returns `202`:

```json
{
  "data": {
    "id": "run_...",
    "object": "format.run",
    "format": { "id": "skl_...", "slug": "sume-product-promo", "version": 1 },
    "status": "queued",
    "status_url": "https://api.sume.com/v1/format-runs/run_.../status",
    "result_url": "https://api.sume.com/v1/format-runs/run_.../result",
    "created_at": "2026-08-02T09:00:00.000Z"
  }
}
```

Send `Idempotency-Key` on every call. A replay with the same body returns `200` and the original
run; a replay with a different body returns `409 idempotency_conflict`.

### About `input`

`input` is free-form JSON, fenced into the prompt as caller data and never as instructions —
**concatenated**, not validated against a wire schema. Use whatever shape is convenient for your
backend; the Format body decides which keys it reads. The example above is a realistic shape, not
a contract. Keep it small and literal: at most 64 keys and 8 KiB.

Anything that is a decision belongs in `instruction`. Anything that is data belongs in `input`.
More on composition: [Calling a Format](/formats/call#input-caller-data).

## 4. Spend cap

Promo runs generate paid media, so the cap is the control that matters.

The Format's cap is what a run inherits when it names none. Read the current value from
`PublicFormat.generation_spend_cap_usd_micros`. A Format that never named one gets the platform
default of **$400**; the ceiling you can set is $500.

`generation_spend_cap_usd` on a run names that run's own ceiling, up to $500 — above the Format's
own cap is honored, above $500 is an error. Omit it and the run gets the Format's cap.

## 5. Poll, then read the result

```bash
curl -sS "https://api.sume.com/v1/format-runs/$RUN_ID" \
  -H "Authorization: Bearer $SUME_API_KEY"
```

Statuses are `queued`, `processing`, `completed`, `failed`, `canceled`, `skipped`. Poll
`status_url` for the cheap check; it returns just the status fields and `next_action`.

A `completed` receipt carries `output`, `artifacts[]` — every durable file the run produced — and
`primary_output_url`. Media URLs are durable `media.sume.com` HTTPS URLs and do not expire.

Cancel a run in flight:

```bash
curl -sS -X POST "https://api.sume.com/v1/format-runs/$RUN_ID/cancel" \
  -H "Authorization: Bearer $SUME_API_KEY"
```

Cancel is a no-op once the run is terminal; the current receipt comes back either way.

## Two things that surprise people

**A fresh fork reads as inactive until its first run.** `GET /v1/formats/{format_id}` reports
`status: "inactive"` and `api_trigger_enabled: false` on a copy you just made, because both are read
off a runner that is provisioned lazily. Do not gate your integration on those fields being true —
the first `POST .../runs` provisions the runner and the run proceeds normally. `sume/{slug}` itself
always reads `active`, since the catalog is callable by definition.

**API runs are unattended.** The Format body was written for chat, where it can stop and ask a
person to approve preview stills before the paid step. Over the API nobody is there, so the run is
told those approvals are already granted and to carry on within the spend cap. A run that genuinely
cannot finish comes back `failed` with `output_error.code` of `unattended_blocked` — never a
half-finished `completed`.

## Next

- [Calling a Format](/formats/call) — the full invoke contract and every error code
- [Runs and results](/formats/runs) — receipts, versioning, cancelation
- [Structured output](/formats/structured-output) — bind a schema and get typed JSON back
- [Avatar UGC video](/formats/avatar-ugc) — the talking-head counterpart to this Format
- [OpenAPI](https://api.sume.com/reference) — exact request and response schemas
