# Use Codex with the LLM Gateway

OpenAI Codex (CLI and Desktop) talks to models over the **OpenAI Responses API** (`POST /v1/responses`), not Chat Completions. The Barndoor LLM Gateway speaks that wire format natively — configure Codex with a custom provider whose `base_url` is your gateway endpoint and whose `wire_api` is `responses`.

## Prerequisites

* Codex CLI installed, and/or the **Codex desktop app**.
* A Barndoor LLM Gateway endpoint and a `bd-…` API key from **Settings → My Models**.
* At least one **model route** (or enabled model) your key is allowed to call. Use the exact name shown under **Available Models**.

## Why `/v1` matters

Codex appends `/responses` to the provider `base_url`. The gateway's Responses endpoint is `/api/llm-gateway/v1/responses`.

| `base_url` you set                           | Codex actually calls         | Result                                                        |
| -------------------------------------------- | ---------------------------- | ------------------------------------------------------------- |
| `https://app.barndoor.ai/api/llm-gateway/v1` | `…/llm-gateway/v1/responses` | Correct                                                       |
| `https://app.barndoor.ai/api/llm-gateway`    | `…/llm-gateway/responses`    | Wrong — often a `401` with `invalid JWT header: InvalidToken` |

Always keep the trailing `/v1` that **Settings → My Models** shows for OpenAI-compatible clients. (This is the opposite of Claude Code, which must *omit* `/v1` because it appends `/v1/messages` itself.)

## Configure Codex CLI

### 1. Add a Barndoor provider

Edit `~/.codex/config.toml` (create the file if it does not exist):
```toml theme={null}
model_provider = "barndoor"
model = "gpt-4o-mini"   # replace with a route or model from Settings → My Models

[model_providers.barndoor]
name = "Barndoor"
base_url = "https://app.barndoor.ai/api/llm-gateway/v1"
wire_api = "responses"
env_key = "BARNDOOR_API_KEY"
```
* `wire_api = "responses"` selects the Responses wire format Codex requires.
* `env_key` is only the **name** of the environment variable Codex should read for the API key — it is not the secret itself.
* `model` must match a name your key can call (a bare route alias like `gpt-4o-mini`, or a provider-prefixed form if that is how the model is listed).

### 2. Export the gateway key

```bash theme={null}
export BARNDOOR_API_KEY="bd-…"
```
`env_key` points Codex at this variable; the `export` supplies the value. Keeping the secret in the environment (not in `config.toml`) avoids committing it to git.

### 3. Run Codex

```bash theme={null}
codex
```
Traffic goes to Barndoor on `POST /v1/responses`. Usage and governance follow the same rules as any other gateway client.

## Configure Codex Desktop

Codex Desktop uses the same provider configuration as the CLI. Custom providers are selected by `model_provider` / `model` in config — the in-app model picker may not list custom gateway models the way it lists built-in ones.

1. Put the same `model_provider`, `model`, and `[model_providers.barndoor]` block in `~/.codex/config.toml` (or in `$CODEX_HOME/config.toml` if you set `CODEX_HOME`).
2. Make `BARNDOOR_API_KEY` available to the Desktop process. Dock / Spotlight launches on macOS typically do **not** inherit exports from `.zshrc` or `.zprofile`. Prefer one of:
   * Start Desktop from a terminal after exporting the key (for example `export BARNDOOR_API_KEY="bd-…" && open -a "Codex"` — use the exact app name on your machine).
   * A small wrapper script that exports the key, then launches the app.
3. Fully quit and relaunch Desktop so it reloads `config.toml`. Routing follows the `model_provider` and `model` you set; you should not need to pick “Barndoor” from a provider menu.

## Smoke-test without Codex

Confirm the gateway accepts Responses traffic with your key before debugging Codex itself:
```bash theme={null}
curl https://app.barndoor.ai/api/llm-gateway/v1/responses \
  -H "Authorization: Bearer bd-…" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-4o-mini",
    "input": "Reply with the single word pong."
  }'
```
A successful JSON response means the endpoint, key, and model name are fine — remaining issues are almost always Codex `base_url` / `wire_api` / env wiring.

## Troubleshooting

| Symptom                                    | Likely cause                                 | Fix                                                                                                                       |
| ------------------------------------------ | -------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| `401` / `invalid JWT header: InvalidToken` | `base_url` missing `/v1`                     | Use `…/api/llm-gateway/v1`                                                                                                |
| `401` / invalid API key                    | Wrong or unset `BARNDOOR_API_KEY`            | Confirm `env_key` matches the variable you exported; recreate the key under **Settings → My Models** if needed            |
| Model not found / `404`                    | `model` is not an enabled route for your key | Copy an exact name from **Available Models**                                                                              |
| Desktop ignores the key                    | GUI process lacks the env var                | Launch Desktop from a shell/wrapper that exports `BARNDOOR_API_KEY` (Dock launches usually will not see `.zshrc` exports) |
| Works in `curl` but not in Codex           | Wrong `wire_api` or provider block           | Set `wire_api = "responses"` under `[model_providers.barndoor]`                                                           |
