# Quickstart: CLI (/quickstart/cli)



<SurfaceStatus id="cli" />

One video from your terminal in three commands. The CLI calls the REST API for you.

You need: Node 20.10.0 or newer, and an API key with **Generate** ticked from [app.riffads.com/api-keys](https://app.riffads.com/api-keys) (owners and admins create keys).

## Install and log in [#install-and-log-in]

```bash title="Terminal"
npm install -g riffads
riffads login --base-url https://app.riffads.com
riffads whoami
```

* `login` asks for the key and checks it before saving. A bad key exits `3` and saves nothing.
* `whoami` shows which host and key it will use.

<Callout type="warn" title="Always set the base URL">
  The default base URL is `https://riffads.com`, which has no API. Pass `--base-url https://app.riffads.com` or set `RIFFADS_BASE_URL`. Symptom: `did not answer as a RiffAds API endpoint`.
</Callout>

CI: skip `login`. Set `RIFFADS_API_KEY` and `RIFFADS_BASE_URL`.

## Make your first video [#make-your-first-video]

`veo_31` is text-to-video: one prompt, one generation.

```bash title="Terminal"
CONFIG='{"prompt":"A matte black water bottle on wet slate, morning light"}'

# the estimate prints a bare number on stdout
EST=$(riffads estimate --capability veo_31 --config "$CONFIG")
MAX=$(( (EST * 11 + 9) / 10 ))   # ceil(EST * 1.1)

riffads generate \
  --capability veo_31 \
  --config "$CONFIG" \
  --max-credits "$MAX" \
  --output ./out
```

<Callout type="warn" title="max_credits must be above the estimate">
  `--max-credits` is required. Send at least `ceil(estimate * 1.1)`. The bare estimate is refused with `max_credits_exceeded` (exit `4`).
</Callout>

* `generate` blocks until the job ends, then saves the file to `./out` (for example `./out/gen_8c31fa-0.mp4`).
* stdout prints the generation id first, then file paths. Keep the id.
* Ctrl+C stops waiting, not the render. Download it later:

```bash title="Terminal"
riffads download gen_8c31fa --output ./out
```

Signed links expire in 10 minutes, so `download` takes an id, never a URL.

## Exit codes [#exit-codes]

| Code | Meaning                                                          |
| ---- | ---------------------------------------------------------------- |
| 0    | Worked                                                           |
| 2    | Fix the request (bad flag, bad config, blocked content)          |
| 3    | Fix the key, scope, plan or workspace                            |
| 4    | Not enough credits (top up in the app) or a spend cap blocked it |
| 5    | Refused for now. Send the same call again later                  |
| 6    | The render failed                                                |
| 7    | Only part of the output arrived                                  |

Full list and flags: [Commands](/cli/commands).

## Next [#next]

<Cards>
  <Card title="Talking actor ads" href="/guides/talking-actor" description="An actor speaks your script." />

  <Card title="CLI commands" href="/cli/commands" description="Every command, flag and exit code." />

  <Card title="Capabilities" href="/capabilities" description="Every id you can submit." />
</Cards>
