OpenAI and OpenAI-compatible keys
In the desktop or Android app
- Create a key at platform.openai.com/api-keys on an account with billing set up. Give it a name like "Open Dungeon Master" so you can revoke it later.
- Home screen, Story AI, Your OpenAI API key.
- Paste the key, list the models it can use, and choose the Dungeon Master model. An optional utility model handles cheaper chores; blank uses the story model. Save.
That is the whole setup. The key is the device's: every campaign on the world, including ones made before the key existed, can tell the story and paint with it. Picture and transcription models come from the key's own list: a single clear recommendation is chosen, otherwise finish choosing them in Admin, Images and Speech. Until a picture model is selected, pictures use placeholders. You can also opt into OpenAI read-aloud on the same key. The screen remembers that a key is saved ("Saved on this device. Blank keeps it") and brings the model names back filled in, so switching models later is one field. Inside a campaign, the Settings tab shows the device's storyteller and keeps pictures on or off, their shape and speed, and passage length per campaign.
On a self-hosted server
Admin, Server settings, Text model: provider Custom backend, backend URL https://api.openai.com/v1, the model you pay for, and the key. Or in .env.server:
DEFAULT_TEXT_PROVIDER=custom
OPENAI_COMPAT_BASE_URL=https://api.openai.com/v1
OPENAI_COMPAT_MODEL=your-listed-story-model
OPENAI_COMPAT_API_KEY=sk-...
UTILITY_TEXT_MODEL=your-listed-utility-modelAn administrator can point a single campaign elsewhere in its Settings tab with a key of its own; campaigns anyone else owns use the server's. Press Test backend once: it streams a line, makes a real function call and continues after it, the way a turn does, and shows which OpenAI route the model takes. A saved key only goes to the host it was saved for: moving the storyteller to another address clears it, and Test backend never tries it against a newly typed one.
One key for pictures too
A story whose backend host is api.openai.com lends its key to the OpenAI image backend, so nobody pastes the same key twice: scene art, location maps and portraits paint on it. The lending is gated on the host, so a key for llama.cpp, LM Studio or OpenRouter is never sent to OpenAI. On a server, campaign covers and library portraits paint from the server's own image settings, not a campaign's key; set OPENAI_IMAGE_API_KEY (or the Images section) for those. Select an image model from the provider's list; a blank image model means no pictures. Fast and slow request medium and high quality where the model supports those choices. A refusal may fall back to a supported quality or size.
Context
OpenAI models use the catalog's context size capped at 128K, with a 128K fallback for an unknown model, so far more of the story reaches the Dungeon Master than the 16K stand-in an unknown endpoint gets. Retired small models keep their real sizes. OPENAI_COMPAT_CONTEXT overrides in either direction.
Provider compatibility
The app discovers models from the backend and uses the model catalog for capabilities and context sizes. It adapts supported parameters and can switch between Chat Completions and Responses when the provider requires it. You choose a listed, tool-capable model; you do not need to configure the request route. Test backend checks streaming, an actual function call and the continuation after it.
Cost
You pay OpenAI per token. A turn sends the packed prompt (tens of thousands of tokens on a long campaign) and receives a few hundred back; the utility model handles the cheap chores. Pictures are the expensive part of a session and can be turned off, set to fast, or limited by shape in the Settings tab. Watch usage on OpenAI's dashboard for the first session or two.
Any other OpenAI-compatible endpoint
The same three fields work for anything that speaks the chat completions API with tool calling: a hosted router, a vLLM or LM Studio server on your network, a provider's own compatible endpoint. Use the provider's base URL (ending in /v1 for most), the model id exactly as they name it, and their key. On the apps, these go in the world's admin panel rather than the Story AI screen. Known hosted providers use catalog capabilities and context sizes, capped at 128K for prompt packing. A self-hosted endpoint can report its actual window (llama.cpp does); an unknown endpoint falls back to 16K. Set OPENAI_COMPAT_CONTEXT when the server needs an explicit override.