Add APIsRouter as a LibreChat custom endpoint.
Updated 2026-07-16
LibreChat treats custom OpenAI-compatible endpoints as a first-class feature: one endpoints.custom block in librechat.yaml with a baseURL, an apiKey, and models.fetch set to true, and the whole catalog shows up in the model selector under one key.
Quick answer: one block in librechat.yaml.
LibreChat's custom endpoints are configured in librechat.yaml under endpoints.custom, an array where each entry is one provider. The three fields that matter are name (the label in the endpoint selector), apiKey (which interpolates environment variables in the ${VARIABLE} form, so the key lives in .env and never in the YAML), and baseURL. For APIsRouter the baseURL is https://api.apisrouter.com/v1, with the /v1 included, because LibreChat appends route paths like /chat/completions to whatever base you give it. The models block decides what appears in the model dropdown. Set models.fetch to true and LibreChat queries the endpoint's /v1/models listing at load, so every catalog id becomes selectable without maintaining a hand-written list. models.default is still required as an array and serves as the fallback shown before or instead of a fetch. This is documented upstream configuration, not a patch: the custom endpoint object structure in the LibreChat docs defines every key used here.
version: 1.2.1
endpoints:
custom:
- name: "APIsRouter"
apiKey: "${APISROUTER_API_KEY}"
baseURL: "https://api.apisrouter.com/v1"
models:
default: ["claude-sonnet-4-6"]
fetch: trueHow LibreChat routes custom endpoints.
LibreChat (danny-avila on GitHub, roughly 41K stars) is the most widely deployed self-hosted ChatGPT-style interface: multi-user, multi-model, with conversation search, agents, file handling, and per-user keys. Unlike clients that hardcode a provider list, its endpoints.custom array accepts any OpenAI-compatible service, and several well-known providers in the docs are configured through exactly this mechanism. When a user picks a model from a custom endpoint, LibreChat sends a standard /v1/chat/completions request to that endpoint's baseURL with the model field as a plain string. Nothing in the client cares which vendor trained the model; the string is forwarded as-is. When the endpoint behind the baseURL serves several vendors, one librechat.yaml entry puts Claude, GPT, Gemini, DeepSeek, and GLM ids in the same dropdown, and a user switches vendors mid-conversation the same way they would switch between two GPT variants. That collapses the usual multi-provider LibreChat setup. Instead of one custom entry per vendor, each with its own key in .env and its own billing surface, one entry with one key covers the catalog, and the admin sees usage per model in one place instead of reconciling several dashboards.
Full setup: YAML, .env, and the Docker mount.
Create librechat.yaml in the project root and put the key in .env. The ${APISROUTER_API_KEY} reference in the YAML resolves from the environment at startup, so the config file stays committable. The step most first-time setups miss is Docker-specific: the container does not see your librechat.yaml until you mount it. The docs have you create docker-compose.override.yml with a bind mount from ./librechat.yaml to /app/librechat.yaml, then recreate the containers. Editing the YAML afterwards also requires a restart, because the file is read at startup, not watched. A few optional fields are worth setting on a gateway entry. titleConvo enables automatic conversation titles, and titleModel picks the model that writes them; LibreChat's documented default for titleModel is gpt-3.5-turbo, an id a non-OpenAI endpoint may not serve, so set it explicitly to a fast catalog id or to the special value current_model. modelDisplayLabel controls the name shown on assistant messages. And apiKey accepts the special value user_provided if you want each user to paste their own key instead of sharing the server's.
version: 1.2.1
endpoints:
custom:
- name: "APIsRouter"
apiKey: "${APISROUTER_API_KEY}"
baseURL: "https://api.apisrouter.com/v1"
models:
default: ["claude-sonnet-4-6", "gpt-5.5", "deepseek-v4-pro"]
fetch: true
titleConvo: true
titleModel: "claude-haiku-4-5-20251001"
modelDisplayLabel: "APIsRouter"Choosing models for a shared chat workspace.
Because every model bills through the same key, the practical loop for an admin is to watch a week of usage in the console, see which models users actually pick, and prune models.default to match, keeping fetch on so power users can still reach the full list.
- Daily-driver chat wants a strong generalist. claude-sonnet-4-6 and gpt-5.5 carry long conversations, file discussion, and agent runs without per-message model anxiety.
- High-frequency short questions are volume work. claude-haiku-4-5-20251001 and gemini-3.5-flash answer fast and keep a many-user deployment from concentrating spend on throwaway turns.
- Title generation fires on every conversation. Point titleModel at a fast id; paying frontier rates to write six-word titles is the most common silent waste in a LibreChat deployment.
- Multilingual teams should test deepseek-v4-pro and glm-5.2 on their real language mix; a multi-vendor dropdown makes that an in-app comparison rather than a reconfiguration.
- models.fetch means new catalog models appear without touching the YAML, so a model added upstream is selectable the next time the list refreshes.
Pay-as-you-go · transparent per-model pricing
Selected models are priced below official list prices. Exact input, output, cache, and per-request prices are shown for each model.
| Model | Official Price | Our Price |
|---|---|---|
| Claude Sonnet 4.6 | $3.00 / $15.00 per M | $2.40 / $12.00 per M |
| Claude Haiku 4.5 20251001 | $1.00 / $5.00 per M | $0.80 / $4.00 per M |
| GPT-5.5 | $5.00 / $30.00 per M | $4.00 / $24.00 per M |
| Gemini 3.5 Flash | $1.50 / $9.00 per M | $1.20 / $7.20 per M |
| DeepSeek V4 Pro | $0.43 / $0.87 per M | $0.39 / $0.78 per M |
Failure modes specific to LibreChat.
The config silently not loading is the classic, and it is almost always the Docker mount. Without the docker-compose.override.yml bind mount, the container runs with no librechat.yaml at all, the custom endpoint never appears in the selector, and nothing errors. Confirm the file exists inside the container before debugging anything else. An apiKey that arrives literally as ${APISROUTER_API_KEY} means the variable was not present in the environment the server started with; the interpolation happens at startup from .env, so a key added afterwards needs a container restart. The symptom is a 401 from the gateway with a nonsense bearer token. A baseURL without /v1 produces 404s on every request, because LibreChat appends /chat/completions to the base as given. The reverse mistake, pasting a full completions URL as baseURL, belongs to the separate directEndpoint option and should not be combined with a normal entry. An empty model dropdown with fetch off means models.default is missing or empty; it is a required array. With fetch on, an empty dropdown usually means the fetch itself failed, which circles back to the key or the baseURL. And failed conversation titles on an otherwise working endpoint are the titleModel default pointing at an id the gateway does not serve; set it explicitly.
Who routes LibreChat through a gateway.
- Teams self-hosting a shared chat workspace who want Claude, GPT, Gemini, and DeepSeek in one dropdown without maintaining one endpoints.custom entry and one vendor account each.
- Admins running multi-user deployments who need one usage surface. Per-key logs show which models the team actually uses, priced, without merging vendor dashboards.
- Operators giving departments their own keys: same YAML, one key per group, and the usage log becomes the per-team cost report.
- Households and small groups replacing several chat subscriptions with one metered endpoint, paying for tokens used rather than seats.
- Developers without access to a given vendor's billing. Top-up based access with no card requirement removes the per-provider sign-up dependency.
Verify the endpoint and debug the first message.
Prove the gateway half before touching LibreChat: list models with your key, and confirm the ids you put in models.default appear. If that works, every remaining symptom is on the LibreChat side of the wire. Then start the stack and open the endpoint selector. The APIsRouter entry appearing at all proves the YAML loaded; the model list populating proves the fetch and the key; the first reply proves the chat path. Work through those three in order rather than all at once, because each one has a distinct failure set, the mount, the env var, and the baseURL respectively. Once messages flow, the APIsRouter console shows per-request model, token counts, and spend. A shared LibreChat instance is exactly the kind of deployment where usage quietly concentrates on two or three models, and the usage log is how you find out which ones before the invoice does.
curl -s https://api.apisrouter.com/v1/models \
-H "Authorization: Bearer $APISROUTER_API_KEY" | head -50FAQ
Where do I configure a custom OpenAI-compatible endpoint in LibreChat?
In librechat.yaml under endpoints.custom, an array of provider entries with name, apiKey, baseURL, and a models block. On Docker installs the file must be bind-mounted into the container via docker-compose.override.yml or it is silently ignored.
Should the baseURL include /v1?
Yes for APIsRouter: https://api.apisrouter.com/v1. LibreChat appends route paths like /chat/completions to the base as given, so a missing /v1 produces 404s on every request.
Can one LibreChat endpoint serve Claude, GPT, and DeepSeek models together?
Yes. LibreChat forwards the selected model id as a plain string to the endpoint's baseURL. When the endpoint serves multiple vendors, one endpoints.custom entry puts all of their ids in the same dropdown, and models.fetch keeps that list current automatically.
Why is my custom endpoint missing from the selector?
The YAML did not load. On Docker the usual cause is a missing bind mount for librechat.yaml; the container runs without the file and nothing errors. Confirm the file exists inside the container, then restart, since the config is read at startup.
Why do conversation titles fail when chat works?
titleConvo uses titleModel, whose documented default is gpt-3.5-turbo, an id your endpoint may not serve. Set titleModel explicitly to a fast catalog id such as claude-haiku-4-5-20251001, or to the special value current_model.
Can each user bring their own key instead of sharing the server key?
Yes. Set apiKey to the special value user_provided and LibreChat prompts each user for a key, stored per user. That fits gateway keys well, since one key per user turns the usage log into a per-person cost view.