LibreChat takes any OpenAI-compatible API as a custom endpoint in librechat.yaml: a name, a key, a base URL and a model list. One block, and the uncensored builds sit in its endpoint selector next to the rest, billed per token. The same ids work in Open WebUI and in OpenCode.
Where the settings are
LibreChat reads librechat.yaml from the project root, and a custom endpoint is one item under endpoints.custom: a name, a key, a base URL and a model list. The key goes in .env and the YAML references it; LibreChat’s docs call the environment-variable reference the recommended form for apiKey. Docker users mount the file through docker-compose.override.yml and restart.
Steps
- Create a key in the console and put it in
.envnext todocker-compose.yml:
# .envUNCENSOREDLLM_API_KEY=sk-ullm-live-…- Add the endpoint to
librechat.yaml. The ids undermodels.defaultare a starting list; any id on the models page goes in the same way:
# librechat.yamlversion: 1.3.18cache: trueendpoints: custom: - name: 'UncensoredLLM' apiKey: '${UNCENSOREDLLM_API_KEY}' baseURL: 'https://api.uncensoredllm.ai/v1' models: default: - 'glm-5.3-uncensored' - 'deepseek-v4-pro-uncensored' - 'deepseek-v4.1-flash-abliterated' - 'glm-5.3-abliterated' - 'glm-5.3-flash-uncensored' fetch: false titleConvo: true titleModel: 'glm-5.3-flash-uncensored' modelDisplayLabel: 'UncensoredLLM'- Keep the mount in the override file, then restart:
# docker-compose.override.ymlservices: api: volumes: - type: bind source: ./librechat.yaml target: /app/librechat.yamldocker compose down && docker compose up -d reloads the file. The endpoint then appears in the selector under the name you gave it, with the models in models.default.
What each setting does
- name
- UncensoredLLMthe title in the endpoint selector; required and unique
- apiKey
- ${UNCENSOREDLLM_API_KEY}reads the sk-ullm- key from .env; user_provided makes each user paste their own
- baseURL
- https://api.uncensoredllm.ai/v1with the /v1; LibreChat appends /chat/completions itself, so directEndpoint stays unset
- models.default
- the ids abovethe picker, as long as fetch is false; required
- models.fetch
- falsetrue would load every model on the key into the picker
- titleConvo, titleModel
- glm-5.3-flash-uncensoredthe automatic chat title and the small model that writes it
- modelDisplayLabel
- UncensoredLLMthe label beside the AI icon in the chat; "AI" by default
Picking a model
LibreChat sends the whole conversation on every turn in the OpenAI format, and every build on the models page answers it. The cost column is one turn of 2,000 tokens in and 500 out at the catalog prices on 2026-11-09.
| Model | One turn | One title |
|---|---|---|
| GLM-5.3 Uncensored | $0.00099 | $0.0003 |
| DeepSeek V4 Pro Uncensored | $0.0029 | $0.001 |
| DeepSeek V4.1 Flash Abliterated | $0.0025 | $0.00088 |
| GLM-5.3 Abliterated | $0.0065 | $0.0023 |
| GLM-5.3 Flash Uncensored | $0.00039 | $0.00011 |
| GLM-5.3 Uncensored | Uncensored | $0.282 | $0.846 |
| DeepSeek V4 Pro Uncensored | Uncensored | $0.97 | $1.94 |
| DeepSeek V4.1 Flash Abliterated | Abliterated | $0.8488 | $1.6975 |
| GLM-5.3 Abliterated | Abliterated | $2.1825 | $4.365 |
| GLM-5.3 Flash Uncensored | Uncensored | $0.1053 | $0.3685 |
Check it
From the machine that runs LibreChat, list the models the key can call; every id under models.default should be in the answer:
curl https://api.uncensoredllm.ai/v1/models -H "Authorization: Bearer sk-ullm-live-…"Then send one streamed request the way LibreChat does. -i prints the headers: x-uplink-request-id names the request for support.
curl -i https://api.uncensoredllm.ai/v1/chat/completions \ -H "Authorization: Bearer sk-ullm-live-…" \ -H "Content-Type: application/json" \ -d '{"model": "glm-5.3-uncensored", "messages": [{"role": "user", "content": "Reply with the single word ok."}], "stream": true}'If both work and LibreChat does not, the problem is in the YAML or the mount. Check the container log after docker compose up.
Errors and fixes
- The endpoint is missing from the selector: the file is not mounted, or the YAML did not parse. The container log after
docker compose upnames the line. 401 invalid_api_key: the key is wrong or revoked, or the variable name in.envdoes not match the one inapiKey.402 insufficient_balance: the balance does not cover the request. Top up in the console.402 monthly_limit_reachedmeans the key hit the monthly spend limit you set on it.404 model_not_found: an id inmodels.defaultis not on the models page, or a display name was typed where the id belongs.429 rate_limited: the key hit its rate limit; every user of one endpoint shares one key and one limit. The response carriesretry-after.- Every model on the key shows up in the picker:
fetchis on. Set it tofalseand keep the list inmodels.default.
Sources
Field names, the env-var reference, the baseURL convention and the mount are from LibreChat’s own docs, read 2026-11-06: Custom Endpoint Object Structure and Custom Endpoints quick start. Prices are from the live catalog at render.
Questions
In librechat.yaml in the project root, under endpoints.custom as one list item with name, apiKey, baseURL and models. Docker users mount the file through docker-compose.override.yml and restart.
Yes: https://api.uncensoredllm.ai/v1. LibreChat appends /chat/completions to it, the same way its own OpenAI-compatible examples carry a /v1 base. directEndpoint is for a URL that is already the full completions path.
Yes. Set apiKey to user_provided and each user enters a key in the endpoint's settings and pays from their own balance. With an env-var reference, every user of the instance chats on the one key you set.
Every model on the models page: all of them answer /v1/chat/completions in the OpenAI format with the same key, so any id there goes into models.default as it is spelled on the page. See the models page.
LibreChat itself is free software; the tokens are what you pay, at the live prices in the table, from a prepaid balance with no subscription. A small titleModel keeps the title requests cheap.
Every model above is on the uncensored model list with its live price per million tokens. Per-token pricing sets the whole catalog side by side, and the family directory groups the builds by base model.