# Ask our agent

Say what you want made, and our agent makes the whole video with you: it writes the script, makes the frames and the clips, and checks with you on the way. It asks before each paid step, unless you give it a spending cap. You can run it from the dashboard (Home, "Ask our agent") or from your code with one key.

## How a run works

1. `POST /v1/agent/runs` with your `prompt`. You get a `run_id` at once, and the run is `running`.
2. Read `GET /v1/agent/runs/{run_id}` about every 10 seconds. `message` is what the agent says now; `messages` is the whole conversation.
3. When the agent needs you, `waiting_for` says what for:
   - `answers` (status `needs_input`): read `questions[]` (some have `options`) and answer them all in one reply: `POST /v1/agent/runs/{run_id}/messages` with `{"text": "..."}`. With no questions, the agent paused: say go on with `POST /v1/agent/runs/{run_id}/approve`.
   - `quote` (status `needs_approval`): the next paid step costs about `quote_usd`. Say yes with `POST /v1/agent/runs/{run_id}/approve`, or ask for a change with a reply.
   - `checkpoint` (status `needs_approval`): a script, frames or a first clip waits in `checkpoints[]`. Approve it (`POST /v1/agent/runs/{run_id}/approve`, optionally with its `checkpoint_id`), or reply with a change.
4. When the run is `succeeded`, `output.videos[].url` holds the finished video (and `output.images`, `output.audio`; `output.text` holds a written answer, such as hooks or a script). Download it right away.

Send `"approval": "auto"` with `max_price_usd` and the agent 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.

```bash
curl -s https://vidlab.ai/v1/agent/runs \
  -H "Authorization: Bearer $VIDLAB_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: coffee-ad-1" \
  -d '{"prompt": "A 20 second 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 request

| Field | Type | What it is |
| - | - | - |
| `prompt` | string, 3 to 8,000 characters | What you want made, in plain words. Required. |
| `model` | `opus-5.5` | The agent's model. The default. |
| `effort` | `medium`, `high` | How hard it thinks at 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 agent 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 |
| - | - | - |
| `POST` | `/v1/agent/runs` | Starts a run. |
| `GET` | `/v1/agent/systems` | What the agent can make (public, no key; see below). |
| `GET` | `/v1/agent/runs` | Your runs, newest first (`?limit=` 1 to 100). |
| `GET` | `/v1/agent/runs/{run_id}` | Reads a run. |
| `POST` | `/v1/agent/runs/{run_id}/messages` | Replies to the agent: `{"text": "..."}`, optionally with `inputs`. |
| `POST` | `/v1/agent/runs/{run_id}/approve` | Says yes: to the next step's price, or past a checkpoint (`{"checkpoint_id": "..."}` optional). |
| `POST` | `/v1/agent/runs/{run_id}/cancel` | Stops the run. Safe to repeat. |

Every call needs your key. Dashboard keys have full access; a scoped key needs the `runs` scope.

## What it can make (Systems)

`GET /v1/agent/systems` (no key) lists the agent's systems: `id`, `name`, `description` (what it makes), `kind` (`video` or `image`), `length_seconds` (`min`, `max`), the `inputs` it asks for (`name`, `label`, `type`, `required`, `options`), a `thumbnail_url` and a rough `price_usd` (`min`, `max`). `available` is `false` while the agent is not switched on yet; the list is then our formats. To make one, start a run whose prompt names it ("Make a Drama ad for ..."). The answer may be cached for 10 minutes. The dashboard shows it as Systems.

## 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 agent says now, and the conversation: `role` (`agent` 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 agent. |
| `output` | Once `succeeded`: `videos[].url`, `images[].url`, `audio[].url`, `text`, `media_cost_usd`. |
| `price` | `agent_usd` (the agent's own work 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 model 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 agent's own work** (its thinking and writing) is billed as it goes and shows in your usage logs as "Agent". `price.agent_usd` is 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. |
| `agent_rate_limited` | 429 | Too many new runs and replies for now: wait `Retry-After` seconds. |
| `agent_run_not_found` | 404 | A run is visible only to the account that started it. |
| `agent_run_ended` | 409 | The run is over: start a new one. |
| `agent_run_conflict` | 409 | The agent could not take that now (it is working, or nothing waits for your yes). Read the run and try again. |
| `agent_not_available` | 404 | Our agent is not switched on yet. Run a [format](/vidlab-api/docs/formats) or a model instead. |
| `agent_unavailable` | 503 | Our agent is not available right now. Try again later, or run a model yourself (`POST /v1/generations`). |
