# Open API

> Ein OpenAI-kompatibler Endpunkt für deine Figuren.

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

Reverie stellt einen OpenAI-kompatiblen Chat-Completions-Endpunkt bereit. Richte irgendeinen OpenAI-Client darauf, gib einen Reverie-API-Schlüssel mit, und nenne im Feld `model` eine **Figur oder ein Szenario** statt eines LLM. Reverie hält Unterhaltung, Erinnerungen und Zusammenfassungen auf seiner Seite, deshalb braucht jede Anfrage nur deine neue Nachricht.

Jedes angemeldete Konto kann ihn nutzen. Es gibt keine Abostufe und keine Warteliste — du brauchst einen API-Schlüssel, mehr nicht. [Einen anlegen →](https://reverie.im/de/docs/integrations/api-keys)

## Basis-URL und Authentifizierung \[#base-url-and-auth]

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

**Einstellungen → Mehr → API-Schlüssel** zeigt die genaue Basis-URL in der Karte **API Endpoint**, mit Kopierknopf.

> **Das ist eine serverseitige API.** Browser-Anfragen von fremder Herkunft werden blockiert, ein fetch von deiner eigenen Webseite scheitert also unabhängig vom Schlüssel. Ruf sie aus einem Backend auf und halte den Schlüssel aus dem Client-Code heraus.

## Schnellstart \[#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 ?? "");
}
```

**Einstellungen → Mehr → API-Schlüssel** hat außerdem einen Anfragen-Baukasten, der diese drei Schnipsel mit einem deiner echten Schlüssel und einer echten Figur erzeugt.

## Das Feld `model` nennt eine Figur \[#the-model-field-names-a-character]

> **Ein bloßer Figurname funktioniert nicht.** `model: "Luna"` schlägt keine Figur namens Luna nach. Es passt auf nichts, fällt auf die Standardfigur des Schlüssels oder deinen letzten Chat zurück, und du bekommst die Antwort einer anderen Figur, ganz ohne Fehler. Nimm immer die Form `Name [kurzid]`, die `GET /models` zurückgibt.

| Wert von `model`                                  | Wer antwortet                                                                 |
| ------------------------------------------------- | ----------------------------------------------------------------------------- |
| `Luna [abc12345]`                                 | Die Figur oder das Szenario, deren ID auf diese 8 Zeichen endet               |
| Eine vollständige Figuren- oder Szenario-ID       | Diese Figur oder dieses Szenario                                              |
| Eine Reverie-Modell-ID, z. B. `deepseek-v4-flash` | Wählt das **LLM**; die Figur kommt aus dem Schlüssel oder deinem letzten Chat |
| Weggelassen                                       | Die am Schlüssel angeheftete Figur, sonst dein letzter Chat                   |

Was darüber entscheidet, ob eine kurze ID aufgelöst wird:

* Das `[...]` muss am **Ende** der Zeichenkette stehen.
* Ein Suffix von 8 Zeichen oder weniger wird nur gegen Figuren geprüft, **mit denen du bereits einen Chat hast**, im Web oder über die API. Die kurze ID einer nie geöffneten Figur läuft stillschweigend ins Leere.
* Die Szenariosuche läuft nur, wenn der Schlüssel an eine Figur geheftet ist. Mit einem globalen Schlüssel kann eine kurze Szenario-ID nie aufgelöst werden.
* Mehr als 8 Zeichen gelten als vollständige ID.

### Auflisten, mit wem du reden kannst \[#listing-what-you-can-talk-to]

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

Ein **globaler** Schlüssel gibt deine letzten Figuren zurück. Ein **an eine Figur gehefteter** Schlüssel gibt stattdessen die Szenarien dieser Figur zurück, oder die Figur selbst, wenn sie keine hat. Ein Eintrag sieht so aus:

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

Kopier `id` direkt in `model`. Fehler dieses Endpunkts nutzen eine schlichte Fehlerform statt der OpenAI-Hülle.

## Was vom Anfragekörper gelesen wird \[#what-the-request-body-reads]

Vier Felder werden gelesen. Alles andere wird angenommen und stillschweigend verworfen.

| Feld          | Typ      | Standard                           | Hinweise                                                  |
| ------------- | -------- | ---------------------------------- | --------------------------------------------------------- |
| `messages`    | Array    | Pflicht                            | Siehe unten — nur ein Teil davon wird genutzt             |
| `model`       | String   | optional                           | Figur, Szenario oder LLM, wie oben                        |
| `stream`      | Boolean  | **`true`**                         | Streaming ist der Standard, anders als bei der OpenAI-API |
| `temperature` | Zahl 0–2 | Einstellung der Figur, sonst `0.8` | Werte außerhalb des Bereichs werden abgelehnt             |

Ohne Warnung ignoriert: `max_tokens`, `top_p`, `n`, `stop`, `presence_penalty`, `frequency_penalty`, `logit_bias`, `seed`, `user`, `response_format`, `tools`, `tool_choice`, `logprobs`, `stream_options`.

Wie `messages` behandelt wird:

* **`system`-Nachrichten werden verworfen.** Persönlichkeit und Verhalten stammen aus den Feldern der Figur, nicht aus der Anfrage. [Prompt-Felder →](https://reverie.im/de/docs/characters/prompt-fields)
* **Es gibt keine Bildverarbeitung.** Der Inhalt darf ein String oder ein Array von Teilen sein, gelesen werden aber nur `text`-Teile; Bildteile werden ignoriert.
* Nur die **letzte `user`-Nachricht** wird der Unterhaltung hinzugefügt. Frühere Nutzernachrichten werden ignoriert.
* Assistenten-Nachrichten dienen allein dem Abgleich des Verlaufs (siehe unten).
* Eine leere oder nur aus Leerzeichen bestehende letzte Nutzernachricht liefert `missing_user_message`.

## Antworten \[#responses]

Eine Antwort ohne Streaming ist ein gewöhnliches `chat.completion`-Objekt. `finish_reason` ist immer `stop` — interne Werkzeugaufrufe werden nie sichtbar — und die `usage`-Zähler stehen auf null, miss Tokens also über die Nutzungsstatistik auf der Seite der API-Schlüssel statt über die Antwort.

Eine Streaming-Antwort ist ein `text/event-stream`:

1. Inhaltsblöcke: `chat.completion.chunk`-Objekte mit `delta.content`. **Ein einleitender `delta: {"role": "assistant"}`-Block wird nicht gesendet.**
2. Ein Abschlussblock mit `finish_reason` `stop`, `length` oder `content_filter`. Abschlüsse durch Werkzeugaufrufe werden als `stop` gemeldet.
3. Ein Nutzungsblock mit leerem `choices`-Array.
4. `data: [DONE]`.

Scheitert die Generierung mitten im Stream, sendet der Stream `data: {"error": {...}}` und danach `[DONE]`.

## Zustand der Unterhaltung \[#conversation-state]

Reverie speichert die Unterhaltung. Pro Schlüssel-und-Figur-Paar existiert ein Chat, er taucht in der Web-App neben deinen anderen Chats auf, und jeder Zug wird gebaut aus dem System-Prompt und dem Szenario der Figur, dem Kanon aus Weltbüchern, Langzeit-Erinnerungen, laufenden Zusammenfassungen, dem Erzählstil der Figur, Antwortlänge und NSFW-Einstellungen, einer Sprachfestlegung aus der Sprache deines Kontos und so viel jüngerem Verlauf, wie das Kontextfenster des Modells fasst. Erinnerungs-Werkzeuge laufen, wenn das Modell Werkzeuge unterstützt.

Da der Server den Verlauf hält, musst du ihn nicht noch einmal mitschicken.

> **Assistenten-Nachrichten zu senden kann Verlauf löschen.** Enthält dein `messages`-Array Assistenten-Nachrichten, nimmt Reverie die letzte davon, sucht sie unter den 20 zuletzt gespeicherten Nachrichten und löscht bei einem Treffer dauerhaft jede danach erstellte Nachricht samt der Erinnerungen, die nach diesem Punkt entstanden sind. Gibt es keinen Treffer, wird nichts gelöscht. Die Länge deines Arrays spielt keine Rolle. Um das ganz zu vermeiden, schick nur die neue Nutzernachricht.

## Welches LLM antwortet \[#which-llm-answers]

Das entscheidet die Figur, nicht die Anfrage — es sei denn, du nennst ein LLM. Reihenfolge von schwach nach stark: das Standard-Chatmodell, dann die Modelleinstellung der Figur, dann eine als `model` übergebene Reverie-Modell-ID, und zuletzt die Modellvorliebe, die du in der Web-App für diesen Chat gesetzt hast — sie schlägt alle anderen. [Modelle →](https://reverie.im/de/docs/reference/models)

## Fehler \[#errors]

Fehler von `/chat/completions` nutzen die OpenAI-Hülle: `{"error": {"message", "type", "param": null, "code"}}`.

| HTTP      | `code`                 | `type`                  | Ursache                                                                                            |
| --------- | ---------------------- | ----------------------- | -------------------------------------------------------------------------------------------------- |
| 401       | `invalid_api_key`      | `invalid_request_error` | `Authorization` fehlt oder ist falsch geformt, Schlüssel unbekannt, oder der Schlüssel ist inaktiv |
| 401       | `api_key_expired`      | `invalid_request_error` | Der Schlüssel ist abgelaufen                                                                       |
| 404       | `scenario_not_found`   | `invalid_request_error` | Eine Szenario-ID wurde aufgelöst, das Szenario gibt es aber nicht mehr                             |
| 404       | `character_not_found`  | `invalid_request_error` | Die Figur fehlt oder wurde gelöscht                                                                |
| 404       | `no_chat_history`      | `invalid_request_error` | Kein `model`, keine angeheftete Figur und kein früherer Chat als Rückfall                          |
| 400       | `missing_user_message` | `invalid_request_error` | Keine nicht-leere `user`-Nachricht                                                                 |
| 429       | `rate_limit_exceeded`  | `rate_limit_exceeded`   | Fenster für kostenlose Modelle aufgebraucht. `Retry-After` nennt die Wartezeit in Sekunden         |
| 429       | `insufficient_quota`   | `insufficient_quota`    | Nicht genug Guthaben für die Anfrage                                                               |
| 502       | `MODEL_EMPTY_RESPONSE` | `server_error`          | Das Modell endete sauber, aber ohne Text                                                           |
| wechselnd | Code des Anbieters     | `server_error`          | Generierung stromaufwärts fehlgeschlagen                                                           |

Zwei Fälle fallen aus dieser Hülle heraus: Fehler von `GET /models` und Anfragekörper, die an der Prüfung scheitern (etwa eine `temperature` außerhalb des Bereichs) — beide liefern eine schlichte Fehlerform.

## Ratenlimits und Kontingente \[#rate-limits-and-quotas]

Diese API hat **kein Ratenlimit pro Schlüssel, keine Obergrenze für gleichzeitige Anfragen und kein Anfragekontingent**. Nur zwei Dinge begrenzen deine Nutzung:

| Grenze                         | Wert                                                                                                 |
| ------------------------------ | ---------------------------------------------------------------------------------------------------- |
| Guthabenstand                  | Wird vor jeder Anfrage geprüft; reicht er nicht, kommt `insufficient_quota`                          |
| Fenster für kostenlose Modelle | 15 Nachrichten pro 3 Stunden, pro Konto — ×3 bei Pro (45), ×4 bei Premium (60), ×5 bei Ultimate (75) |

Das Fenster für kostenlose Modelle teilst du mit dem Web-Chat, Geschichten, Romanen und den Bots — es ist ein Kontingent pro Konto, nicht eines pro Oberfläche. [Kostenlose Modelle →](https://reverie.im/de/docs/reference/free-models)

Reverie sendet keine ausgehenden Webhooks; es gibt nichts zu abonnieren, um vom Ende einer Generierung zu erfahren.

## Figuren importieren \[#importing-characters]

Ein zweiter Endpunkt, `POST /api/v1/characters/import`, legt aus einer Figurenkarte eine Figur an. Er verlangt einen Schlüssel mit Import-Berechtigung, und das ist nicht die Art Schlüssel, die die Einstellungsseite anlegt. [API-Schlüssel →](https://reverie.im/de/docs/integrations/api-keys) und [Charaktere importieren →](https://reverie.im/de/docs/characters/import-characters)

## Verwandt \[#related]

* [API-Schlüssel](https://reverie.im/de/docs/integrations/api-keys) — Schlüssel anlegen, anheften, ablaufen lassen und beobachten
* [Modelle](https://reverie.im/de/docs/reference/models) — Modell-IDs und Guthaben-Multiplikatoren
* [Limits](https://reverie.im/de/docs/reference/limits) — die übrigen Obergrenzen im Produkt
* [Credits](https://reverie.im/de/docs/billing/credits) — wie Anfragen bepreist werden
