# Open API

> Een OpenAI-compatibel endpoint voor je personages.

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

Reverie biedt een OpenAI-compatibel Chat Completions-endpoint. Richt een willekeurige OpenAI-client erop, geef een Reverie-API-sleutel mee en gebruik het veld `model` om een **personage of scenario** te noemen in plaats van een LLM. Reverie bewaart het gesprek, de herinneringen en de samenvattingen aan zijn kant, dus elk verzoek heeft alleen je nieuwe bericht nodig.

Elk ingelogd account kan het gebruiken. Er is geen abonnementsniveau en geen wachtlijst — je hebt een API-sleutel nodig, en dat is alles. [Maak er een →](https://reverie.im/nl/docs/integrations/api-keys)

## Basis-URL en authenticatie \[#base-url-and-auth]

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

**Instellingen → Meer → API-sleutels** toont de exacte basis-URL in de kaart **API-endpoint**, met een kopieerknop.

> **Dit is een API voor de serverkant.** Cross-origin-verzoeken vanuit de
> browser worden geblokkeerd, dus een fetch vanaf je eigen webpagina mislukt,
> welke sleutel je ook gebruikt. Roep de API aan vanuit een backend en houd de
> sleutel uit clientcode.

## Snel aan de slag \[#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 ?? "");
}
```

**Instellingen → Meer → API-sleutels** heeft ook een verzoekbouwer die deze drie fragmenten genereert met een van je echte sleutels en een echt personage.

## Het veld `model` noemt een personage \[#the-model-field-names-a-character]

> **Alleen een personagenaam werkt niet.** `model: "Luna"` zoekt geen
> personage op dat Luna heet. Het komt met niets overeen, valt terug op het
> standaardpersonage van de sleutel of op je meest recente chat, en je krijgt
> een antwoord van een ander personage zonder enige foutmelding. Gebruik altijd
> de vorm `Name [shortid]` die `GET /models` teruggeeft.

| Waarde van `model`                              | Wie antwoordt                                                           |
| ----------------------------------------------- | ----------------------------------------------------------------------- |
| `Luna [abc12345]`                               | Het personage of scenario waarvan de ID op die 8 tekens eindigt         |
| Een volledige personage- of scenario-ID         | Dat personage of scenario                                               |
| Een Reverie-model-ID, bijv. `deepseek-v4-flash` | Kiest het **LLM**; het personage komt van de sleutel of je laatste chat |
| Weggelaten                                      | Het vastgezette personage van de sleutel, anders je meest recente chat  |

Details die bepalen of een korte ID wordt opgelost:

* De `[...]` moet aan het **einde** van de string staan.
* Een achtervoegsel van 8 tekens of minder wordt alleen vergeleken met personages **waarmee je al een chat hebt**, op het web of via de API. Een korte ID voor een personage dat je nooit hebt geopend, valt stilletjes door.
* Scenario's worden alleen opgezocht als de sleutel aan een personage is vastgezet. Met een globale sleutel kan een korte scenario-ID nooit worden opgelost.
* Meer dan 8 tekens wordt behandeld als een volledige ID.

### Opvragen met wie je kunt praten \[#listing-what-you-can-talk-to]

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

Een **globale** sleutel geeft je recente personages terug. Een sleutel die **aan een personage is vastgezet**, geeft in plaats daarvan de scenario's van dat personage terug, of het personage zelf als het er geen heeft. Elk item ziet er zo uit:

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

Kopieer `id` direct naar `model`. Fouten van dit endpoint gebruiken een eenvoudige foutvorm in plaats van de OpenAI-envelop.

## Wat er uit de request body wordt gelezen \[#what-the-request-body-reads]

Er worden vier velden gelezen. Al het andere wordt geaccepteerd en stilletjes genegeerd.

| Veld          | Type      | Standaard                                  | Opmerkingen                                             |
| ------------- | --------- | ------------------------------------------ | ------------------------------------------------------- |
| `messages`    | array     | verplicht                                  | Zie hieronder — slechts een deel ervan wordt gebruikt   |
| `model`       | string    | optioneel                                  | Personage, scenario of LLM, zoals hierboven             |
| `stream`      | boolean   | **`true`**                                 | Streaming is de standaard, anders dan bij de OpenAI-API |
| `temperature` | getal 0–2 | instelling van het personage, anders `0.8` | Waarden buiten het bereik worden geweigerd              |

Zonder waarschuwing genegeerd: `max_tokens`, `top_p`, `n`, `stop`, `presence_penalty`, `frequency_penalty`, `logit_bias`, `seed`, `user`, `response_format`, `tools`, `tool_choice`, `logprobs`, `stream_options`.

Hoe `messages` wordt verwerkt:

* **`system`-berichten worden weggegooid.** Persona en gedrag komen uit de eigen velden van het personage, niet uit het verzoek. [Promptvelden →](https://reverie.im/nl/docs/characters/prompt-fields)
* **Er is geen ondersteuning voor beeldinvoer.** De inhoud mag een string of een array met onderdelen zijn, maar alleen `text`-onderdelen worden gelezen; afbeeldingsonderdelen worden genegeerd.
* Alleen het **laatste `user`-bericht** wordt aan het gesprek toegevoegd. Eerdere gebruikersberichten worden genegeerd.
* Assistant-berichten worden alleen gebruikt om de geschiedenis te synchroniseren (zie hieronder).
* Een leeg laatste gebruikersbericht, of een dat alleen uit witruimte bestaat, geeft `missing_user_message`.

## Antwoorden \[#responses]

Een antwoord zonder streaming is een normaal `chat.completion`-object. `finish_reason` is altijd `stop` — interne toolaanroepen worden nooit getoond — en de `usage`-tellers staan op nul, dus meet tokens via de gebruiksstatistieken op de pagina met API-sleutels in plaats van via het antwoord.

Een streamingantwoord is `text/event-stream`:

1. Inhoudschunks: `chat.completion.chunk`-objecten met `delta.content`. \*&#x2A;Er wordt geen eerste chunk `delta: {"role": "assistant"}` verstuurd.*\*
2. Een afsluitende chunk, met `finish_reason` `stop`, `length` of `content_filter`. Afsluitingen door toolaanroepen worden gemeld als `stop`.
3. Een usage-chunk met een lege `choices`-array.
4. `data: [DONE]`.

Mislukt het genereren halverwege de stream, dan stuurt de stream `data: {"error": {...}}` en daarna `[DONE]`.

## Gespreksstatus \[#conversation-state]

Reverie slaat het gesprek op. Er bestaat één chat per combinatie van sleutel en personage, die verschijnt in de webapp naast je andere chats, en elke beurt wordt opgebouwd uit de systeemprompt en het scenario van het personage, canon uit wereldboeken, langetermijnherinneringen, doorlopende samenvattingen, de vertelstijl van het personage, de antwoordlengte en NSFW-instellingen, een taalvergrendeling op basis van de taal van je account, en zoveel van de recente geschiedenis als het contextvenster van het model toelaat. Geheugentools draaien als het model tools ondersteunt.

Omdat de server de geschiedenis bewaart, hoef je die niet opnieuw mee te sturen.

> **Assistant-berichten meesturen kan geschiedenis verwijderen.** Als je
> `messages`-array assistant-berichten bevat, neemt Reverie het laatste ervan,
> zoekt het op tussen de 20 meest recent opgeslagen berichten en verwijdert bij
> een overeenkomst definitief elk bericht dat daarna is gemaakt, samen met de
> herinneringen die na dat punt zijn ontstaan. Is er geen overeenkomst, dan wordt
> er niets verwijderd. De lengte van je array maakt niet uit. Wil je dit volledig
> vermijden, stuur dan alleen het nieuwe gebruikersbericht.

## Welk LLM antwoordt \[#which-llm-answers]

Het personage beslist, niet het verzoek — tenzij je een LLM noemt. Rangorde, van laag naar hoog: het standaard chatmodel, dan de eigen modelinstelling van het personage, dan een Reverie-model-ID die je als `model` meegeeft, en tot slot de modelvoorkeur per chat die je in de webapp hebt ingesteld, die van alle andere wint. [Modellen →](https://reverie.im/nl/docs/reference/models)

## Fouten \[#errors]

Fouten van `/chat/completions` gebruiken de OpenAI-envelop: `{"error": {"message", "type", "param": null, "code"}}`.

| HTTP      | `code`                 | `type`                  | Oorzaak                                                                                              |
| --------- | ---------------------- | ----------------------- | ---------------------------------------------------------------------------------------------------- |
| 401       | `invalid_api_key`      | `invalid_request_error` | `Authorization` ontbreekt of is onjuist opgemaakt, onbekende sleutel, of de sleutel is inactief      |
| 401       | `api_key_expired`      | `invalid_request_error` | De sleutel is verlopen                                                                               |
| 404       | `scenario_not_found`   | `invalid_request_error` | Een scenario-ID is opgelost, maar het scenario bestaat niet meer                                     |
| 404       | `character_not_found`  | `invalid_request_error` | Het personage ontbreekt of is verwijderd                                                             |
| 404       | `no_chat_history`      | `invalid_request_error` | Geen `model`, geen vastgezet personage en geen eerdere chat om op terug te vallen                    |
| 400       | `missing_user_message` | `invalid_request_error` | Geen niet-leeg `user`-bericht                                                                        |
| 429       | `rate_limit_exceeded`  | `rate_limit_exceeded`   | Venster van het gratis model opgebruikt. `Retry-After` geeft het aantal seconden dat je moet wachten |
| 429       | `insufficient_quota`   | `insufficient_quota`    | Niet genoeg credits voor het verzoek                                                                 |
| 502       | `MODEL_EMPTY_RESPONSE` | `server_error`          | Het model is netjes klaar maar gaf geen tekst                                                        |
| wisselend | code van de provider   | `server_error`          | Genereren is bij de provider mislukt                                                                 |

Twee gevallen vallen buiten die envelop: fouten van `GET /models`, en request bodies die bij de validatie worden geweigerd (bijvoorbeeld een `temperature` buiten het bereik) — beide geven een eenvoudige foutvorm terug.

## Snelheidslimieten en quota \[#rate-limits-and-quotas]

Deze API heeft **geen snelheidslimiet per sleutel, geen maximum aan gelijktijdige verzoeken en geen quotum voor verzoeken**. Twee dingen begrenzen je gebruik:

| Grens                        | Waarde                                                                                           |
| ---------------------------- | ------------------------------------------------------------------------------------------------ |
| Creditsaldo                  | Wordt vóór elk verzoek gecontroleerd; is het te laag, dan krijg je `insufficient_quota`          |
| Venster van het gratis model | 15 berichten per 3 uur, per account — ×3 met Pro (45), ×4 met Premium (60), ×5 met Ultimate (75) |

Het venster van het gratis model deel je met de webchat, verhalen, romans en de bots — het is één tegoed per account, niet één per onderdeel. [Gratis modellen →](https://reverie.im/nl/docs/reference/free-models)

Reverie stuurt geen uitgaande webhooks; er is niets waarop je je kunt abonneren voor afrondingsgebeurtenissen.

## Personages importeren \[#importing-characters]

Een tweede endpoint, `POST /api/v1/characters/import`, maakt een personage aan op basis van een personagekaart. Daarvoor is een sleutel met het importbereik nodig, en dat is niet het soort sleutel dat de instellingenpagina aanmaakt. [API-sleutels →](https://reverie.im/nl/docs/integrations/api-keys) en [Personages importeren →](https://reverie.im/nl/docs/characters/import-characters)

## Gerelateerd \[#related]

* [API-sleutels](https://reverie.im/nl/docs/integrations/api-keys) — sleutels maken, vastzetten, laten verlopen en volgen
* [Modellen](https://reverie.im/nl/docs/reference/models) — model-ID's en creditvermenigvuldigers
* [Limieten](https://reverie.im/nl/docs/reference/limits) — de andere grenzen in het product
* [Credits](https://reverie.im/nl/docs/billing/credits) — hoe verzoeken worden geprijsd
