Live Commerce API
mobidoo/live-commerce is the Format Mobidoo uses for host-led live commerce
video. You get back a full cut and the individual clips that make it up.
When one clip is wrong, you continue the same thread and ask for that clip
only — not a new production from scratch.
A product URL is the only field the Format needs. Send a host image, a tagged Korean script, and your own prices when you have them and they win; send none of it and the Format derives each one from the product page — a host generated to the product's tone, a script written from the page, and a Korean voice preset.
Use a Mobidoo team workspace API key (created under the Mobidoo team, not a
personal key). A personal key calling mobidoo/live-commerce fails with
403 workspace_key_required — see
Team Formats need a team key.
Not in the Mobidoo workspace yet? Request an invite on Slack to 허채원 (Chase Huh), or email chase@sume.com — see Workspace access.
Create a run
Fill in the fields to rewrite the cURL, TypeScript, JavaScript, and Python snippets.
Run the live-commerce Format
POST /v1/formats/{handle}/{slug}/runs
Required
The call returns a Format run. Poll
status_url / result_url, take a
run webhook (format.run.terminal), or use
subscribeFormatRun. Read
Errors and rate limits before you put it
behind user traffic.
What to send
| Field | Notes |
|---|---|
instruction | Short prose: tone, “use Intro/Mid/Fin as written”, no BGM / no captions, vertical 9:16. |
input | Structured caller data — product, host, price, tagged script. |
output_schema | Bind mobidoo/live-commerce/v1 so the receipt is typed for your ingest. |
primary_output_key | "full_video" — the assembled cut is the primary media field. |
generation_spend_cap_usd | Per-run generation ceiling (clamped to the Format’s own cap). |
There is no separate “JSON mode.” instruction is guidance; input is data.
Same shape as an LLM turn — see Best practices
for one worked create → receipt → clip-retry loop.
keys the recipe recognises
input is free-form JSON concatenated into the prompt — not a fixed request
schema. Shape it however is convenient for your backend. Full rules:
Calling a Format — what is carried
and Structured output.
None of the keys below are hard-required by HTTP. Extra keys ride along as data; missing ones are not an error.
| Key | Effect |
|---|---|
product_url | Page to crawl for specs, copy, and product photos. The one field worth treating as required. |
host_image_url | Person to use as the host (identity for every talk shot). Alias: avatar_image_url. Omit and a host is generated to match the product's tone. |
script.segments | Your script as few long tagged blocks — typically Intro / Mid / Fin. Do not pre-split into dozens of cuts. Omit and the Format writes one from the page. |
vo_language | Spoken language. Defaults to Korean. |
on_card_name | Exact product-name spelling allowed on an on-screen card. |
price | List / sale / discount label when you want those numbers on a card. |
banner_reference_image_urls | Layout references for on-screen cards (media.sume.com URLs). |
variants_per_n | Candidate images per card. Defaults to 1. |
The delivered video is exactly as long as its voice track. To change length, change the script — there is no duration parameter.
Script tags → clip arrays
| Your tag | Receipt array |
|---|---|
Intro | opening[] |
Mid (or Mid · …) | middle[] |
Fin | closing[] |
Send few, long segments (about 3–5), not one object per cut. The Format
decides where cuts fall; pre-splitting into ~45 cut objects wastes the
input size budget and usually makes a worse edit. Details under
Size limits below.
Threads: continue the same production
A Format run is one agent turn. The first successful run starts a conversation. The receipt carries:
| Field | Meaning |
|---|---|
id | This turn’s run id (arun_…). Poll / webhook this id. |
thread_id | Durable conversation id for the whole production. Response-only — never put it in a request body; the API rejects it with unknown_parameter. |
previous_run_id | Echoed when this turn continued an earlier run; otherwise null. |
To revise, create a new run on the same Format and pass
previous_run_id pointing at the finished turn. That is the partner equivalent
of “send another message on the same thread” (like an LLM
previous_response_id). Platform detail:
Continue a run.
Important habits:
- Continue with
previous_run_id, never by postingthread_id. A body carryingthread_idis rejected withunknown_parameter— it is a response field on both turns, not an input. - A continuation is a new run — new id, its own spend, its own single
terminal webhook. The old run stays
completedforever. - Send the same
output_schemaevery turn. Binding is per-run, not inherited. - Group turns in your DB by the shared
thread_id.
Get the clips you asked for
Bind the partner schema (mobidoo/live-commerce/v1) and you receive:
full_video— assembled vertical cutopening[]/middle[]/closing[]— each scene is its own file (scene.video), with a stablescene.id
So you can publish the full cut or pick individual clips for your own editor / QA. Scene ids are frozen for the life of that production — store them; do not key off array index.
Treat scene.id as an opaque string. Current productions return
sc_0, sc_1, … but earlier ones returned other shapes, so validating or
constructing ids against a pattern will break. Store whatever scene.id the
receipt hands you and send that back on the retry.
A realistic first-turn body (Samsung Q9000 short sample — swap URL / copy for your catalog):
A filled Q9000 call, the receipt it returns, and the clip-retry turn: Best practices.
Retry only the clips you want
Built for a dashboard “retry this clip” control: persist create run.id + each
receipt scene.id, then continue the thread with a fixed instruction and the
selected id(s). Do not start a fresh run with the same script unless you
want a new production (new ids, full cost).
When the operator is rejecting a take rather than repairing a stand-in, put
their note in instruction — which scene, what is wrong, how it should change.
See
Prefer concrete per-scene feedback.
Example — one Mid talk clip
Example — two clips that came back stand-in / failed
Neither body carries thread_id. previous_run_id is the whole continuation
contract.
The receipt is again a full opening / middle / closing list — not a
delta and not a patch. Regenerated scenes get new media URLs; every other scene
keeps the URL from the previous turn. Same thread_id on both runs, and
full_video comes back re-assembled with a new URL of its own.
Measured on the production pair in
Best practices — one sc_7 retry on an
11-scene cut: all 11 rows returned, 10 of 11 sibling URLs byte-identical,
only sc_7 moved, full_video re-assembled at the same 73.360 s. The scene's
previous URL still resolves 200 afterwards, so a create receipt you already
persisted stays valid and you can keep both takes.
What clip retry can and cannot change
| Ask | Answer |
|---|---|
| Different take, framing, lighting, or B-roll for named scene ids | ✅ re-render those clips + re-assemble |
Finalize a scene that came back stand-in or failed | ✅ same |
| Different wording, price read, or longer/shorter line | ❌ new full production (voice spine moves) |
| Different host, script, or product | ❌ new full production |
The line is the voice track. Looks change → clip retry. Words change → new production and new scene ids.
A retry is a new generation, not a re-encode. Everything generative in the frame is re-rolled: structured overlay facts (price, discount label, spec badges, set composition) held exactly on the measured pair, but decorative copy rendered inside generated product art changed wording between takes. Tell operators they are getting another take, not the same frame with one detail corrected.
Budgeting a retry
Budget about a twentieth of the create run per single-clip retry when
script, VO, host stills, and every other clip are reused. Measured on
production: $0.742530 against a $14.959638 create — one under_banner
scene on an 11-scene cut, 2m53s wall.
It is a budgeting guide, not a guarantee. A short production spreads its fixed
work over fewer clips, and an earlier 8-scene cut measured closer to a fifth.
Size a dashboard budget from your own first runs and keep
generation_spend_cap_usd on every retry.
Size: two limits, and only one of them tells you
Worth knowing before you send a full broadcast script — the two limits fail in opposite ways.
inputis rejected above 8 192 UTF-8 bytes (and above 64 top-level properties), measured on the compact JSON → loud400.- Each field is then carried into the run cut at ~4 000 characters, keeping the beginning → no error; the tail is simply missing.
So a script of about six minutes or less arrives whole. Past roughly
thirteen minutes you get a clean 400. In between, the call can succeed while
the end of your script never reaches the run.
For a 5–15 minute broadcast, run one call per product block of 1–3 minutes and merge on your side — then retry only the weak block’s thread.
input must be a JSON object (a stringified blob is 400). attachments
carries images only (up to 30), so a script cannot be sent as a file.
Partner FAQ: webhooks
Direct answers to the usual integration questions:
| Question | Answer for Formats API |
|---|---|
| (A) Does a webhook fire per scene as each clip finishes? | No for the Format run webhook. Formats does not emit a Formats response per scene. |
| (B) Does one webhook fire when all scenes for the turn are done? | Yes. When the agent turn completes, you get the final structured receipt and one format.run.terminal webhook. |
Formats calls an AI agent. Tool calls (TTS, clip renders, assemble) may finish at different times underneath, but the partner contract is turn-final: one receipt, one Format run webhook. A scene-regen continuation is a new run and fires its own single terminal webhook.
Job-layer events (per media job) exist for internal progress and are not the published partner scene webhook yet — ask us if you need that mapping.
More detail: Run webhooks.
Webhooks: two layers
| Layer | Unit | Fires |
|---|---|---|
| Format run | one agent turn | once, format.run.terminal, when the turn ends |
| Generation job | one media job | per job, as each completes |
Build on the Format layer. A clip retry fires exactly one new terminal webhook against the new run id.
Partner FAQ: scene regeneration
| Question | Answer |
|---|---|
| Can I regenerate one scene inside a finished production? | Yes — continue the same thread with previous_run_id and name the scene id(s). See Retry only the clips you want. |
| Do I have to re-run the whole video? | Only when wording / host / product / VO spine must change. Looks-only fixes use clip retry. |
| How do I continue the conversation? | Send previous_run_id (not thread_id). Both runs share thread_id on the receipt. |
Platform contract: Continue a run.
Shareable links
Copy-paste for Slack / email.
| Topic | Link |
|---|---|
| Webhook FAQ (A vs B) | https://docs.sume.com/enterprise/mobidoo/live-commerce#partner-faq-webhooks |
| Scene regeneration FAQ | https://docs.sume.com/enterprise/mobidoo/live-commerce#partner-faq-scene-regeneration |
| Threads / continue | https://docs.sume.com/enterprise/mobidoo/live-commerce#threads-continue-the-same-production |
| Clip retry recipes | https://docs.sume.com/enterprise/mobidoo/live-commerce#retry-only-the-clips-you-want |
| Best practices + examples | https://docs.sume.com/enterprise/mobidoo/best-practices |
| KO: webhook FAQ | https://docs.sume.com/ko-KR/enterprise/mobidoo/live-commerce#파트너-faq-웹훅 |
| KO: scene regen FAQ | https://docs.sume.com/ko-KR/enterprise/mobidoo/live-commerce#파트너-faq-씬-재생성 |
Next
- Best practices — create curl, receipt, clip-retry curl.
- Continue a run — platform thread contract.
- Structured output — schema rules.
- Quick start — first generation end to end.

