# オープン API

> キャラクターを呼び出せる、OpenAI 互換のエンドポイント。

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

Reverie は OpenAI 互換の Chat Completions エンドポイントを公開しています。どの OpenAI クライアントでもそこへ向け、Reverie の API キーを渡し、`model` フィールドには LLM ではなく**キャラクターかシナリオ**を指定します。会話も記憶も要約も Reverie 側が持っているので、リクエストごとに必要なのは新しいメッセージだけです。

サインインしていれば誰でも使えます。サブスクリプションの区分も順番待ちもありません——必要なのは API キーだけです。[作成する →](https://reverie.im/ja/docs/integrations/api-keys)

## ベース URL と認証 \[#base-url-and-auth]

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

**設定 → その他 → APIキー**の **API Endpoint** カードに正確なベース URL が表示され、コピーボタンも付いています。

> **これはサーバー側の 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キー**には、あなたの実際のキーと実在のキャラクターを使って上の 3 つのコードを生成するリクエストビルダーもあります。

## `model` フィールドはキャラクターを指す \[#the-model-field-names-a-character]

> **キャラクター名だけでは動きません。** `model: "Luna"` は Luna という名前のキャラクターを探してはくれません。どれにも一致せず、キーの既定キャラクターか直近のチャットに流れ、エラーも出ないまま別のキャラクターから返事が来ます。必ず `GET /models` が返す `名前 [短いID]` の形を使ってください。

| `model` の値                             | 答えるもの                                  |
| -------------------------------------- | -------------------------------------- |
| `Luna [abc12345]`                      | ID がその 8 文字で終わるキャラクターまたはシナリオ           |
| 完全なキャラクター ID またはシナリオ ID                | そのキャラクターまたはシナリオ                        |
| Reverie のモデル ID（例：`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]

読まれるのは 4 つのフィールドだけです。それ以外は受け付けられたうえで黙って捨てられます。

| フィールド         | 型       | 既定値                  | 備考                          |
| ------------- | ------- | -------------------- | --------------------------- |
| `messages`    | 配列      | 必須                   | 下記参照——使われるのは一部だけです          |
| `model`       | 文字列     | 任意                   | 上記のとおり、キャラクター・シナリオ・LLM      |
| `stream`      | 真偽値     | **`true`**           | OpenAI API と違い、既定でストリーミングです |
| `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/ja/docs/characters/prompt-fields)
* **画像の理解には対応していません。** 内容は文字列でもパーツの配列でもかまいませんが、読まれるのは `text` パーツだけで、画像パーツは無視されます。
* 会話に加えられるのは**最後の `user` メッセージ**だけです。それより前のユーザーメッセージは無視されます。
* アシスタントメッセージは履歴の同期（下記）にだけ使われます。
* 最後のユーザーメッセージが空、または空白だけの場合は `missing_user_message` が返ります。

## レスポンス \[#responses]

非ストリーミングのレスポンスは通常の `chat.completion` オブジェクトです。`finish_reason` は常に `stop` で——内部のツール呼び出しが表に出ることはありません——`usage` のカウンターはすべてゼロなので、トークン数はレスポンスではなく API キーのページの使用統計で測ってください。

ストリーミングのレスポンスは `text/event-stream` です。

1. コンテンツのチャンク：`delta.content` を持つ `chat.completion.chunk` オブジェクト。**冒頭の `delta: {"role": "assistant"}` チャンクは送られません。**
2. 終了チャンク。`finish_reason` は `stop`、`length`、`content_filter` のいずれか。ツール呼び出しによる終了は `stop` として報告されます。
3. `choices` が空配列の使用量チャンク。
4. `data: [DONE]`.

途中で生成に失敗した場合、ストリームは `data: {"error": {...}}` を出してから `[DONE]` を送ります。

## 会話の状態 \[#conversation-state]

会話は Reverie が保存します。チャットはキーとキャラクターの組ごとに 1 つ存在し、ウェブアプリでもほかのチャットと並んで表示されます。各ターンは、キャラクターのシステムプロンプトとシナリオ、ワールドブックの設定、長期記憶、随時更新される要約、キャラクターの語り口・応答の長さ・NSFW 設定、アカウントのロケールによる言語の固定、そしてモデルのコンテキストウィンドウに収まるだけの直近の履歴から組み立てられます。モデルがツールに対応していれば、記憶のツールも動きます。

履歴はサーバーが持っているので、あなたが送り直す必要はありません。

> **アシスタントメッセージを送ると履歴が消えることがあります。** `messages` 配列にアシスタントメッセージが含まれていると、Reverie はその最後のものを取り、保存済みの直近 20 件の中から探します。見つかった場合、それ以降に作られたメッセージと、その時点より後に作られた記憶をすべて完全に削除します。見つからなければ何も削除されません。配列の長さは関係ありません。これを完全に避けるには、新しいユーザーメッセージだけを送ってください。

## どの LLM が答えるか \[#which-llm-answers]

決めるのはキャラクターであってリクエストではありません——LLM を名指しした場合を除きます。優先順位は低いほうから、既定のチャットモデル、キャラクター自身のモデル設定、`model` として渡された Reverie のモデル ID、そして最後にウェブアプリでそのチャットに設定したモデルの指定で、これがすべてに勝ちます。[モデル →](https://reverie.im/ja/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`          | 上流で生成に失敗                                 |

この外枠に入らないものが 2 つあります：`GET /models` のエラーと、検証で弾かれたリクエストボディ（たとえば範囲外の `temperature`）——どちらも素朴なエラー形式を返します。

## レート制限とクォータ \[#rate-limits-and-quotas]

この API には**キー単位のレート制限も、同時実行の上限も、リクエストのクォータもありません**。使用量を縛るのは次の 2 つだけです。

| 制約      | 値                                                              |
| ------- | -------------------------------------------------------------- |
| クレジット残高 | リクエストのたびに確認され、足りなければ `insufficient_quota` が返ります                |
| 無料モデルの枠 | アカウントごとに 3 時間で 15 通——Pro ×3（45）、Premium ×4（60）、Ultimate ×5（75） |

無料モデルの枠は、ウェブのチャット、ストーリー、小説、ボットと共通です——入口ごとではなく、アカウントごとに 1 つの持ち分です。[無料モデル →](https://reverie.im/ja/docs/reference/free-models)

Reverie は外向きの webhook を送りません。生成完了を受け取るために購読するものはありません。

## キャラクターの取り込み \[#importing-characters]

もう 1 つのエンドポイント `POST /api/v1/characters/import` は、キャラクターカードからキャラクターを作ります。取り込み用の権限を持つキーが必要で、これは設定ページが作るキーとは別種です。[APIキー →](https://reverie.im/ja/docs/integrations/api-keys) と [キャラクターの取り込み →](https://reverie.im/ja/docs/characters/import-characters)

## 関連 \[#related]

* [APIキー](https://reverie.im/ja/docs/integrations/api-keys) —— キーの作成、固定、期限、使用状況
* [モデル](https://reverie.im/ja/docs/reference/models) —— モデル ID とクレジット倍率
* [制限](https://reverie.im/ja/docs/reference/limits) —— プロダクト内のそのほかの上限
* [クレジット](https://reverie.im/ja/docs/billing/credits) —— リクエストの料金の決まり方
