# Chat completions

The request and response of POST /api/v1/chat/completions, messages and roles, finish reasons.

The router has one generation endpoint, `POST /api/v1/chat/completions`, in the OpenAI Chat Completions format. The `prompt` and `input` formats are not supported: send `messages`.

## Request

```json
{
  "model": "google/gemma-3-4b-it",
  "messages": [
    { "role": "system", "content": "You answer in one sentence." },
    { "role": "user", "content": "What is a router?" }
  ],
  "max_tokens": 200,
  "temperature": 0.7
}
```

- `model` is a model id from the [catalog](/models). Instead of one model you may give a fallback list in `models`, see [Models and routing](/docs/en/models-and-routing).
- `messages` is a non-empty array; every message needs a `role`.
- Every other field is described in [Parameters](/docs/en/parameters).

## Messages and roles

| Role        | Purpose                                                                                                                    |
| ----------- | -------------------------------------------------------------------------------------------------------------------------- |
| `system`    | Instructions for the model. Some models also accept `developer`.                                                           |
| `user`      | The user's message: text, or an array of content parts with images and files, see [Images and files](/docs/en/multimodal). |
| `assistant` | Earlier answers of the model, including its `tool_calls`.                                                                  |
| `tool`      | The result of a tool call, with the `tool_call_id` it answers. See [Tool calling](/docs/en/tool-calling).                  |

The API is stateless: send the whole conversation in every request. Everything you send is billed as prompt tokens.

## Response

```json
{
  "id": "gen-5d0c3b6e-…",
  "object": "chat.completion",
  "created": 1793178000,
  "model": "google/gemma-3-4b-it",
  "provider": "Google",
  "choices": [
    {
      "index": 0,
      "finish_reason": "stop",
      "native_finish_reason": "STOP",
      "message": { "role": "assistant", "content": "A router forwards each request to a model that can serve it." }
    }
  ],
  "usage": {
    "prompt_tokens": 24,
    "completion_tokens": 14,
    "total_tokens": 38,
    "cost": 0.0000146,
    "prompt_tokens_details": { "cached_tokens": 0 },
    "completion_tokens_details": { "reasoning_tokens": 0 }
  }
}
```

| Field        | Meaning                                                                                         |
| ------------ | ----------------------------------------------------------------------------------------------- |
| `id`         | The generation id. Find the request with `GET /api/v1/generation?id=…` or in the cabinet logs.  |
| `model`      | The model that answered. With a `models` list it may be a fallback model.                       |
| `provider`   | Who hosted the model: the hosting provider in the Global region, `Russia` in the Russia region. |
| `usage.cost` | What the request cost, in PnP.                                                                  |

## Finish reasons

`finish_reason` is normalized; `native_finish_reason` keeps the provider's own value (non-streaming responses only).

| Value            | Meaning                                                                               |
| ---------------- | ------------------------------------------------------------------------------------- |
| `stop`           | The model finished or hit a stop sequence.                                            |
| `length`         | The output reached `max_tokens` (4096 when you set none) or the model's limit.        |
| `tool_calls`     | The model wants to call tools.                                                        |
| `content_filter` | The provider filtered the output.                                                     |
| `error`          | The generation failed midway; see [Streaming](/docs/en/streaming#errors-in-a-stream). |

## Streaming

Add `"stream": true` to receive the answer token by token as server-sent events. See [Streaming](/docs/en/streaming).
