# Model list

Every model, its options and its prices, as JSON. `GET /v1/models` needs no key. The price you see is the price you pay: VidLab picks the route, you never pay more than the listed price.

```bash cURL
curl -s "https://vidlab.ai/v1/models?kind=video"
```

```python Python
import requests

models = requests.get("https://vidlab.ai/v1/models", params={"kind": "video"}).json()["data"]
for m in models:
    print(m["id"], m["unit"], m["prices"])
```

```js JavaScript
const res = await fetch("https://vidlab.ai/v1/models?kind=video");
const { data: models } = await res.json();
for (const m of models) console.log(m.id, m.unit, m.prices);
```

| Query | Values | What it does |
| - | - | - |
| `kind` | `video`, `image`, `audio`, `lipsync`, `upscale` | Only models of that kind. |
| `maker` | A maker's name, any case | Only that maker's models, for example `maker=Google`. |
| `search` | Words | Only models whose id, name, maker or description has every word. `q` works the same. |

The answer is `{ "object": "list", "data": [ ...models ] }`. `GET /v1/models/{id}` returns one model as `{ "data": model }`, or `404 model_not_found`. The list is public data: answers may be cached for up to 60 seconds.

## The model object

```json
{
  "id": "seedance-2.5",
  "name": "Seedance 2.5",
  "maker": "ByteDance",
  "kind": "video",
  "unit": "per_second",
  "description": "Generates video from text, an image, references",
  "prices": {
    "480p": 0.088,
    "720p": 0.21,
    "1080p": 0.52
  },
  "params": {
    "resolution": { "values": ["480p", "720p", "1080p"] },
    "prompt": { "required": true },
    "images": { "max": 16 },
    "negative_prompt": {},
    "seed": {},
    "duration": { "min": 4, "max": 30 },
    "aspect_ratio": { "values": ["16:9", "9:16", "1:1"] }
  },
  "featured": true,
  "save_pct": 34,
  "routes": 2,
  "status": "operational"
}
```

| Field | Type | What it is |
| - | - | - |
| `id` | string | The id you send as `model`. |
| `name`, `maker` | string | Display name and the company that made the model. |
| `kind` | string | `video`, `image`, `audio`, `lipsync` or `upscale`. |
| `unit` | string | What one unit of the price is (see [Units](#units)). |
| `description` | string | Optional. A one-line summary. |
| `prices` | object | USD per unit for each priced option (see [Variants](#variants)). |
| `params` | object | The input fields this model takes (see [The params object](#the-params-object)). |
| `media` | object | Optional. Example `still` and `video` paths. |
| `featured` | boolean | Shown first on the models page. |
| `save_pct` | number | Optional. How much cheaper we are, in percent, at the setting the price starts from (our cheapest one), rounded down. |
| `offer` | object | Optional. The price a model card leads with: `variant` (our cheapest plain option), `price_usd`, `market_usd` (the usual price for the same unit, shown struck through) and `pct` (the saving, rounded down). Only models we are cheaper on have one. |
| `duration_must_cover` | array | Optional. For models whose length comes from an input file: which files (`video`, `audio`) `duration` must cover. |
| `routes` | number | How many routes can run this model right now. |
| `status` | string | `operational`, `degraded` or `down`. |

## Units

| Unit | One unit is | Counted from |
| - | - | - |
| `per_second` | one second of output | `duration` |
| `per_image` | one image | `n` (default 1) |
| `per_job` | one call | always 1 |
| `per_1k_chars` | each started 1,000 characters | `text` (or `prompt`) |
| `per_minute` | each started minute | `duration` in seconds |

The price of a call is the variant's price times the units. A 5 second clip at 720p on a model priced `0.21` per second costs `1.05`. The wallet moves whole cents, so a price is rounded up to the next cent: the quote, the reservation and the charge are all that same number.

## Variants

A model's `prices` are keyed by variant. A variant is the resolution or quality, then flags joined with `+`:

- `+audio` when the call asks for sound (`generate_audio: true`),
- `+video_input` when the call sends a reference `video`,
- `*` when the model has one price for everything.

VidLab picks the variant from your input: the exact key first, then the key with fewer flags, then the bare resolution or quality, then `*`. Options you leave out get the model's first allowed value, so the quote and the run always agree. If no priced variant matches, the call answers `400 variant_unavailable` with the priced options in the message.

## The params object

`params` lists every input field the model accepts. A field that is not listed is refused, never ignored. Each entry has up to three keys:

| Key | Meaning |
| - | - |
| `required` | The field must be sent. |
| `values` | The only allowed values. Matching ignores letter case. |
| `min`, `max` | Number limits. For `images`, the most images; for `n`, how many images per call; for `duration`, seconds. |

- `{}` means the field is accepted with no limit beyond [Input fields](https://docs.vidlab.ai/input-fields).
- A list of lengths (`"duration": { "values": [4, 6, 8] }`) means only those lengths run.
- `params` only lists what the model can really do: an option that no route can carry is not listed. A reference `video` or `generate_audio` is listed only while its price (`+video_input`, `+audio`) is.

## Model status

`GET /v1/status` lists every model with its `status` and `routes` count. No key needed.

```json
{ "object": "list", "data": [{ "model": "seedance-2.5", "status": "operational", "routes": 2 }] }
```

A model that is `down` can still be called: the generation is accepted and fails with `model_busy` if no route can take it, at no charge.

## UGC Real 1

`ugc-real-1` is VidLab's own image model, made for realistic phone-shot UGC people: the kind of picture a creator would take on a phone. It costs one flat price per image, shown on its [model page](https://docs.vidlab.ai/models/ugc-real-1) next to real examples of what it makes.

It takes words only. Send `prompt` (up to 2,000 characters) and, if you want another shape, `aspect_ratio` (`9:16` by default). Short prompts are fine: the model writes your words out into a detailed photo description before it draws. A call makes one image. It takes no pictures, no `n`, no `resolution` and no `seed`: a field it does not list is refused with `400 invalid_input` before anything is held.

```bash cURL
curl -s -X POST https://vidlab.ai/v1/generations \
  -H "Authorization: Bearer $VIDLAB_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"model":"ugc-real-1","input":{"prompt":"a woman in her kitchen, talking to the camera"}}'
```

Poll the generation as for any other model. A finished call has one picture in `outputs`, and a failed or blocked one is not charged.
