# Open API

> Ендпоінт для твоїх персонажів, сумісний з OpenAI.

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

Reverie надає ендпоінт Chat Completions, сумісний з OpenAI. Спрямуй на нього будь-який клієнт OpenAI, передай API-ключ Reverie і використовуй поле `model`, щоб указати **персонажа або сценарій** замість LLM. Reverie зберігає розмову, спогади й підсумки на своєму боці, тож кожному запиту потрібне лише твоє нове повідомлення.

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

## Базова URL-адреса та автентифікація \[#base-url-and-auth]

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

**Налаштування → Більше → API-ключі** показує точну базову URL-адресу на картці **API-ендпоінт** разом із кнопкою копіювання.

> **Це серверний API.** Міждоменні запити з браузера блокуються, тож fetch
> із твоєї власної вебсторінки не спрацює незалежно від ключа. Викликай API з
> бекенду й не додавай ключ у клієнтський код.

## Швидкий старт \[#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. Значення ні з чим не збігається, запит переходить до типового
> персонажа ключа або до твого останнього чату, і ти отримуєш відповідь від
> іншого персонажа без жодної помилки. Завжди використовуй формат
> `Name [shortid]`, який повертає `GET /models`.

| Значення `model`                             | Хто відповідає                                                         |
| -------------------------------------------- | ---------------------------------------------------------------------- |
| `Luna [abc12345]`                            | Персонаж або сценарій, чий ID закінчується цими 8 символами            |
| Повний ID персонажа чи сценарію              | Цей персонаж або сценарій                                              |
| ID моделі Reverie, напр. `deepseek-v4-flash` | Вибирає **LLM**; персонаж визначається ключем або твоїм останнім чатом |
| Не вказано                                   | Персонаж, закріплений за ключем, а інакше — твій останній чат          |

Від чого залежить, чи буде розпізнано короткий 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`       | рядок     | необов'язкове                        | Персонаж, сценарій або LLM, як описано вище                             |
| `stream`      | boolean   | **`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/uk/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 останніх збережених повідомлень і — якщо знаходить збіг —
> назавжди видаляє всі повідомлення, створені після нього, разом зі спогадами,
> створеними після цього моменту. Якщо збігу немає, нічого не видаляється.
> Довжина масиву не має значення. Щоб цілком цього уникнути, надсилай лише нове
> повідомлення користувача.

## Яка LLM відповідає \[#which-llm-answers]

Це вирішує персонаж, а не запит — хіба що ти вкажеш LLM. Пріоритет, від найнижчого до найвищого: типова модель чату, потім власне налаштування моделі персонажа, потім ID моделі Reverie, переданий як `model`, і нарешті вибір моделі для конкретного чату, зроблений у вебзастосунку, — він має перевагу над усіма іншими. [Моделі →](https://reverie.im/uk/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/uk/docs/reference/free-models)

Reverie не надсилає вихідних вебхуків; підписатися на події завершення генерації неможливо.

## Імпорт персонажів \[#importing-characters]

Другий ендпоінт, `POST /api/v1/characters/import`, створює персонажа з картки персонажа. Для нього потрібен ключ із дозволом на імпорт, а такі ключі сторінка налаштувань не створює. [API-ключі →](https://reverie.im/uk/docs/integrations/api-keys) і [Імпорт персонажів →](https://reverie.im/uk/docs/characters/import-characters)

## Пов'язане \[#related]

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