# Models & modalities

> Discover models and use embeddings, speech and transcription.

`GET https://api.roar-ai.com/v1/models` returns the catalogue your key can use — and it is the answer, not this page. Model names change as the catalogue does; a name written into a guide is a name that goes stale.

Each entry lists its `roar_modalities`, the request types it serves:

| Modality | Endpoint | In the catalogue today |
| --- | --- | --- |
| `chat` | `POST /v1/chat/completions` | Yes — most of the catalogue |
| `embedding` | `POST /v1/embeddings` | Yes |
| `tts` | `POST /v1/audio/speech` (text to audio bytes) | Yes — `tts-1` |
| `stt` | `POST /v1/audio/transcriptions` (multipart audio upload, max 50MB) | Yes — `whisper-large-v3-turbo` |
| `image` | `POST /v1/images/generations` (prompt to images, billed per image) | Not yet — ask us if you need one |

Every `chat` model also takes **PDF documents**: models that cannot read PDFs on their own get the pages as text, read on our side at no charge. Models that support vision also take **images**. See [Documents](/docs/chat#documents-pdf) and [Vision](/docs/chat#vision).

<Note>
The endpoints are live; `image` has nothing published behind it yet. `GET /v1/models` is what settles it for your account — if a modality returns no models there, that request type has nowhere to go and will answer `404 model_not_found`. Tell us what you need and we will add it.
</Note>

## Cheaper ways to run a model

Each entry also tells you which discounted tiers it supports and what they cost, so you can decide before building around one:

<CodeCard caption="Entry from /v1/models">

```json
{
  "id": "claude-haiku-4-5",
  "roar_modalities": ["chat"],
  "roar_batch": true,
  "roar_pricing": {
    "batchInputPer1M": 0.575,
    "batchOutputPer1M": 2.875,
    "cachedInputPer1M": 0.115,
    "cacheWriteInputPer1M": 1.4375
  }
}
```

</CodeCard>

| Field | Meaning |
| --- | --- |
| `roar_batch` | The model can be sent to [batch](/docs/batch) — roughly half price, results within 24h. |
| `cachedInputPer1M` | Rate for prompt tokens served from cache. Applied automatically when a prompt repeats a long prefix; no flag to set. |
| `cacheWriteInputPer1M` | What it costs to write the cache the first time, where a model charges for that. Absent means writes are free. |
| `batchInput/OutputPer1M` | The batch rate, when `roar_batch` is true. |
| `priorityInput/OutputPer1M` | Rate when a request sets `"service_tier": "priority"`. Asking for it on a model without one returns `400`. |
| `flexInput/OutputPer1M` | Rate when a request sets `"service_tier": "flex"` — cheaper, and may queue behind standard traffic. Still answers on the same request, unlike [batch](/docs/batch). |

An absent key means no such rate is offered, and nothing is silently substituted — cache hits simply bill at the normal input rate.

Rates are in USD per million tokens and hold until we republish them. All prices are the same for every account.

## Embeddings

Turn text into vectors for search and similarity. Same call shape as any OpenAI-compatible client:

<CodeCard caption="Python">

```python
emb = client.embeddings.create(
    model="text-embedding-3-small",  # whichever embedding model GET /v1/models lists for you
    input=["first passage", "second passage"],
)
print(len(emb.data[0].embedding))
```

</CodeCard>

## Speech and transcription

The endpoints are OpenAI-compatible and take the usual shape — `POST /v1/audio/speech` for text to audio, `POST /v1/audio/transcriptions` for a multipart upload back to text:

<CodeCard caption="curl (text to speech)">

```bash
curl https://api.roar-ai.com/v1/audio/speech \
  -H "Authorization: Bearer roar_live_..." \
  -H "Content-Type: application/json" \
  -d '{"model": "tts-1", "input": "Hello there", "voice": "alloy"}' \
  --output hello.mp3
```

</CodeCard>

<CodeCard caption="curl (transcription)">

```bash
curl https://api.roar-ai.com/v1/audio/transcriptions \
  -H "Authorization: Bearer roar_live_..." \
  -F file=@meeting.mp3 \
  -F model="whisper-large-v3-turbo"
```

</CodeCard>

<Note>
Speech bills per million characters of input and transcription per million seconds of audio — both are on the [models page](/models), where each row opens to its full rates.
</Note>

## How a model is served

You never pick a server, and neither does the request. Each model in the catalogue is served one chosen way, and it keeps being served that way — the same model name gives you the same behaviour on every call.

That is a deliberate promise rather than an implementation detail. A model whose serving changed from request to request would change with it: a parameter accepted on one call and rejected on the next, prompt caching that works some of the time, a `max_tokens` ceiling that moves. Anything you build on top has to be built for the worst case. Fixing how a model is served removes that whole class of surprise.

It is not a single point of failure. If the chosen path is unhealthy we fail over automatically and the request still succeeds; what does not happen is picking a different one because it was momentarily cheaper or quicker. Cost is settled when we set a model's published price — not per request, out of your control, and never by changing what you get.

<Note>
Nothing to configure, and nothing you can set per request. If your account keeps traffic inside a region, a model with no route there returns `404 no_regional_route` rather than being served from outside it — see the [error reference](/docs/errors).
</Note>
