# Chat completions

> Call chat models through the OpenAI-compatible chat completions endpoint of the Tarout AI Gateway

# Chat completions

`POST /chat/completions` is the OpenAI chat completions API. Any OpenAI SDK,
LangChain or the Vercel AI SDK works with it once you set the base URL to
`https://tarout.sa/api/ai/v1` and use a Tarout key (`sk_tarout_...`). One key
calls every chat model; each request picks its model with `model`.

## Regions

| Region | Where processed | `model` |
| --- | --- | --- |
| **Global** | Processed outside Saudi Arabia. | `glm`, `deepseek-v4-pro`, `kimi-k3`, `minimax-m3`, `qwen3` |
| **Global, fast route** | Processed outside Saudi Arabia, on a route tuned for fast inference. | `gpt-oss-fast`, `gpt-oss-20b-fast`, `qwen3.8-fast`, `qwen3.6-fast` |

The full IDs of these models are in the [model tables](https://tarout.sa/docs/api#models).
`GET /models` lists every chat model you can call right now, each with its
`region`.

## Endpoint

```
POST https://tarout.sa/api/ai/v1/chat/completions
```

Your key needs the **AI Gateway** scope.

## Request

| Field | Type | Description |
| --- | --- | --- |
| `model` | string | Required. A model alias or full ID. |
| `messages` | array | Required. At least one message. Each `content` is a string (or `null`); images and other content parts are not accepted. |
| `stream` | boolean | Optional. `true` streams the answer as Server-Sent Events. |
| `stream_options` | object | Optional. Streaming options, such as `{ "include_usage": true }`. |
| `max_tokens` | integer | Optional. The most tokens to generate. When you leave it out, the answer is capped at 4096 tokens. |
| `max_completion_tokens` | integer | Optional. The same limit under its newer name. If you send both, they must be equal. |
| `temperature`, `top_p` | number | Optional. Sampling controls. |
| `frequency_penalty`, `presence_penalty` | number | Optional. |
| `stop` | string or array | Optional. Stop sequences. |
| `seed` | integer | Optional. Passed to the model for more repeatable answers. |
| `n` | integer | Optional. Only `1`: one choice per request. Send parallel requests for more. |
| `response_format` | object | Optional. `{ "type": "text" }`, `{ "type": "json_object" }` or `{ "type": "json_schema", "json_schema": {...} }`. The two JSON types need a model with structured outputs. |
| `tools`, `tool_choice`, `parallel_tool_calls` | | Optional. Function calling, for models that support tools. |
| `functions`, `function_call` | | Optional. The older form of function calling. |
| `reasoning_effort` | string | Optional. Only for models that declare reasoning efforts; the models on this page answer `400` `UNSUPPORTED_PARAMETER` if you send it. |
| `user` | string | Optional. Your end user's ID, for your own records. |

A field not in this table answers `400` `VALIDATION_ERROR` naming it. A
model's page in the dashboard (**AI Models**) shows whether it supports tools
and structured outputs; a request that needs one the model lacks answers
`400`.

## Response

```json
{
  "id": "chatcmpl-...",
  "object": "chat.completion",
  "created": 1761300000,
  "model": "z-ai/glm-5.3",
  "choices": [
    {
      "index": 0,
      "message": { "role": "assistant", "content": "مرحبًا! كيف أساعدك؟" },
      "finish_reason": "stop"
    }
  ],
  "usage": { "prompt_tokens": 12, "completion_tokens": 9, "total_tokens": 21 }
}
```

With `"stream": true` the answer arrives as `data:` events, one
`chat.completion.chunk` each, and ends with `data: [DONE]`. A stream that fails
after it started ends with one `data:` event carrying an `error` object, then
`data: [DONE]`.

## Limits

- Text messages only.
- One choice per request (`n` is `1`).
- Without `max_tokens`, an answer is capped at 4096 tokens.
- By default each key may send 60 requests and 100,000 tokens a minute, and
  1,000,000 tokens a day. Past a limit you get `429` with `Retry-After`.

## Pricing

Chat is billed per token, input and output priced separately, in SAR from your
organization's prepaid balance. Failed requests are free. See each model's
current rates in the dashboard (**AI Models**) or with `tarout ai models`;
`GET /models` lists the models you can call right now. A key can also carry a
monthly credit limit in SAR.

## Examples

```sh
curl https://tarout.sa/api/ai/v1/chat/completions \
  -H "Authorization: Bearer $TAROUT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "glm",
    "messages": [{ "role": "user", "content": "Write one sentence about Riyadh." }]
  }'
```

With the Tarout SDK (`npm install @tarout/ai`):

```ts
import Tarout from "@tarout/ai";

const client = new Tarout(); // reads TAROUT_API_KEY

const res = await client.chat.completions.create({
  model: "gpt-oss-fast",
  messages: [{ role: "user", content: "Write one sentence about Riyadh." }],
});

console.log(res.choices[0]?.message.content);
```

With the official `openai` package for Python (`pip install openai`):

```python
import os
from openai import OpenAI

client = OpenAI(
    base_url="https://tarout.sa/api/ai/v1",
    api_key=os.environ["TAROUT_API_KEY"],
)

stream = client.chat.completions.create(
    model="glm",
    messages=[{"role": "user", "content": "Write one sentence about Riyadh."}],
    stream=True,
)
for chunk in stream:
    if chunk.choices and chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end="")
```

## Errors

Errors use the OpenAI envelope `{"error": {"message", "type", "code"}}`, with
`type` and `code` carrying the same value. The full list is on the
[API overview](https://tarout.sa/docs/api#errors).

| Status | `code` | Meaning |
| --- | --- | --- |
| 400 | `VALIDATION_ERROR` | The body is invalid or has a field this endpoint does not take. |
| 400 | `UNSUPPORTED_PARAMETER` | The model does not take this field (`response_format`, `reasoning_effort`, `n` above 1). |
| 401 | `AUTHENTICATION_ERROR` | Missing or invalid key. |
| 402 | `PAYMENT_REQUIRED`, `BUDGET_EXCEEDED` | The balance or the key's monthly credit limit cannot cover the request. |
| 403 | `KEY_SCOPE_FORBIDDEN` | The key does not have the AI Gateway scope. |
| 404 | `MODEL_NOT_FOUND`, `MODEL_UNAVAILABLE` | Unknown or removed model, or one that cannot be called right now. |
| 429 | `RATE_LIMIT_EXCEEDED` | Too many requests or tokens. Wait `Retry-After` seconds. |
| 502, 503 | `PROVIDER_ERROR` | The model is temporarily unavailable. Retry; failed requests are free. |

## CLI and MCP

```sh
tarout ai models                                          # the chat catalog and its rates
tarout ai keys create --name production --monthly-cap 50  # a key with a 50 SAR monthly limit
```

Chat runs from your own code with any OpenAI-compatible client; the CLI and the
MCP server manage keys and list models.

---

## Every Tarout agent guide

- [Start Here (Agents)](https://tarout.sa/docs/for-ai/start.md)
- [Overview](https://tarout.sa/docs/for-ai.md)
- [Deploying an app](https://tarout.sa/docs/for-ai/deploy.md)
- [Databases](https://tarout.sa/docs/for-ai/database.md)
- [Object storage](https://tarout.sa/docs/for-ai/storage.md)
- [Custom domains](https://tarout.sa/docs/for-ai/domains.md)
- [Plans and upgrades](https://tarout.sa/docs/for-ai/billing.md)
- [Troubleshooting](https://tarout.sa/docs/for-ai/troubleshoot.md)
- [Agent Onboarding](https://tarout.sa/docs/for-ai/onboarding.md)
- [CLI Reference](https://tarout.sa/docs/for-ai/cli-reference.md)
- [CLI JSON Schema](https://tarout.sa/docs/for-ai/cli-json-schema.md)

Whole corpus in one file: https://tarout.sa/llms-full.txt · index: https://tarout.sa/llms.txt
Any docs page is raw markdown at the same URL + `.md`. Short link to the entry point: https://tarout.sa/deploy.md
