Run a system
A system makes a whole video for you, start to finish: a Drama Ad, a Street Interview, a Product Commercial and the rest. Name a system or just describe the video; the run plans and makes it; you approve the quote and the checkpoints. You call it from your code or your own agent with one key.
How a run works
POST /v1/system-runswith what you want made (prompt), and optionally thesystem. You get arun_idat once, and the run isrunning.- Read
GET /v1/system-runs/{run_id}about every 10 seconds.messageis what the run says now;messagesis the whole conversation. - When the run needs you,
waiting_forsays what for:answers(statusneeds_input): readquestions[](some haveoptions) and answer them all in one reply:POST /v1/system-runs/{run_id}/messageswith{"text": "..."}. With no questions, the run paused: say go on withPOST /v1/system-runs/{run_id}/approve.quote(statusneeds_approval): the next paid step costs aboutquote_usd. Say yes withPOST /v1/system-runs/{run_id}/approve, or ask for a change with a reply.checkpoint(statusneeds_approval): a script, frames or a first clip waits incheckpoints[]. Approve it (POST /v1/system-runs/{run_id}/approve, optionally with itscheckpoint_id), or reply with a change.
- When the run is
succeeded,output.videos[].urlholds the finished video (andoutput.images,output.audio;output.textholds a written answer, such as hooks or a script). Download it right away.
Send "approval": "auto" with max_price_usd and the run goes on by itself while its media spend stays within that cap; anything over it waits for your yes. You can still reply or cancel while it works.
curl -s https://vidlab.ai/v1/system-runs \
-H "Authorization: Bearer $VIDLAB_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: coffee-ad-1" \
-d '{"system": "drama-ad", "prompt": "Make a Drama Ad for my coffee brand: a woman in her kitchen, warm morning light", "inputs": {"images": ["https://example.com/bag.png"], "aspect_ratio": "9:16"}}'The systems
GET /v1/system-runs/catalog (no key) lists them: id, name, description (one line of what it is), kind (video or image) and a thumbnail_url. available is false while running systems is not switched on yet. A system is a way of making a video, not a product with a fixed length or price: what a run costs depends on what you ask, and each paid step is quoted before anything is spent. The answer may be cached for 10 minutes. The dashboard shows them on the Systems page, where each has a "Copy API call".
The request
| Field | Type | What it is |
|---|---|---|
prompt | string, 3 to 8,000 characters | What you want made, in plain words. Required. |
system | string | One of the systems (an id from GET /v1/system-runs/catalog). Name it in the prompt too. |
effort | medium, high | How much care goes into each step. Default medium. |
approval | ask, auto | ask (the default): it asks before each paid step and at each checkpoint. auto: it goes on by itself up to max_price_usd. |
max_price_usd | number, up to 1,000 | The most the run may spend on media without asking. Required with auto. |
checkpoints | key, all, none | Where it stops for a look: key (the default: the script and the first clip), all (frames too) or none. |
media | fast, balanced, quality | How the media is made. Default balanced. |
brand_id | string | One of your brands (the app's brand id). Default: your selected brand. The run uses what it knows about it. |
inputs | object | Your files and words: images (up to 10 https links), audio, video (one https link each), product_name, brief, script, aspect_ratio (9:16, 16:9, 1:1, 4:5). Upload a local file first (POST /v1/uploads). |
An Idempotency-Key header makes a resend find the same run for the rest of the UTC day.
Endpoints
| Method | Path | What it does |
|---|---|---|
GET | /v1/system-runs/catalog | The systems (public, no key; see above). |
POST | /v1/system-runs | Starts a run. |
GET | /v1/system-runs | Your runs, newest first (?limit= 1 to 100). |
GET | /v1/system-runs/{run_id} | Reads a run. |
POST | /v1/system-runs/{run_id}/messages | Replies to the run: {"text": "..."}, optionally with inputs. |
POST | /v1/system-runs/{run_id}/approve | Says yes: to the next step's price, or past a checkpoint ({"checkpoint_id": "..."} optional). |
POST | /v1/system-runs/{run_id}/cancel | Stops the run. Safe to repeat. |
Every call but the catalogue needs your key. Dashboard keys have full access; a scoped key needs the runs scope.
The run
| Field | What it holds |
|---|---|
status | queued, running, needs_input, needs_approval, succeeded, failed or cancelled. |
waiting_for | answers, quote, checkpoint, or null while it works. |
message, messages[] | What the run says now, and the conversation: role (system or member), text, at. |
questions[] | While it asks: id, question, options[]. |
quote_usd | While a paid step waits for your yes: about what it costs. |
checkpoints[] | id, kind (script, frames, clip), title, text, media[] (kind, url) and status (waiting, approved, changed). |
warnings[] | Short notes from the run. |
output | Once succeeded: videos[].url, images[].url, audio[].url, text, media_cost_usd. |
price | run_usd (the run's own planning and writing so far), media_usd (the media, once finished) and held_usd (set aside while it runs). |
error | Once failed or stopped: code and message. |
next_action | What to do now, in one sentence. |
What it costs
A run is billed from your balance, the same balance as your generations:
- Each media step (an image, a clip, a voice-over) is an ordinary generation at that model's price, never above the price you approved. Each one shows in your usage logs.
- The run's own planning and writing is billed as it goes and shows in your usage logs under the system's name.
price.run_usdis the total so far. - When a run starts, a small amount (50 credits) is set aside, and it is released when the run ends.
A run stops if your balance runs out (error.code api_wallet_exhausted): what it made stays on the run. A cancel stops the billing at once. A run still going after 72 hours is stopped.
Errors
| Code | HTTP | What to do |
|---|---|---|
invalid_request | 400 | Fix the field the message names. |
unknown_field | 400 | Send only the fields above. |
brand_not_found | 404 | brand_id is not one of your active brands. |
api_wallet_exhausted | 429 | Add credit, then start again. |
system_runs_rate_limited | 429 | Too many new runs and replies for now: wait Retry-After seconds. |
system_run_not_found | 404 | A run is visible only to the account that started it. |
system_run_ended | 409 | The run is over: start a new one. |
system_run_conflict | 409 | The run could not take that now (it is working, or nothing waits for your yes). Read the run and try again. |
not_available | 404 | Running systems is not switched on yet. Meanwhile, run a model (POST /v1/generations). |
system_runs_unavailable | 503 | Running systems is not available right now. Try again later, or run a model yourself (POST /v1/generations). |