# Codex CLI and the Responses API: why most relays 404

> Markdown mirror of https://router.one/codex-responses-api for AI assistants and crawlers. Router One is an OpenAI-compatible LLM API gateway.
> Last updated: 2026-08-25

OpenAI's Codex CLI doesn't call the classic Chat Completions API — it speaks the newer Responses API wire format. Most OpenAI-compatible relays only implement Chat Completions, so Codex pointed at them fails with 404s or malformed-request errors even though the same key works in curl. Router One implements the Responses wire format natively (wire_api = "responses"), so Codex works with a two-minute config change.

## The one-line root cause

Codex sends requests to /responses-style routes with a request schema that Chat Completions servers don't recognize. A relay that only speaks Chat Completions answers with 404 (unknown path) or 400 (unknown fields). No amount of key or model fiddling fixes a wire-format mismatch — the gateway itself has to support it.

## The working configuration

Point Codex at Router One in ~/.codex/config.toml and export your key in the same shell that runs codex:

`config.toml`

```bash
# ~/.codex/config.toml
model_provider = "router"

[model_providers.router]
name = "router"
base_url = "https://api.router.one/v1"
env_key = "ROUTER_ONE_API_KEY"
wire_api = "responses"

# in your shell:
# export ROUTER_ONE_API_KEY=sk-your-router-one-key
```

## Error checklist

If Codex still fails after the config change:

| Symptom | Cause | Fix |
| --- | --- | --- |
| 404 on every request | base_url points at a relay without Responses API support, or has a typo | Set base_url to https://api.router.one/v1 exactly and keep wire_api = "responses". |
| 401 unauthorized | ROUTER_ONE_API_KEY isn't visible in the shell running codex | Export the key in the same session (or your shell profile), then restart the terminal and re-run codex. |
| Model not found | Model ID doesn't match the catalog | Copy the exact ID from the /models page — IDs are case-sensitive. |
| 402 insufficient balance | Wallet or key spend cap exhausted | Top up or raise the key's maxSpend in Dashboard → API Keys. |
| Config seems ignored | Codex reads a different config file than the one you edited | Confirm the file lives at ~/.codex/config.toml (Windows: %USERPROFILE%\.codex\config.toml). |
| 400 mentioning background or image_generation | Codex asked for a background response or the image_generation tool — the two Responses features the gateway does not run | Disable background mode; generate images through POST /v1/images/generations instead. Hosted tools and previous_response_id keep working on natively served Responses models. |
| 400 saying the model must be called via /v1/messages | A Claude-family model ID was sent to the Responses endpoint; Claude is served on the Anthropic-compatible endpoint and on /v1/chat/completions, never on /v1/responses | Switch Codex to a model whose detail page lists POST /v1/responses (the GPT family or DeepSeek V4). To work with Claude, use Claude Code instead. |
| Model not found for codex-auto-review | Codex CLI sends the model ID codex-auto-review for its review line (/review and automatic review) unless review_model in config.toml overrides it; relays that only know their own model list, or only speak Chat Completions, reject the ID | Nothing to change on Router One — codex-auto-review is in the catalog and is served on /v1/responses and /v1/chat/completions; pricing is on /models/codex-auto-review. To review with a different model, set review_model in ~/.codex/config.toml. |

## What the Responses endpoint accepts — and the two things it rejects

Router One implements the Responses wire format itself, for the models whose detail page lists POST /v1/responses (the GPT family and DeepSeek V4). The table lists current behavior by request feature; anything accepted is forwarded as sent and billed at the model's standard rate.

| Request feature | Status | Notes |
| --- | --- | --- |
| Function tools (Codex's default tool shape) | Accepted | Structured tool calls come back as first-class Responses output items. |
| Custom tools (Codex's freeform apply_patch and similar) | Accepted on natively served Responses models | Use a model whose page lists POST /v1/responses; other models get 400 invalid_request. |
| previous_response_id / conversation / prompt (server-side context references) | Accepted on natively served Responses models | Same model rule as custom tools; the reference is resolved on the native path. |
| Hosted tools: file_search, code_interpreter, computer_use, mcp, web_search | Accepted on natively served Responses models | Forwarded as sent and billed at the model's standard rate — Router One runs none of them itself. |
| input_file parts with file_id or file_url | Accepted on natively served Responses models | Same model rule; the file reference travels with the request. |
| service_tier (any value) | Accepted | Forwarded as sent; billed at the model's standard rate regardless of tier. |
| stream / instructions / temperature / max_output_tokens | Accepted | Forwarded as sent; see the Responses API reference. |
| image_generation tool and image_generation_call input items | Rejected — 400 invalid_request | Image generation is not offered through the Responses endpoint; use POST /v1/images/generations (see /image-generation-api). |
| background: true | Rejected — 400 invalid_request | No background execution and no GET /v1/responses/{id} to fetch a result later; each request completes within its HTTP connection. |

## Verify from the trace

Once requests reach the gateway, every Codex call shows up in Dashboard → Logs with model, tokens, cost, and status. If the log stays empty while Codex errors, the failure is still local — config path or env var. If entries appear with 4xx, the trace names the exact limit.

## FAQ

### Why does my key work in curl but not in Codex?

curl exercises the Chat Completions surface; Codex uses the Responses API wire format. A relay can pass the curl test and still 404 for Codex. The gateway must implement the Responses wire format — Router One does.

### What does wire_api = "responses" actually do?

It tells Codex which protocol shape to speak with the provider block. With "responses", Codex sends Responses-API-formatted requests; the endpoint on the other side has to understand them natively.

### Does the base URL need /v1?

Yes — for Codex the OpenAI-compatible base URL is https://api.router.one/v1 including /v1. That's the opposite of Claude Code, whose Anthropic-compatible base URL has no /v1 suffix.

### Which models can Codex use through the gateway?

The models served natively over the Responses wire format: the GPT family and DeepSeek V4 (deepseek-v4-pro, deepseek-v4-flash). Use the exact model ID from /models — each model page lists whether it exposes POST /v1/responses. Claude models are not on this endpoint: sending one gets a 400 back before any model is called.

### I pointed Codex at a Claude model and got a 400. What now?

The gateway refuses that request before any model runs, and the message spells out where the model lives: model 'anthropic/claude-opus-5' must be called via /v1/messages or /v1/chat/completions. Claude is served on the Anthropic-compatible endpoint (the path Claude Code uses) and on /v1/chat/completions, not on /v1/responses. Point Codex at a GPT-family model or DeepSeek V4, and use Claude Code when you want to work with Claude — see /claude-code-china.

### What is the codex-auto-review model Codex keeps requesting?

It is the model ID Codex CLI sends for its review line (/review and automatic review) unless review_model in ~/.codex/config.toml points elsewhere. Relays that validate model names against their own list, or only implement Chat Completions, answer model not found. Router One lists codex-auto-review in the catalog, so the request is routed and billed like any other model — it works on /v1/responses and /v1/chat/completions, and the current price is on /models/codex-auto-review.

### Do previous_response_id, hosted tools and service_tier work through the gateway?

Yes, on models served natively over the Responses wire format — the model page's endpoint list shows which. Requests are forwarded as sent and billed at the model's standard rate; only background: true and the image_generation tool are rejected with 400.

### Why does Codex get 400 when it tries image generation?

Image generation is not offered through the Responses endpoint, so an image_generation tool or image_generation_call item is refused with 400 invalid_request before any model is called. Generate images with POST /v1/images/generations instead — see /image-generation-api.

### Can I run a response in the background?

No. background must be omitted or false; background: true returns 400 invalid_request. The gateway does not run detached responses and has no GET /v1/responses/{id}, so a result cannot be fetched after the connection closes.

### Does this work from Mainland China?

Yes. The gateway is reachable from Mainland China without a VPN; the config.toml above is identical everywhere.

## See also

- Error codes reference: https://router.one/llm-api-error-codes#errors-in-codex-cli
- Claude Code 403 checklist: https://router.one/claude-code-403
- Claude Code in China: https://router.one/claude-code-china
- API authenticity check: https://router.one/llm-api-authenticity
- Codex CLI in China: https://router.one/codex-china
- insufficient_quota fix: https://router.one/openai-insufficient-quota
- Responses API reference (POST /v1/responses): https://router.one/docs/chat/createResponse
- CLI setup guide: https://router.one/docs/guides/cli-setup
- Image generation API: https://router.one/image-generation-api
- Canonical page: https://router.one/codex-responses-api
- Models and per-model token rates: https://router.one/models (markdown: https://router.one/models.md)
- Pricing: https://router.one/pricing
- API docs (markdown): https://router.one/docs.md
- Company facts: https://router.one/facts/company.md
