# Открытый API

> Совместимый с OpenAI эндпоинт для ваших персонажей.

Source: https://reverie.im/ru/docs/integrations/open-api
Language: ru

Reverie предоставляет эндпоинт Chat Completions, совместимый с OpenAI. Направьте на него любой клиент OpenAI, передайте ключ API Reverie и в поле `model` укажите **персонажа или сценарий** вместо большой модели. Разговор, воспоминания и сводки Reverie хранит у себя, поэтому в каждом запросе нужно только ваше новое сообщение.

Пользоваться им может любой вошедший аккаунт. Никаких уровней подписки и списков ожидания — нужен ключ API, и всё. [Создать →](https://reverie.im/ru/docs/integrations/api-keys)

## Базовый URL и авторизация \[#base-url-and-auth]

```
https://reverie.im/api/device/v1
Authorization: Bearer rk_...
```

**Настройки → Ещё → Ключи API** показывают точный базовый URL в карточке **API Endpoint**, рядом кнопка копирования.

> **Это серверный API.** Браузерные запросы с чужого источника блокируются, поэтому fetch с вашей собственной веб-страницы не сработает, каким бы ни был ключ. Вызывайте его из бэкенда и держите ключ подальше от клиентского кода.

## Быстрый старт \[#quick-start]

**cURL**

```bash
curl --no-buffer https://reverie.im/api/device/v1/chat/completions \
  -H "Authorization: Bearer $REVERIE_API_KEY" \
  -H "Content-Type: application/json" \
  --data-binary '{
  "model": "Luna [abc12345]",
  "messages": [
    {
      "role": "user",
      "content": "Hi"
    }
  ],
  "stream": true,
  "temperature": 0.8
}'
```

**Python**

```python
import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["REVERIE_API_KEY"],
    base_url="https://reverie.im/api/device/v1",
)

stream = client.chat.completions.create(
    model="Luna [abc12345]",   # an id from GET /models, a full character or scenario ID, or omit entirely
    messages=[{"role": "user", "content": "Hi"}],
    stream=True,
    temperature=0.8,
)

for chunk in stream:
    print(chunk.choices[0].delta.content or "", end="")
```

**TypeScript**

```ts
import OpenAI from "openai";

const client = new OpenAI({
	apiKey: process.env.REVERIE_API_KEY,
	baseURL: "https://reverie.im/api/device/v1",
});

const stream = await client.chat.completions.create({
	model: "Luna [abc12345]",
	messages: [{ role: "user", content: "Hi" }],
	stream: true,
	temperature: 0.8,
});

for await (const chunk of stream) {
	process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
}
```

В **Настройках → Ещё → Ключах API** есть и конструктор запросов, который собирает эти три фрагмента с одним из ваших настоящих ключей и настоящим персонажем.

## Поле `model` называет персонажа \[#the-model-field-names-a-character]

> **Одно только имя персонажа не работает.** `model: "Luna"` не ищет персонажа по имени Luna. Оно ни с чем не совпадает, проваливается к персонажу по умолчанию у ключа или к вашему последнему чату, и вы получаете ответ от другого персонажа без всякой ошибки. Всегда используйте форму `Имя [короткийID]`, которую возвращает `GET /models`.

| Значение `model`                                | Кто отвечает                                                       |
| ----------------------------------------------- | ------------------------------------------------------------------ |
| `Luna [abc12345]`                               | Персонаж или сценарий, чей ID заканчивается этими 8 символами      |
| Полный ID персонажа или сценария                | Этот персонаж или сценарий                                         |
| ID модели Reverie, например `deepseek-v4-flash` | Выбирает **модель**; персонаж берётся из ключа или последнего чата |
| Не указано                                      | Персонаж, закреплённый за ключом, иначе ваш последний чат          |

От чего зависит, разрешится ли короткий ID:

* `[...]` должно стоять в **конце** строки.
* Суффикс длиной 8 символов или меньше сверяется только с персонажами, **с которыми у вас уже есть чат** — в вебе или через API. Короткий ID персонажа, которого вы ни разу не открывали, тихо не срабатывает.
* Поиск сценария выполняется, только когда ключ закреплён за персонажем. С глобальным ключом короткий ID сценария не разрешится никогда.
* Больше 8 символов считается полным ID.

### Как узнать, с кем можно говорить \[#listing-what-you-can-talk-to]

```bash
curl https://reverie.im/api/device/v1/models \
  -H "Authorization: Bearer $REVERIE_API_KEY"
```

**Глобальный** ключ возвращает ваших недавних персонажей. Ключ, **закреплённый за персонажем**, возвращает сценарии этого персонажа, а если их нет — самого персонажа. Каждая запись выглядит так:

```json
{
	"id": "Luna [abc12345]",
	"object": "model",
	"created": 1759200000,
	"owned_by": "character",
	"permission": [],
	"root": "<full character id>",
	"parent": null
}
```

Скопируйте `id` прямо в `model`. Ошибки этого эндпоинта приходят в простом виде, а не в оболочке OpenAI.

## Что читается в теле запроса \[#what-the-request-body-reads]

Читаются четыре поля. Всё остальное принимается и молча отбрасывается.

| Поле          | Тип        | По умолчанию                     | Примечания                                                        |
| ------------- | ---------- | -------------------------------- | ----------------------------------------------------------------- |
| `messages`    | массив     | обязательно                      | См. ниже — используется только часть                              |
| `model`       | строка     | необязательно                    | Персонаж, сценарий или модель, как выше                           |
| `stream`      | логическое | **`true`**                       | В отличие от API OpenAI, потоковая передача включена по умолчанию |
| `temperature` | число 0–2  | настройка персонажа, иначе `0.8` | Значения вне диапазона отклоняются                                |

Молча игнорируются: `max_tokens`, `top_p`, `n`, `stop`, `presence_penalty`, `frequency_penalty`, `logit_bias`, `seed`, `user`, `response_format`, `tools`, `tool_choice`, `logprobs`, `stream_options`.

Как обрабатывается `messages`:

* **Сообщения `system` отбрасываются.** Личность и поведение берутся из полей самого персонажа, а не из запроса. [Поля промпта →](https://reverie.im/ru/docs/characters/prompt-fields)
* **Работы с изображениями нет.** Содержимое может быть строкой или массивом частей, но читаются только части `text`; части-картинки игнорируются.
* В разговор добавляется только \*\*последнее сообщение `user`\*\*. Более ранние сообщения пользователя игнорируются.
* Сообщения ассистента используются лишь для синхронизации истории (см. ниже).
* Пустое или состоящее из пробелов последнее сообщение пользователя вернёт `missing_user_message`.

## Ответы \[#responses]

Непотоковый ответ — это обычный объект `chat.completion`. `finish_reason` всегда `stop` — внутренние вызовы инструментов наружу не показываются, — а счётчики `usage` нулевые, поэтому считайте токены по статистике использования на странице ключей API, а не по ответу.

Потоковый ответ — это `text/event-stream`:

1. Блоки содержимого: объекты `chat.completion.chunk` с `delta.content`. \*&#x2A;Начальный блок `delta: {"role": "assistant"}` не отправляется.*\*
2. Завершающий блок с `finish_reason` `stop`, `length` или `content_filter`. Завершения из-за вызова инструмента сообщаются как `stop`.
3. Блок использования с пустым массивом `choices`.
4. `data: [DONE]`.

Если генерация срывается посреди потока, поток выдаёт `data: {"error": {...}}`, а затем `[DONE]`.

## Состояние разговора \[#conversation-state]

Разговор хранит Reverie. На каждую пару «ключ и персонаж» приходится один чат, он появляется в веб-приложении рядом с остальными вашими чатами, и каждый ход собирается из системного промпта и сценария персонажа, канона книг мира, долговременных воспоминаний, накапливающихся сводок, манеры повествования персонажа, длины ответа и настроек NSFW, языковой привязки из языка вашего аккаунта и такого объёма недавней истории, какой вмещает контекстное окно модели. Инструменты памяти работают, когда модель поддерживает инструменты.

Поскольку историю держит сервер, повторять её не нужно.

> **Отправка сообщений ассистента может удалить историю.** Если в вашем массиве `messages` есть сообщения ассистента, Reverie берёт последнее из них, ищет его среди 20 самых свежих сохранённых сообщений и при совпадении навсегда удаляет все сообщения, созданные после него, вместе с воспоминаниями, появившимися позже этой точки. Если совпадения нет, не удаляется ничего. Длина массива значения не имеет. Чтобы полностью этого избежать, отправляйте только новое сообщение пользователя.

## Какая модель отвечает \[#which-llm-answers]

Решает персонаж, а не запрос, — если только вы не назвали модель сами. Приоритет от низшего к высшему: модель чата по умолчанию, затем собственная настройка модели у персонажа, затем ID модели Reverie, переданный в `model`, и, наконец, выбор модели для этого чата, сделанный вами в веб-приложении, — он побеждает всё остальное. [Модели →](https://reverie.im/ru/docs/reference/models)

## Ошибки \[#errors]

Ошибки `/chat/completions` приходят в оболочке OpenAI: `{"error": {"message", "type", "param": null, "code"}}`.

| HTTP       | `code`                 | `type`                  | Причина                                                                                   |
| ---------- | ---------------------- | ----------------------- | ----------------------------------------------------------------------------------------- |
| 401        | `invalid_api_key`      | `invalid_request_error` | `Authorization` отсутствует или искажён, ключ неизвестен либо неактивен                   |
| 401        | `api_key_expired`      | `invalid_request_error` | Срок действия ключа истёк                                                                 |
| 404        | `scenario_not_found`   | `invalid_request_error` | ID сценария разрешился, но самого сценария больше нет                                     |
| 404        | `character_not_found`  | `invalid_request_error` | Персонаж отсутствует или удалён                                                           |
| 404        | `no_chat_history`      | `invalid_request_error` | Нет ни `model`, ни закреплённого персонажа, ни прошлого чата, к которому можно откатиться |
| 400        | `missing_user_message` | `invalid_request_error` | Нет непустого сообщения `user`                                                            |
| 429        | `rate_limit_exceeded`  | `rate_limit_exceeded`   | Окно бесплатных моделей исчерпано. В `Retry-After` указано, сколько секунд ждать          |
| 429        | `insufficient_quota`   | `insufficient_quota`    | Кредитов на запрос не хватает                                                             |
| 502        | `MODEL_EMPTY_RESPONSE` | `server_error`          | Модель завершила работу штатно, но без текста                                             |
| по-разному | код поставщика         | `server_error`          | Сбой генерации на стороне поставщика                                                      |

Два случая выпадают из этой оболочки: ошибки `GET /models` и тела запросов, отклонённые проверкой (например, `temperature` вне диапазона) — и те и другие возвращают простой вид ошибки.

## Лимиты и квоты \[#rate-limits-and-quotas]

У этого API **нет лимита частоты на ключ, нет потолка по параллельным запросам и нет квоты на запросы**. Ограничивают вас всего две вещи:

| Ограничение             | Значение                                                                                    |
| ----------------------- | ------------------------------------------------------------------------------------------- |
| Баланс кредитов         | Проверяется перед каждым запросом; при нехватке возвращается `insufficient_quota`           |
| Окно бесплатных моделей | 15 сообщений за 3 часа на аккаунт — ×3 на Pro (45), ×4 на Premium (60), ×5 на Ultimate (75) |

Окно бесплатных моделей общее с веб-чатом, историями, романами и ботами — это один лимит на аккаунт, а не по одному на каждую площадку. [Бесплатные модели →](https://reverie.im/ru/docs/reference/free-models)

Reverie не отправляет исходящих вебхуков; подписаться на события о завершении генерации не на что.

## Импорт персонажей \[#importing-characters]

Есть и второй эндпоинт, `POST /api/v1/characters/import`, — он создаёт персонажа из карточки персонажа. Ему нужен ключ с правом импорта, а страница настроек такие ключи не создаёт. [Ключи API →](https://reverie.im/ru/docs/integrations/api-keys) и [Импорт персонажей →](https://reverie.im/ru/docs/characters/import-characters)

## Смежное \[#related]

* [Ключи API](https://reverie.im/ru/docs/integrations/api-keys) — создание, закрепление, срок действия и расход ключей
* [Модели](https://reverie.im/ru/docs/reference/models) — ID моделей и кредитные множители
* [Ограничения](https://reverie.im/ru/docs/reference/limits) — остальные потолки в продукте
* [Кредиты](https://reverie.im/ru/docs/billing/credits) — как считается стоимость запросов
