# Open API

> 당신의 캐릭터를 부를 수 있는 OpenAI 호환 엔드포인트.

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

Reverie는 OpenAI 호환 Chat Completions 엔드포인트를 제공합니다. 어떤 OpenAI 클라이언트든 여기로 향하게 하고, Reverie API 키를 넘기고, `model` 필드에는 LLM 대신 **캐릭터나 시나리오**를 적으세요. 대화와 기억과 요약은 Reverie 쪽에 남으므로, 요청마다 필요한 것은 새 메시지 하나뿐입니다.

로그인한 계정이면 누구나 쓸 수 있습니다. 구독 등급도 대기자 명단도 없습니다 — 필요한 건 API 키뿐입니다. [만들러 가기 →](https://reverie.im/ko/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 키**에는 당신의 실제 키 하나와 실제 캐릭터로 위 세 가지 코드를 만들어 주는 요청 빌더도 있습니다.

## `model` 필드는 캐릭터를 가리킵니다 \[#the-model-field-names-a-character]

> **이름만 적으면 되지 않습니다.** `model: "Luna"`는 Luna라는 캐릭터를 찾아 주지 않습니다. 아무것도 맞추지 못한 채 키의 기본 캐릭터나 가장 최근 대화로 흘러가고, 오류 없이 다른 캐릭터의 답이 옵니다. 언제나 `GET /models`가 돌려주는 `이름 [짧은ID]` 형태를 쓰세요.

| `model` 값                             | 누가 답하는가                             |
| ------------------------------------- | ----------------------------------- |
| `Luna [abc12345]`                     | ID가 그 여덟 글자로 끝나는 캐릭터 또는 시나리오        |
| 전체 캐릭터 ID 또는 시나리오 ID                  | 그 캐릭터 또는 시나리오                       |
| Reverie 모델 ID, 예: `deepseek-v4-flash` | **LLM**을 고릅니다. 캐릭터는 키나 마지막 대화에서 옵니다 |
| 생략                                    | 키에 고정된 캐릭터, 없으면 가장 최근 대화            |

짧은 ID가 풀리는지를 결정하는 세부 사항:

* `[...]`는 문자열 **끝**에 있어야 합니다.
* 여덟 글자 이하의 접미사는 웹에서든 API에서든 **이미 대화한 적 있는 캐릭터**하고만 맞춰 봅니다. 한 번도 열어본 적 없는 캐릭터의 짧은 ID는 조용히 빗나갑니다.
* 시나리오 조회는 키가 캐릭터에 고정되어 있을 때만 돕니다. 전역 키로는 짧은 시나리오 ID가 결코 풀리지 않습니다.
* 여덟 글자를 넘으면 전체 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`      | 불리언    | **`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/ko/docs/characters/prompt-fields)
* **비전은 지원하지 않습니다.** 내용은 문자열이어도 조각 배열이어도 되지만 `text` 조각만 읽히고, 이미지 조각은 무시됩니다.
* 대화에 더해지는 것은 **마지막 `user` 메시지**뿐입니다. 그 앞의 사용자 메시지는 무시됩니다.
* 어시스턴트 메시지는 아래의 기록 동기화에만 쓰입니다.
* 마지막 사용자 메시지가 비었거나 공백뿐이면 `missing_user_message`가 돌아옵니다.

## 응답 \[#responses]

스트리밍이 아닌 응답은 평범한 `chat.completion` 객체입니다. `finish_reason`은 언제나 `stop`이고 — 내부 도구 호출은 절대 드러나지 않습니다 — `usage` 수치는 전부 0이므로, 토큰은 응답이 아니라 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가 보관합니다. 키와 캐릭터의 짝마다 대화 하나가 존재하고, 웹 앱에서도 다른 대화들과 나란히 보입니다. 매 턴은 캐릭터의 시스템 프롬프트와 시나리오, 월드북의 설정, 장기 기억, 갱신되는 요약, 캐릭터의 서술 방식과 응답 길이와 NSFW 설정, 계정 언어에서 온 언어 고정, 그리고 모델의 컨텍스트 창이 허용하는 만큼의 최근 기록으로 짜입니다. 모델이 도구를 지원하면 기억 도구도 함께 돕니다.

기록은 서버가 들고 있으니 다시 보낼 필요가 없습니다.

> **어시스턴트 메시지를 보내면 기록이 지워질 수 있습니다.** `messages` 배열에 어시스턴트 메시지가 들어 있으면 Reverie는 그 마지막 것을 집어 저장된 최근 20개 메시지에서 찾습니다. 맞는 것이 있으면 그 뒤에 만들어진 모든 메시지와, 그 시점 뒤에 생긴 기억을 영구히 지웁니다. 맞는 것이 없으면 아무것도 지우지 않습니다. 배열의 길이는 상관없습니다. 아예 피하려면 새 사용자 메시지만 보내세요.

## 어떤 LLM이 답하는가 \[#which-llm-answers]

요청이 아니라 캐릭터가 정합니다 — 당신이 LLM을 직접 지목한 경우만 빼고요. 우선순위는 낮은 쪽부터 기본 대화 모델, 그다음 캐릭터 자신의 모델 설정, 그다음 `model`로 넘긴 Reverie 모델 ID, 마지막으로 웹 앱에서 그 대화에 지정한 모델 선호이며, 이것이 전부를 이깁니다. [모델 →](https://reverie.im/ko/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`를 돌려줍니다             |
| 무료 모델 창 | 계정당 3시간에 15개 — Pro ×3(45), Premium ×4(60), Ultimate ×5(75) |

무료 모델 창은 웹 채팅, 스토리, 소설, 봇과 함께 씁니다 — 창구마다 따로가 아니라 계정당 하나의 몫입니다. [무료 모델 →](https://reverie.im/ko/docs/reference/free-models)

Reverie는 바깥으로 웹훅을 보내지 않습니다. 생성 완료를 받아 볼 구독 대상이 없습니다.

## 캐릭터 가져오기 \[#importing-characters]

두 번째 엔드포인트 `POST /api/v1/characters/import`는 캐릭터 카드로 캐릭터를 만듭니다. 가져오기 권한이 있는 키가 필요하고, 그것은 설정 페이지가 만들어 주는 종류의 키가 아닙니다. [API 키 →](https://reverie.im/ko/docs/integrations/api-keys) 및 [캐릭터 가져오기 →](https://reverie.im/ko/docs/characters/import-characters)

## 관련 문서 \[#related]

* [API 키](https://reverie.im/ko/docs/integrations/api-keys) — 키를 만들고, 고정하고, 만료시키고, 사용량을 봅니다
* [모델](https://reverie.im/ko/docs/reference/models) — 모델 ID와 크레딧 배수
* [제한](https://reverie.im/ko/docs/reference/limits) — 제품 안의 다른 상한들
* [크레딧](https://reverie.im/ko/docs/billing/credits) — 요청 가격이 매겨지는 방식
