Docs
NextChat
A self-hosted NextChat reaches Kunavo through the variables it already has for OpenAI: OPENAI_API_KEY holds the key, BASE_URL holds the origin, CUSTOM_MODELS holds the ids. No fork, no patch.
Three environment variables — OPENAI_API_KEY, BASE_URL (bare origin) and CUSTOM_MODELS — put a self-hosted NextChat on Claude, GPT and Gemini through one key.
CODE=your-access-password
OPENAI_API_KEY=sk-kn-...
BASE_URL=https://api.kunavo.com
HIDE_USER_API_KEY=1
CUSTOM_MODELS=-all,+claude-sonnet-5@OpenAI,+claude-opus-5@OpenAI,+claude-haiku-4-5@OpenAI,+gpt-5-6-sol@OpenAI,+gemini-3-1-pro@OpenAIBASE_URL takes the bare origin, with no /v1. The docs page has no sentence about the suffix, but its own row settles it: the documented default is https://api.openai.com, not https://api.openai.com/v1 — NextChat appends the rest of the path. A /v1 you add by hand becomes /v1/v1/chat/completions, which comes back as a 404 and reads like a broken endpoint rather than a typo.OPENAI_API_KEY set, the server calls Kunavo with your key and everyone who gets past CODE spends your balance. HIDE_USER_API_KEY=1 is documented as "If you do not want users to input their own API key, set this value to 1" — leave it unset instead and each visitor can paste their own key in Settings, which is the shape you want for a shared instance.-all prefix and the @OpenAI suffix are not in the documented table, which covers only +, - and name=displayName. They come from NextChat's own model-collection code, read on the same day: -all clears the built-in list so the picker does not offer ids Kunavo will reject, and @OpenAI pins each new id to the OpenAI provider so it is sent to BASE_URL. An id written without that suffix gets a provider named after itself and does not travel the path you configured. The capitalisation is literal.ENABLE_BALANCE_QUERY unset as well: the balance check calls OpenAI's own dashboard billing routes, which are not part of the OpenAI-compatible surface. Your balance lives on /app/billing.Step by step
- Create a key at
/app/keysand copy it — it is shown once. - Set
OPENAI_API_KEYto that key andBASE_URLtohttps://api.kunavo.com. In Vercel these are project environment variables; in Docker they are-eflags; locally they go in.env.local. - Set
CODEto an access password, or the deployment is open to whoever finds the URL while your key is the one paying. - List the ids you want in
CUSTOM_MODELS, each with the@OpenAIsuffix, starting with-allto drop the built-ins. - Redeploy — environment variables are read by the server, so a Vercel project needs a new deployment and a container needs a restart. Editing the variable alone changes nothing in a running instance.
- Open the app, pick one of your ids in the model selector and send a message. If the reply arrives, the three variables agree.
Checked against NextChat's Environment Variables page on September 21, 2026. Third-party settings move; if a field name here no longer matches what you see, that page is the authority, not this one.
Verify before you debug the client
One request settles whether a failure is the endpoint, the key, or the configuration file. If this returns JSON, the same base URL and key work in NextChat.
# Settles whether a failure is the endpoint, the key, or the client.
curl -sS https://api.kunavo.com/v1/models \
-H "Authorization: Bearer sk-kn-..."Which model id to put in the field
Every text model is reachable as a model id — the live list is GET /v1/models, and the catalog with prices is on the models page. Rates are USD per 1M tokens, input / output.
| Model id | Kunavo in / out | Where it fits in NextChat |
|---|---|---|
claude-sonnet-5 | $2.00 / $10.00 | the everyday thread — long conversations without watching the balance |
claude-opus-5 | $2.00 / $10.00 | the one question a week that deserves the expensive model |
claude-haiku-4-5 | $0.40 / $2.00 | summarising, renaming chats, and the short back-and-forth that dominates a shared instance |
gpt-5-6-sol | $2.00 / $12.00 | a second family in the same picker, on the same key |
gemini-3-1-pro | $0.70 / $4.20 | long pasted documents, where the context window is the deciding feature |
FAQ
How do I point NextChat at a custom API endpoint?
Set BASE_URL to the endpoint's origin and OPENAI_API_KEY to the key it issued, both as environment variables on the self-hosted deployment. NextChat's own Environment Variables page documents BASE_URL as "Override OpenAI API request base URL", so nothing needs patching: the app keeps speaking the OpenAI wire format and sends it somewhere else. Redeploy afterwards — the values are read on the server, so a running instance does not pick them up.
Does the NextChat BASE_URL need /v1 at the end?
No. NextChat appends the version segment and the route itself, which is why the documented default value for BASE_URL is the bare origin https://api.openai.com rather than https://api.openai.com/v1. Write https://api.kunavo.com and nothing more. Adding the suffix yourself produces a doubled path and a 404, which is easy to misread as the endpoint being down.
How do I add a custom model to NextChat's model list?
CUSTOM_MODELS takes a comma-separated list where + adds a model, - hides one and name=displayName renames it. An id NextChat does not know is created on the spot, so +claude-sonnet-5@OpenAI puts that id in the picker. Two details are worth copying exactly: start the list with -all so the built-in OpenAI ids disappear instead of failing when someone picks one, and keep the @OpenAI suffix so the id is routed through BASE_URL rather than to a provider named after the model.
Should NextChat use a server API key or let each user paste their own?
Both are supported and the choice is about who pays. A key in OPENAI_API_KEY is the server's, so every visitor past the CODE password spends from that one balance — sensible for a private instance, expensive for a shared link. Leaving HIDE_USER_API_KEY unset lets a visitor enter their own key in Settings and pay for themselves; setting it to 1 removes that field. Either way the key never reaches the browser unless the user typed it there.