---
title: Know the cost before you spend
description: Your agent prices every paid call with a dry run, caps it with max_credits, and tells you the price before it spends.
---
Your agent knows the price of a generation, a transcript or an upscale before it starts one. It runs a dry run, which prices the call and spends nothing. Then it runs the real call with a cap, so nothing starts above the price you agreed to. A retry after a timeout does not pay twice.

Edits and exports are free. Generation and transcripts cost credits. Paid stock costs a small credit charge, or one of your workspace's iStock licenses. Your agent runs a dry run first and tells you the price before it spends anything. For prices, see [Credits](/account/credits).

Your agent runs a dry run first. For any call that costs 1 credit or more, it tells you the price and waits for your yes. A call under 1 credit runs without asking, and your agent tells you what it cost.

## Quickest path

Set up your agent first with [invideo for AI agents](/agents). Then give it this rule once, at the start of the session:

```text
Before any call that costs credits, run it with dry_run and tell me the
price. Pass max_credits and an idempotency_key on every paid call. Wait
for my yes before you spend.
```

In a chat app, your agent shows you the price in the chat. In a terminal, it prints the dry run answer, then runs the real command with `--max-credits`.

## How it works

Three fields control spending. They work the same on `generate` and on the `media` ops that cost credits.

- **`dry_run`** checks the inputs and returns the price. Nothing starts and nothing is spent.
- **`max_credits`** is the most a call may cost. Nothing starts when the price is higher. `generate` needs it on every call that is not a dry run. A `media` op needs it when the op costs anything.
- **`idempotency_key`** is any text unique to one call, like a UUID. A retry with the same key finds the first call's result instead of paying twice.

Credit prices by model are on the <a href="https://invideo.io/help/billing/video-model-pricing/" target="_blank">video</a>, <a href="https://invideo.io/help/billing/image-pricing/" target="_blank">image</a> and <a href="https://invideo.io/help/billing/audio-pricing/" target="_blank">audio</a> pricing pages. The dry run is the price of one specific call. Some prices are estimates. When `pricing` says the price is an estimate, the final charge can end above it.

### What costs credits and what is free

Most of the work on a timeline is free. The paid calls are generation, transcripts, the model ops in `media`, and stock.

| Free | Costs credits |
| --- | --- |
| Every `edit_timeline` change | `generate` with any model |
| `export`, in every format | `media` `audio.transcript`, on the call that starts it |
| `capture`, `check_timeline`, `get_timeline` | `media` model ops: `audio.separate`, `audio.clean`, `video.upscale`, `image.upscale`, `video.removeBackground`, `image.removeBackground` |
| `media` reads: `metadata`, `video.frames`, `audio.waveform`, `audio.loudness`, `audio.content`, `audio.beats` and the other audio reads | `add_media` with `stock`, at the cost the search result shows |
| `find_models`, `get_model`, `search_library` | |

`document.pages` and the `media` tool ops that make a file without a model, like `video.trim`, `video.loop` and `image.crop`, can show a charge. The dry run shows its price before anything starts.

A transcript charges once. Your agent calls `audio.transcript` again with the same file to follow it, and later calls spend nothing.

Stock has no dry run. `search_library` shows each result's `cost`, and searching and looking are free. Your agent tells you the cost before it adds a paid stock item with `add_media`.

### Check, then preview, then render

Spend credits last. Work in this order:

1. **Check.** Run the dry run. It checks the inputs and gives the price for free.
2. **Preview.** Look before you pay for the full thing. On a timeline, `capture` shows frames for free. For a generation, try a short or low resolution take first, where the model's inputs allow it. `get_model` lists the inputs.
3. **Render.** Run the full call with `max_credits` and an `idempotency_key`.

## Steps

The agent follows these steps for every paid call.

<Steps>
<Step title="Find the price">
The agent runs `find_models` with the job in words and picks a model. A good pick for a video shot is `seedance_2_5.r2v`. It runs `get_model` for the model's inputs, then calls `generate` with `dry_run: true`. Expected result: a price and no new sequence.
</Step>
<Step title="Tell you the price">
The agent tells you the price in credits, and says when it is an estimate. It follows the rule at the top of this page. Expected result: your yes, or a change to the request.
</Step>
<Step title="Run it with a cap and a key">
The agent calls `generate` with `max_credits` at the agreed price and a new `idempotency_key`. Expected result: a thread URL at once.
</Step>
<Step title="Follow it without paying again">
The agent follows the job with `status` or `read`, at the time `retry_after_s` gives. Expected result: status `completed`. The agent never calls `generate` again to check on a job.
</Step>
<Step title="Stop on a hold">
When the status is `needs_confirmation`, only you can confirm it, in invideo. When it is `held`, a safety review is running and the job is not over. Expected result: the agent tells you and waits.
</Step>
</Steps>

The same flow from a terminal:

```bash
invideo gen models <project-url> --query "slow product shot"
invideo gen model <project-url> --model seedance_2_5.r2v
invideo gen run <page-url> --model seedance_2_5.r2v --dry-run \
  -i prompt="slow push on the bottle"
invideo gen run <page-url> --model seedance_2_5.r2v \
  --max-credits <price> --idempotency-key bottle-push-1 \
  -i prompt="slow push on the bottle"
invideo status <thread-url> --wait
```

Where each value comes from: `<project-url>` from `invideo project new`, and `<page-url>` from `invideo notebook show <project-url>`, which lists the notebook pages. `<price>` is the price the person agreed to, from the dry run's `.estimated_credits`. `<thread-url>` is the `url` the paid run returns. A retry uses the same key, so it finds the first run.

A `media` op that costs takes the same flags:

```bash
invideo media audio.transcript <sequence-url> --dry-run
invideo media audio.transcript <sequence-url> --max-credits <price>
invideo media video.upscale <sequence-url> --dry-run
```

`<sequence-url>` is the file's sequence URL, from `add_media` or `invideo asset upload`. Ops that cost or make a file refuse a media bin id with `--asset`.

The key MCP call is the arguments of `generate` for a dry run. `<page-url>` is a notebook page from `read` on the project.

```json
{
  "url": "<page-url>",
  "model": "seedance_2_5.r2v",
  "inputs": { "prompt": "slow push on the bottle" },
  "dry_run": true
}
```

Your agent checks the credits you have left with `current_user`. In a terminal, `invideo auth status` shows them.

## If something goes wrong

Most cost problems come from a retry without a key, or a cap that is too low.

| Symptom | Fix |
| --- | --- |
| `get_model` or `generate` refuses the model as not found | Models retire. Run `find_models` with the job in words, use the best match, and tell the person which model you used. |
| Refused because the price is above `max_credits` | Nothing started. Tell the person the new price, then run again with a new cap. |
| CLI exit 5, a limit: credits or quota | Stop and tell the person. Credits are listed in [Credits](/account/credits). |
| CLI exit 8, needs the person's confirmation | Stop. The person confirms it in invideo. |
| Exit code 6, or `status` is `held` | A safety review, not a refusal. Wait, then run `invideo status <url> --wait` again. Do not resend. If it ends `failed`, change the input the review flagged. |
| Status `needs_confirmation` | Only the person can confirm it, in invideo. Tell them and wait. |
| The dry run refuses an input | Fix the input the `message` names, and run the dry run again. |
| A call returns `completion_unknown`, or times out | Retry the same call with the same `idempotency_key`. It finds the first call. |
| The final charge is above the dry run price | The price was an estimate. Say so before the next estimated call. |
| Avoid: calling `generate` again to check on a job | Instead: `read` or `status` the thread URL. |
| Avoid: a retry with a new `idempotency_key` | Instead: retry with the same key, so it does not pay twice. |
| Avoid: spending first and telling the person after | Instead: dry run, tell the price, then spend. |

## Related

- [Credits](/account/credits)
- [Check your video before you say it is done](/how-to/check-your-video)
- [Run invideo in CI and on servers](/how-to/ci-and-servers)
- [Models reference](/reference/models)
- [Exit codes](/reference/exit-codes)