Back to guides
Setup·July 26, 2026·9 min read

Codex CLI API key — the working custom-provider setup

Codex CLI accepts a custom provider only over the Responses API. Here is the config block that works, what each field does, and what a session costs.

Codex CLI is OpenAI's open-source terminal coding agent, and it runs on either a ChatGPT sign-in or an API key. The API-key route is the one worth understanding: it bills per token with no monthly fee, and it is the only route that lets you point the CLI at a different provider — or a different model family entirely. This guide is the working configuration, the one requirement that trips most gateways up, and what a session actually costs.

The one requirement that matters

Codex CLI is stricter about custom endpoints than most tools. Its model_providers block has a wire_api key, and it accepts exactly one value: responses. That means a custom provider must serve OpenAI's Responses API at POST /v1/responses — not the far more common /v1/chat/completions. Most OpenAI-compatible gateways offer only the latter, which is why so many of them cannot drive Codex CLI at all, whatever base_url you give them.

Kunavo serves both surfaces, so the config below works as written.

The configuration

Codex reads ~/.codex/config.toml. Two top-level keys pick the model and the provider; the provider block describes how to reach it:

~/.codex/config.toml
# ~/.codex/config.toml
model          = "gpt-5-3-codex"
model_provider = "kunavo"

[model_providers.kunavo]
name     = "kunavo"
base_url = "https://api.kunavo.com/v1"
env_key  = "KUNAVO_API_KEY"
wire_api = "responses"

Note what is not in that file: the key itself. env_key names an environment variable, and Codex reads the key from there at launch — so the config file stays safe to commit or share.

shell
# Codex reads the key from the variable named by env_key.
export KUNAVO_API_KEY="sk-kn-..."     # create at kunavo.com/app/keys

# Persist it (pick the file your shell actually loads):
echo 'export KUNAVO_API_KEY="sk-kn-..."' >> ~/.zshrc

codex "explain the structure of this repository"

Create the key at the dashboard after signing up and topping up $5. It is shown once, so store it immediately. If codex was already running in another shell, restart it — it reads the variable at launch, not per request.

Verify before you debug

If something is wrong, find out whether it is the key, the endpoint or the CLI. One request settles it:

verify.sh
# Confirm the key and the endpoint before blaming Codex.
curl https://api.kunavo.com/v1/responses \
  -H "Authorization: Bearer $KUNAVO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-5-3-codex",
    "input": "Say OK and nothing else."
  }'

A JSON response means the key and endpoint are good and any remaining problem is in config.toml. A 401 means the key is wrong or the variable is empty in this shell. A 404 on model means the slug does not match the catalog.

Which model to set

The model value is just a slug on the same endpoint, so switching is a one-word edit — no new key, no new provider block.

TaskModelKunavo input / output (per 1M)
Coding-specialised defaultgpt-5-3-codex$0.70 / $5.60
Hardest refactors and debuggingclaude-opus-5$2.00 / $10.00
Everyday agentic codingclaude-sonnet-4-6$1.20 / $6.00
Quick edits and Q&Aclaude-haiku-4-5$0.40 / $2.00

gpt-5-3-codex is the coding-tuned GPT and the natural default for this CLI, at $0.70 / $5.60 per 1M tokens against OpenAI's list price of $1.75 / $14.00. Full rates for every model are on the pricing page.

Running Claude models in Codex CLI

This surprises people: Codex CLI is protocol-bound, not model-bound. It speaks the Responses wire format, and whatever chat model sits behind that endpoint answers. Point it at claude-opus-5 and it runs end to end — including tool calls, so the agent still reads files, proposes edits and runs commands as normal.

~/.codex/config.toml
# Same provider block, different model — no new key, no new config.
model          = "claude-opus-5"
model_provider = "kunavo"

[model_providers.kunavo]
name     = "kunavo"
base_url = "https://api.kunavo.com/v1"
env_key  = "KUNAVO_API_KEY"
wire_api = "responses"

The gateway translates the Responses request into the Anthropic Messages API and the reply back into the Responses shape. One honest caveat: Codex sends opaque reasoning items that only a Responses-native model can consume, and those are dropped on the way to a non-GPT upstream. The model loses its private scratchpad from the previous turn; the visible transcript it works from is intact. In practice that costs a little continuity on long reasoning chains, and nothing at all on ordinary edit-run-fix loops.

Whether that is a good idea is a separate question from whether it works. If you want Claude specifically, Claude Code is built for it and passes cache_control through untranslated. But if you prefer Codex CLI's sandboxing and want Claude behind it, that combination is available.

What a session costs

Agentic CLIs resend the system prompt, the task history and fresh file context on every step, so tokens accumulate faster than the step count suggests. A typical step is roughly 25,000 input and 1,200 output tokens:

UnitTokens (input / output)gpt-5-3-codexAt OpenAI list
One agentic step25,000 / 1,200$0.024$0.061
A 20-step task~500k / ~24k~$0.48~$1.21
A heavy day (5 such tasks)~$2.42~$6.05

Because output rates differ between model families far more than input rates do, output-heavy work shifts the ranking — put your own numbers through the cost calculator rather than trusting one worked example. Failed requests are not billed.

When the API key route beats a subscription

A ChatGPT plan bundles Codex usage at a flat monthly rate; an API key bills only for what you run. The key route wins when you code in bursts rather than daily, when you want per-key spend limits and usage visibility instead of an opaque allowance, or when you want a model the subscription does not offer. It loses when you are a heavy everyday user — at that volume a flat rate is hard to beat. The routes are not exclusive: Codex profiles let you keep both and switch per task.

Troubleshooting

SymptomCause
404 on every requestProvider does not serve /v1/responses, or base_url already includes the path — it should end at /v1.
401 UnauthorizedThe variable named by env_key is empty in the shell that launched Codex. Restart the shell after exporting it.
Model not foundThe slug does not match the catalog. Slugs use hyphens: gpt-5-3-codex, not gpt-5.3-codex.
wire_api rejectedOnly "responses" is accepted. A config using "chat" will not load.
Insufficient quotaWallet balance is below the request estimate. Top up at billing.

FAQ

Where does Codex CLI store the API key?

It doesn't. env_key names an environment variable and Codex reads the key from the environment at launch, so config.toml contains no secret and stays safe to commit.

Do I need a ChatGPT subscription?

No. A key is a complete alternative to signing in, and the only route that supports a custom provider or a non-GPT model.

Does this work with Codex in the IDE extension?

The extension shares ~/.codex/config.toml with the CLI, so the same provider block applies. Restart the editor after editing it.

Can I keep OpenAI and a gateway side by side?

Yes — define multiple [model_providers.*] blocks and switch with model_provider, or wrap each in a Codex profile and select it per run.

How does this compare to Claude Code?

Claude Code reads ANTHROPIC_BASE_URL and speaks the Messages API, so pointing it at a gateway is three environment variables and no config file. The full comparison — extension surface, sandboxing, cost shape — is in Claude Code vs Codex CLI.