# Chat completions

> POST /v1/chat/completions в формате OpenAI, со стримингом, инструментами, изображениями и рассуждениями.


Запрос и ответ OpenAI Chat Completions на моделях NotHoly. Направьте OpenAI SDK на base URL, больше ничего менять не нужно.

```endpoint
POST https://api.notholy.com/v1/chat/completions
```

## Запрос

| Поле | Тип | Обязательное | Примечания |
|---|---|---|---|
| `model` | string | Да | ID модели, например `notholy-specter`. См. [Модели](/ru/getting-started/models) |
| `messages` | array | Да | Роли `system`, `developer` (читается как `system`), `user`, `assistant` и `tool`. Содержимое — строка или список частей `text` и `image_url` |
| `max_completion_tokens` / `max_tokens` | number | Нет | Лимит выхода. Если заданы оба, действует `max_completion_tokens`. По умолчанию максимальный выход модели; большее значение возвращает `400` |
| `stream` | boolean | Нет | `true` возвращает server-sent events. См. [Стриминг](/ru/guides/streaming) |
| `tools` | array | Нет | Только функции. Другие типы инструментов возвращают `400 unsupported_parameter` |
| `tool_choice` | string или object | Нет | Передаётся модели, если задано `tools` |
| `reasoning_effort` | string | Нет | Одно из значений `reasoning_efforts` модели. Любое другое значение возвращает `400`. См. [Рассуждения](/ru/guides/reasoning) |
| `response_format` | object | Нет | Передаётся модели |
| `temperature`, `top_p`, `stop` | number, number, string или array | Нет | Передаются модели |
| `n` | number | Нет | Только `1` |

Неизвестные поля игнорируются. Изображения принимаются моделями, у которых в `input_modalities` есть `image`; у остальных они возвращают `400 unsupported_parameter`.

## Ответ без стриминга

```json
{
  "id": "chatcmpl-8Kp2c1Vx",
  "object": "chat.completion",
  "created": 1793836800,
  "model": "notholy-specter",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "An IDOR lets a user read or change another user's object by changing its ID…",
        "refusal": null,
        "reasoning_content": "…"
      },
      "finish_reason": "stop",
      "logprobs": null
    }
  ],
  "usage": {
    "prompt_tokens": 42,
    "completion_tokens": 118,
    "total_tokens": 160,
    "prompt_tokens_details": { "cached_tokens": 0 },
    "completion_tokens_details": { "reasoning_tokens": 64 }
  }
}
```

- `reasoning_content` есть, только если модель рассуждала.
- При вызовах инструментов `message.tool_calls` содержит элементы `{id, type: "function", function: {name, arguments}}`, `finish_reason` равен `tool_calls`, а `content` равен `null`, если текста нет.
- `finish_reason` принимает значения `stop`, `length`, `tool_calls` или `content_filter`.
- При стриминге последний чанк перед `data: [DONE]` всегда содержит `usage`, независимо от того, отправляете ли вы `stream_options.include_usage`.

## Пример

```bash test
curl https://api.notholy.com/v1/chat/completions \
  -H "Authorization: Bearer $NOTHOLY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "notholy-specter",
    "messages": [
      {"role": "system", "content": "You are reviewing code for an authorized assessment."},
      {"role": "user", "content": "What does a missing ownership check in GET /api/invoices/:id lead to?"}
    ]
  }'
```

```python test
import os
from openai import OpenAI

client = OpenAI(base_url="https://api.notholy.com/v1", api_key=os.environ["NOTHOLY_API_KEY"])

r = client.chat.completions.create(
    model="notholy-specter",
    messages=[{"role": "user", "content": "List three checks for an SSRF fix."}],
    max_tokens=400,
)
print(r.choices[0].message.content)
print(r.usage.prompt_tokens, r.usage.completion_tokens)
```

```js test
import OpenAI from 'openai';

const client = new OpenAI({ baseURL: 'https://api.notholy.com/v1', apiKey: process.env.NOTHOLY_API_KEY });

const r = await client.chat.completions.create({
  model: 'notholy-specter',
  messages: [{ role: 'user', content: 'List three checks for an SSRF fix.' }],
  max_tokens: 400,
});
console.log(r.choices[0].message.content);
```

## Заголовки ответа

| Заголовок | Значение |
|---|---|
| `x-request-id` | Отправьте его в поддержку, когда сообщаете о проблеме |
| `x-notholy-concurrency-limit` | Сколько запросов можно выполнять одновременно |
| `x-notholy-concurrency-remaining` | Свободные слоты на момент начала этого запроса |
| `x-notholy-credits-remaining` | Доступные кредиты в долларах США на момент начала этого запроса |

## Ошибки

`400` неверное тело или параметр · `401` ключ отсутствует или неверен · `402` не хватает кредитов или бюджета ключа · `403` ключу нельзя использовать эту модель · `404` неизвестная модель · `429` лимит запросов или параллельности (соблюдайте `retry-after`) · `502`/`504` модель упала или не ответила вовремя · `503` модель недоступна. Полная таблица: [Ошибки](/ru/guides/errors).
