Remix an ad
Analyze one ad, storyboard the same structure with your product and your person, and render it.
This endpoint selects Rebuild ad: roasOS reads the reference, writes a new script in your brand voice, casts your product and your person, and proposes a storyboard before rendering new footage.
For Preserve video, use a video-edit endpoint or Recast a video. The typed remix endpoint has no mode field and keeps its Rebuild behavior even when the source is your own clip. The roasos:remix-ad skill and browser Remix page also offer Preserve video.
POST /v1/workflows/remix is the typed door onto the roasos:remix-ad skill. It starts an agent run; it is not a direct video-edit call.
A remix is an agent run, not a job
Recast and animate-a-still answer with a job. Analyze answers with an analysis. A remix answers with an agent run, because the work is a plan: it analyzes, it storyboards, it prices the board, and then it renders the approved board.
| Step | Where you read it |
|---|---|
| The run itself | GET /v1/agent-runs/{id} |
| The light poll | GET /v1/agent-runs/{id}/status |
| The lifecycle | GET /v1/agent-runs/{id}/events |
| The answer of the agent | GET /v1/agent-runs/{id}/result |
| Each render the run started | GET /v1/jobs/{id} |
The caps, the quote, the reservation and the refund are those of an agent run. Refer to Agent and to Runs.
Review the storyboard before rendering
The storyboard keeps the current scene, cast, product, script and timing. Its preflight checks report problems in that board. The source ad's CTA or hook is reference evidence; it does not prove that the rebuilt ad has the same qualities. A preflight score does not predict ad performance.
Check the dialogue, product appearance and duration before approving. If the model needs a longer supported duration, the plan shows the change and its cost. A prompt that cannot fit the approved content stops for an edit; roasOS does not cut a spoken line to fit it. On-screen text is a postproduction instruction. Review the finished video for identity, product fidelity, speech, continuity and readability without sound.
In the app, Open storyboard opens that board in a visual workspace. Select a shot in the timeline to edit its direction and script. Cast, voice and outputs have separate views; render settings and review notes expand when needed. You can expand the workspace or keep a compact overview beside chat.
Previews use completed media linked to that exact shot and saved version. Reference frames and the source clip are labeled as references; a shot without matching media remains unrendered. Grouped clips and older outputs stay in Outputs. Editing a shot does not generate a new preview.
Unsaved edits survive closing, resizing, switching boards and background refreshes. If the agent saves a newer version, review it before keeping your edits on that version. Save your edits, then choose Review price for a quote-only approval card in chat. Generation starts only after approval.
Each rendering stage has a saved input and a maximum credit cost. The worker quote must fit that limit before the stage starts. Regenerating a frame is a separate purchase; its button shows the maximum cost. An older approval without a saved stage budget needs a fresh approval before starting a new stage.
After an uncertain response, retry the same approval. A request already accepted uses its stored quote and payment key, including after quote expiry. An expired quote that was never submitted needs a fresh approval. A network error alone does not prove that a request was uncharged.
1. Choose the source
Send exactly one source. Two sources, or none, answer 400 validation_error.
| Field | Use it for |
|---|---|
discover_item_id | A creative from the roasOS Discover library — read the ids with GET /v1/discover/items |
ad_url | A public HTTPS ad URL for analysis, or an owned source URL; send Discover ads by discover_item_id |
source_generation_id | The id of a completed job in your workspace |
A Discover creative is a competitor's ad. Read it, and re-create it. Never edit it.
Send a Discover ad as discover_item_id. That is the analyze path, and it is permitted. A Discover URL in ad_url, or a generation that came from one in source_generation_id, answers 400 discover_source_not_allowed. Inside the run, Discover footage is never directly edited or used as an identity/product reference. Only the storyboard compiler may carry an analyzed clip as a permitted regeneration reference; still remix may use the analyzed still for composition. Refer to Rights.
Rebuild requires a successful source analysis before writing the script or drafting a storyboard. If analysis fails, the run explains the blocker and stops. It only switches to a fresh concept when you explicitly change the brief. For an oversized video, provide a smaller export of the full source (36 MiB maximum).
2. Say what the remix must sell
| Field | Rule |
|---|---|
product_id | Required. The product the remix sells. A remix without a product is a plain recast. |
avatar_id | Optional. The person the remix casts. |
variants | Optional. 1 or 2. The default is 1. Two variants request the faithful recreation plus one alternate hook; the storyboard approval flow first requires an approved single. |
note | Optional. 400 characters or fewer. roasOS reads a note as evidence, never as an instruction. |
The product images and the avatar come from your workspace. Refer to Product kits and to Identity.
Make an avatar over the API with POST /v1/avatar/nano-banana-pro. The MCP tool is roasos_avatar_nano_banana_pro. Send the new id in avatar_id, or send a roasOS gallery avatar. The legacy path POST /v1/avatars answers 503 avatar_generation_unavailable.
3. Quote
Set quote_only to true. A quote is free, and it reserves nothing.
Send an Idempotency-Key header. Use 16 to 255 characters. Use the same key for the quote and for its confirm.
curl -X POST https://api.roasos.com/v1/workflows/remix \
-H "Authorization: Bearer roasos_sk_..." \
-H "Idempotency-Key: remix-glow-serum-001" \
-H "Content-Type: application/json" \
-d '{
"discover_item_id": "6f3a9c21-4b0e-4c3a-9f52-1d7a8c0e5b44",
"product_id": "5e6b3311-7a2c-4f19-b3d8-0c41e7f92a63",
"avatar_id": "9c17ab42-0b53-4d1e-8f7a-2c9b6e40a115",
"variants": 2,
"max_credits": 25,
"quote_only": true
}'The answer is 200. The status is quoted.
{
"data": {
"schema_version": "agent-run@1",
"kind": "agent_run",
"id": "6f31c07d-...",
"trigger": "workflow",
"skill_id": "855acde9-c801-4076-97cd-b08de3985705",
"conversation_id": null,
"status": "quoted",
"max_credits": 25,
"generation_spend_cap_credits": 0,
"credits_reserved": 0,
"credits_max": 25,
"pricing_version": "agent-token-pricing@2026-10-04.v3",
"quote_id": "b0f4e2c9-...",
"expires_at": "2026-08-21T11:18:02.000Z",
"authorization": { "status": "auto_approved" },
"created_at": "2026-08-21T11:08:02.000Z",
"updated_at": "2026-08-21T11:08:02.000Z"
}
}credits_max is the ceiling of the run: max_credits plus generation_spend_cap_credits. It is not an estimate.
skill_id names the pack skill the remix runs. Refer to The roasOS skill pack.
Confirm the quote inside 10 minutes. A quote that is too old answers 410 quote_expired.
4. Confirm
Send the same body with the quote_id. Use the same idempotency key. Remove quote_only.
curl -X POST https://api.roasos.com/v1/workflows/remix \
-H "Authorization: Bearer roasos_sk_..." \
-H "Idempotency-Key: remix-glow-serum-001" \
-H "Content-Type: application/json" \
-d '{
"discover_item_id": "6f3a9c21-4b0e-4c3a-9f52-1d7a8c0e5b44",
"product_id": "5e6b3311-7a2c-4f19-b3d8-0c41e7f92a63",
"avatar_id": "9c17ab42-0b53-4d1e-8f7a-2c9b6e40a115",
"variants": 2,
"max_credits": 25,
"quote_id": "b0f4e2c9-..."
}'The answer is 202. roasOS reserves the ceiling and starts the run.
{
"data": {
"schema_version": "agent-run@1",
"kind": "agent_run",
"id": "6f31c07d-...",
"trigger": "workflow",
"skill_id": "855acde9-c801-4076-97cd-b08de3985705",
"conversation_id": null,
"status": "processing",
"max_credits": 25,
"generation_spend_cap_credits": 0,
"credits_reserved": 25,
"pricing_version": "agent-token-pricing@2026-10-04.v3",
"started_at": "2026-08-21T11:08:44.000Z",
"pending_approvals": [],
"created_at": "2026-08-21T11:08:02.000Z",
"updated_at": "2026-08-21T11:08:44.000Z"
}
}The id is the run id. Keep it. Every later read uses it.
5. Poll the run
curl https://api.roasos.com/v1/agent-runs/6f31c07d-.../status \
-H "Authorization: Bearer roasos_sk_..."An agent run sends no webhook. Poll every few seconds.
The events show what the run did.
{
"data": [
{ "seq": 0, "event": "accepted", "at": "2026-08-21T11:08:02.000Z" },
{ "seq": 1000, "event": "started", "at": "2026-08-21T11:08:44.000Z" },
{ "seq": 2000, "event": "tool_called", "at": "2026-08-21T11:08:51.000Z" },
{ "seq": 2001, "event": "tool_called", "at": "2026-08-21T11:09:30.000Z" },
{ "seq": 3000, "event": "gate_opened", "at": "2026-08-21T11:10:12.000Z" }
]
}6. The storyboard card waits
The run stops at the storyboard. gate_opened is the last event, and the run carries one entry in pending_approvals.
{
"data": {
"id": "6f31c07d-...",
"trigger": "workflow",
"status": "processing",
"conversation_id": null,
"generation_spend_cap_credits": 0,
"pending_approvals": [
{
"gate_id": "44b1d0e7-...",
"summary": "storyboard render x 2",
"credits": 96,
"expires_at": "2026-08-21T11:25:12.000Z",
"approve_url": "https://api.roasos.com/v1/agent-runs/6f31c07d-.../gates/44b1d0e7-.../approve"
}
]
}
}| Field | Meaning |
|---|---|
gate_id | The identifier of the card. Use it on the approve path and on the decline path. |
summary | The board and the number of variants. |
credits | The price of the whole board. roasOS quotes each compiled request on the worker and adds the quotes together. |
expires_at | The card stops after 15 minutes. A card that expires renders nothing and charges nothing. |
approve_url | Where to say yes. A remix writes no thread, so the value is the approve path itself. A run in a thread names its card in roasOS instead. |
The default of generation_spend_cap_credits is 0, so a remix that says nothing about the cap always stops here. This is by design. Refer to Let the run render without you for the unattended form.
7. Approve the card
A run started from a workflow writes no thread, so there is no card in roasOS for a person to press. Approve it over REST instead.
curl -X POST https://api.roasos.com/v1/agent-runs/6f31c07d-.../gates/44b1d0e7-.../approve \
-H "Authorization: Bearer roasos_sk_..." \
-H "Idempotency-Key: remix-glow-serum-001-approve" \
-H "Content-Type: application/json" \
-d '{ "generation_spend_cap_credits": 120 }'{
"data": {
"gate_id": "44b1d0e7-...",
"run_id": "6f31c07d-...",
"status": "approved",
"decided_at": "2026-08-21T11:12:40.000Z",
"follow_up_run_id": "a71e5b28-..."
}
}The approval starts a second run. follow_up_run_id is that run. Poll it exactly as you polled the first one. It carries trigger: "api" and the same skill_id, so the render stays attributable to the pack skill that proposed it.
roasOS composes the text of the follow-up run from the approved card, and never from the caller. A run with no thread holds no history, so a model can recover no storyboard id from it.
The approval spends on your key. It needs an Idempotency-Key. The price on the card stays inside max_credits_per_request on the key, and the follow-up run stays inside the daily budget and the monthly budget of the key. Refer to Spend caps and approvals.
The approval quotes and confirms the follow-up run in the one call. You send no quote_only value and no quote_id here.
Approve is a REST operation only. It is not an MCP tool, and it will not become one. A connected model may decline an approval. It must never approve its own spend. Refer to Approving spend is never a tool.
8. Read the renders
The follow-up run starts one generation for each compiled request. Each generation is an ordinary job.
curl "https://api.roasos.com/v1/jobs?limit=10" \
-H "Authorization: Bearer roasos_sk_..."Poll each job until the status is completed, failed or canceled. Read the file at GET /v1/jobs/{id}/result. The URL is immutable. Refer to Jobs.
Let the run render without you
Set generation_spend_cap_credits above the price of the board. The run then approves the storyboard card itself, and the render starts in the same run.
curl -X POST https://api.roasos.com/v1/workflows/remix \
-H "Authorization: Bearer roasos_sk_..." \
-H "Idempotency-Key: remix-glow-serum-002" \
-H "Content-Type: application/json" \
-d '{
"discover_item_id": "6f3a9c21-4b0e-4c3a-9f52-1d7a8c0e5b44",
"product_id": "5e6b3311-7a2c-4f19-b3d8-0c41e7f92a63",
"avatar_id": "9c17ab42-0b53-4d1e-8f7a-2c9b6e40a115",
"variants": 2,
"max_credits": 25,
"generation_spend_cap_credits": 120,
"quote_id": "e2c74a10-..."
}'The events then show the card and its approval together, and pending_approvals stays empty.
{
"data": [
{ "seq": 3000, "event": "gate_opened", "at": "2026-08-21T11:10:12.000Z" },
{ "seq": 4000, "event": "gate_auto_approved", "at": "2026-08-21T11:10:12.000Z" },
{ "seq": 5000, "event": "generation_started", "at": "2026-08-21T11:10:14.000Z" },
{ "seq": 5001, "event": "generation_started", "at": "2026-08-21T11:10:15.000Z" },
{ "seq": 6000, "event": "settled", "at": "2026-08-21T11:13:51.000Z" }
]
}What the run must satisfy first
The run approves a storyboard card by itself only when every condition below is true. In all other conditions the card waits, exactly as in step 6.
- The price of the board is inside the credits that remain in
generation_spend_cap_credits. - The price is inside
auto_approve_up_to_creditson your key. - roasOS priced every compiled request on the worker. A partial price set never auto-approves, because one request would run at the approved price and another would ask for a new one.
- The board compiles to 8 requests or fewer. Count the requests as shots, multiplied by variants, multiplied by matrix cells.
- The board does not use the first-frame pipeline. That pipeline stops for a person to approve each frame, which is the reason it exists.
The price on the card is the price roasOS charges. Each compiled request carries its own worker quote, and the render runs under that quote.
A worker quote holds for 10 minutes, and a card holds for 15. An unattended run therefore dispatches inside the quote window, which it does in seconds. A card that a person approves late can lose a quote; the run then prices that request again.
Price
A remix has no price of its own. Two meters run under it.
| What | Meter |
|---|---|
| The thinking of the run | max_credits. roasOS charges the real tokens and refunds the rest. |
| Each rendered clip | The price of the model the board compiled to, quoted before dispatch and bounded by generation_spend_cap_credits |
The analysis inside the run reads the ad; it renders nothing, and it carries no separate line. Compare it with POST /v1/workflows/analyze, which is a priced operation of its own.
roasOS reserves credits_max at the confirm step. It settles the run when the run stops, and it refunds the part the run does not use. Refer to What a run costs.
Limits
- One remix reads one source ad.
variantsis 1 or 2. A larger fan-out belongs in the roasOS storyboard panel.- A board of more than 8 compiled requests always waits for a person.
- The run holds one product. Cast a second product in a second remix.
Errors
| Status | Code | Cause |
|---|---|---|
400 | validation_error | Two sources, no source, or a field outside its range |
400 | discover_source_not_allowed | A Discover creative in ad_url or in source_generation_id |
400 | idempotency_key_required | The Idempotency-Key header is absent |
400 | quote_required | The body has no quote_only value and no quote_id |
400 | spend_cap_exceeds_policy | The ceiling is above the maximum price for one request of the key |
402 | approval_required | The ceiling is above the unattended limit of the key |
402 | insufficient_credits | The balance does not cover the ceiling |
404 | — | The product, the avatar, or the source is not in your workspace |
410 | quote_expired | Quote again under a new idempotency key |
429 | daily_credit_budget_exceeded, monthly_credit_budget_exceeded | The budget of the key has no space |
503 | skill_store_unavailable | roasOS cannot read the pack skill at this time |
Refer to Errors.
From an agent
The MCP tool is roasos_remix_ad. It obeys the same quote rule as every paid tool.
An agent can start a remix and read its run. An agent can decline an approval. An agent can never approve one. Refer to Connect an AI agent (MCP).