Open API
An OpenAI-compatible endpoint for your Reverie characters. Drop it into any tool that already speaks OpenAI — SDKs, agent frameworks, IDE extensions, custom apps.
The Reverie Open API exposes any character you can chat with on the platform — your own, or any public character — through an OpenAI-compatible chat completions endpoint. If your tool already talks to OpenAI, point it at Reverie instead and replace the model name with a character name. The character replies with their full personality, scenarios, and persistent memory intact.
Open API is a Labs feature. It's stable and production-ready; the Labs page at /app/labs is where it's surfaced to users. Manage your keys at /app/settings/api-keys.
What it gives you
- Use your characters anywhere. Discord bots, agent frameworks, IDE plugins, voice apps, anything that can call an HTTP endpoint.
- Server-side persistence. Chats from the API show up in your Reverie web UI like any other conversation. Memory, summaries, identities — all the same continuity.
- OpenAI client-drop-in. Change
base_urlandmodel; everything else is the same. - One credit ledger. API usage spends from your Reverie credit balance just like web chat.
Quick start
Create an API key
In Reverie: Settings → API keys → + New key. Give it a name (which app is using it), optionally set a default character (so requests without a model param land on that character), and copy the value.
Keys start with rk_ and are shown once — store them somewhere safe.
See the chat in the web UI
Open the character on reverie.im — the conversation you started from the API is right there in the chat history. Keep it going from the web, switch back to the API, fork it, edit it. Same chat, two surfaces.
The model field
This is the one place where Reverie's API differs from OpenAI: the model parameter isn't a model name, it's which character (or scenario) to talk to.
You can pass it in any of these shapes:
| Shape | Example | Resolves to |
|---|---|---|
| Display name + short ID | "Luna [abc12345]" | The character whose ID ends in abc12345 |
| Display name + scenario short ID | "Cozy Evening [def67890]" | A scenario on the API key's default character (if one is set) |
| Full character ID | "clx9z3k0w0001..." | That exact character |
| Full scenario ID | "clx9z3k0w0001..." | That exact scenario |
| Omitted | (no model field) | Falls back — see priority below |
Resolution priority
When a request comes in, Reverie walks this list to figure out which character should reply:
- Scenario from
model— if the value matches a scenario ID - Character from
model— if the value matches a character ID or short suffix - API key's default character — set when you created the key
- Most recent chat — the last character this user chatted with on web or API
If none of these resolve (no chats at all, no default character, no valid model), the API returns:
Discovering valid model names
GET /v1/models returns the list of names valid for your API key:
- If your API key has a default character, this returns its scenarios (so you can pick which one to chat under).
- Otherwise, this returns the characters you've chatted with most recently on web or API.
Each entry has the shape:
The id is what you pass back in the model field on /v1/chat/completions.
Request shape
Streaming
Streaming is on by default and emits OpenAI-format SSE chunks — data: {...}\n\n lines you parse the same way as any OpenAI client.
Non-streaming
Set stream: false to get a single JSON response with the full message body.
Conversation history
You don't have to track conversation history client-side — Reverie persists it server-side per (API key, character). When you send a request:
- The last user message in
messagesis appended to the server-side conversation. - The model sees the full server-side history (live messages + summaries + long-term memory), not just what you sent.
- If your local
messagesarray is shorter than the server's record, Reverie tail-diff syncs — messages you removed locally cascade-delete server-side too. This is how you "regenerate" or "edit" from a client without forking the conversation.
Most integrations end up sending only [{role: "user", content: "..."}] and letting Reverie manage the rest.
Response shape
Standard OpenAI response object:
Errors
Standard OpenAI error envelope. Reverie-specific codes:
| HTTP | code | Meaning |
|---|---|---|
| 401 | invalid_api_key | Key missing, malformed, or revoked |
| 401 | api_key_expired | Key was set to expire and has |
| 404 | scenario_not_found | Scenario ID in model doesn't exist |
| 404 | character_not_found | Character ID in model doesn't exist |
| 404 | no_chat_history | No model provided, no default character, no past chats |
| 400 | missing_user_message | messages array has no user-role entries |
| 429 | rate_limit_exceeded | Free model rate limit hit (shared across all surfaces) |
| 429 | insufficient_quota | Out of credits |
Free-model requests respond with Retry-After (seconds) when rate-limited.
What gets respected on the server side
Each chat run through the API uses the same engine the web app uses. That means:
- The user's preferred LLM for this character (if set under chat settings) — overrides
modelinmodel_settings. - Memory tools — if the model supports tools, the AI can save / update / delete long-term memories during the reply.
- Summarization — long conversations roll older messages into summaries automatically.
- Token-budget trimming — context is trimmed to fit the chosen LLM's window.
- Credit accounting — input + output tokens × model multiplier debit your balance.
- Free model rate limit —
Llama 3.1 8Bis rate-limited per user across web, bots, and API combined. - Scenario context — if a scenario was resolved, its system context layers onto the reply.
- NSFW intensity / narration style / response length — per-character preferences carry over.
Per-key default character
When creating an API key, you can pin it to a default character. With that set:
GET /v1/modelsreturns that character's scenarios (so model-aware OpenAI tools see useful options).- Requests without a
modelfield land on that character. - Useful for single-character integrations (a Discord bot that's just one character, a tutoring chatbot, etc.).
Rate limits
- Free model: a dynamic per-user rate limit shared with web/bots; returns 429 with
Retry-Afterwhen hit. - Paid models: governed by your credit balance, not request count.
- Per-key concurrency: generous; if you're building something high-volume that hits a wall, email [email protected].
Where to find it in the app
- Labs tile: /app/labs → Open API card
- Key management: /app/settings/api-keys
- OpenAPI spec (auto-generated from route definitions):
/api/openapi.json
Related
- Character Importer skill — port characters from Claude Projects, OpenClaw, etc. — uses the same v1 API under the hood
- Discord bot / Telegram bot — the same engine, exposed as bots instead of an API