Codex CLI & app
Point OpenAI Codex CLI, the Codex app and the IDE extension at RouteMux with one custom model provider in ~/.codex/config.toml.
Codex CLI reaches a third-party endpoint through a custom model provider in its config file. It speaks the OpenAI Responses protocol and nothing else.
The Codex desktop app and the IDE extension run the same Codex engine and read the same
~/.codex/config.toml, so one setup covers all three. The app has a few behaviours of its
own — see Codex app below.
Configure
Add to ~/.codex/config.toml:
model_provider = "routemux"
model = "openai/gpt-5.5"
[model_providers.routemux]
name = "RouteMux"
base_url = "https://api.routemux.com/v1"
env_key = "ROUTEMUX_API_KEY"
wire_api = "responses"export ROUTEMUX_API_KEY="sk-..." # your RouteMux keyProvider keys only take effect in the user-level file
Codex ignores model_provider and model_providers in a project-scoped
.codex/config.toml. They have to live in ~/.codex/config.toml (or a profile file under
$CODEX_HOME). A provider block in a project directory is silently skipped, which looks
exactly like a wrong base URL.
wire_api has exactly one value
responses is the only supported value, and it is the default when you omit the field —
Codex has no Chat Completions mode. RouteMux serves /v1/responses, so this works, but it
also means Codex never touches /v1/chat/completions.
Pick your own provider id: openai, ollama and lmstudio are reserved and cannot be
overridden.
Base URL shape
base_url includes /v1. Codex appends only the operation path, so the request lands
on /v1/responses. Adding /v1 twice is tolerated — RouteMux routes /v1/v1/responses to
the same place — but the other direction (omitting /v1) is not.
Pick a model
GET /v1/models returns exactly the models your key can call. Use those slugs verbatim;
copy-paste is the main source of failure here, and a trailing space in a model id produces a
MODEL_NOT_FOUND whose suggestion looks identical to what you typed.
Codex app
The desktop app needs no separate setup — it uses the provider above. Three things behave differently from a terminal:
- Export the key in your shell profile. An
exporttyped into one terminal only reaches programs started from that terminal. On macOS the app loads the variables exported in your shell profile (for example~/.zshrc) when it launches, so put theexport ROUTEMUX_API_KEY=...line there. - Restart after changes. Environment variables are captured when the app launches. After
editing your shell profile or
~/.codex/config.toml, quit the app completely (Cmd+Q on macOS) and reopen it. - The model menu is Codex's built-in OpenAI list. It shows bare names such as
gpt-5.5; RouteMux accepts those as-is, the same asopenai/gpt-5.5. For a model that is not in the menu, setmodelin~/.codex/config.toml— new chats start on it.
Verify
Test the protocol Codex actually uses, not Chat Completions:
curl https://api.routemux.com/v1/responses \
-H "Authorization: Bearer $ROUTEMUX_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"openai/gpt-5.5","input":"ping"}'If this returns 200 and codex still fails, the problem is in the config file, not the key.
Why a hand-written curl costs more than you expect
Codex CLI always sends its own instructions. A bare curl that omits the field gets the
upstream's default Codex system prompt instead — measured at 21,334 characters, which billed
4,393 input tokens for an 11-token prompt. That is the test call being expensive, not the
integration. Send an instructions field if you want a cheap probe.
Timeouts on long runs
Codex's own stream_idle_timeout_ms defaults to 300000 ms. RouteMux's idle watchdog for
text is 180 s, so ours fires first: if the upstream sends no new chunk for 180 s the
request is aborted and recorded as a timeout. Streaming has no total time limit on our side —
a multi-minute agent turn is fine as long as tokens keep arriving.
Long sessions with images
A long Codex session accumulates screenshots in its history, and the whole history is resent on every turn. Two limits apply:
- Request bodies above 64 MiB are rejected outright.
- The budget for the upstream's first response header scales with body size, because prefill time grows with it. A 27 MB body gets a much longer grace period than a 1 MB one.
If a long session starts timing out while short prompts succeed, clear the conversation rather than retrying — the body is the variable.
Troubleshooting
| Symptom | Cause |
|---|---|
Error loading config.toml: wire_api = "chat" is no longer supported | You followed an older guide. Set wire_api = "responses". This is a config-load error, so every codex command fails until it is fixed — including ones unrelated to this provider. |
codex behaves as if unconfigured | Provider block is in a project-level .codex/config.toml, which ignores these keys. Move it to ~/.codex/config.toml. |
codex in a terminal works, the Codex app gets auth errors | The key was exported only in that terminal session. Export it in your shell profile and restart the app. |
| 404 on every request | base_url is missing /v1, or points at a path instead of the API root. |
400 AUTH_AMBIGUOUS_API_KEY | Two different key values are being sent in two header fields. Clear whichever one you are not using. |
422 BILLING_INSUFFICIENT_CREDITS | Wallet lacks credit. Failed requests are not billed. |
| Model rejected | Not enabled for your key — GET /v1/models is authoritative. |
| A long session times out at a fixed duration, short prompts work | Body size, not the key. See above. |
Generating images
Codex CLI's built-in $imagegen rides your ChatGPT subscription session, not the
base_url configured above — so once Codex points at RouteMux (or any third-party
gateway), that built-in tool goes dark. There is nothing to fix in the config.
Install the routemux-images skill instead: it
calls POST /v1/images/generations over plain HTTP, which works regardless of what
the built-in tool is doing.
npx skills add https://routemux.com -g -a codexNo Node.js? Use the install script instead:
curl -fsSL https://routemux.com/.well-known/agent-skills/install.sh | sh -s -- --agent codexBoth install into ~/.agents/skills, where Codex looks for user skills. Restart Codex,
then call $routemux-images — or just ask in plain words, for example "draw a minimalist
coffee shop logo and save it to ./logo.png". The skills reuse the key of the RouteMux
provider above — the variable its env_key names, or its experimental_bearer_token —
so there is nothing else to set.