GPT-6 Sol & Claude Opus 5.5 are liveGPT-6 Sol at half the price of 5.6 Sol

Codex Image Generation With a Custom Provider: imagegen Setup

Two lines in config.toml turn on Codex's built-in image tool on a relay. Here is the setup we ran on October 29, 2026, where the images are saved, and what the relay must send back.

Kiki, OmniaKey COO8 min read
On this page

Codex 0.165.0 hides its built-in image tool on a relay until the provider block adds an http_headers entry named x-openai-actor-authorization, with any non-empty value, and keeps requires_openai_auth = false, the default. Then Codex sends image requests to the relay's /images/generations with the model gpt-image-2 and saves the PNG under ~/.codex/generated_images/. On October 29, 2026 that gave a 1024×1024 PNG in 29.0 seconds; the same config without the header gave no image tool.

We ran these tests with Codex CLI 0.165.0 on macOS, using OmniaKey, our own API gateway, as the custom provider.

Why imagegen disappears on a custom provider

Codex 0.165.0 decides whether the model gets an image tool from your provider block and the sign-in it has stored, in one function: image_generation_available.

  • requires_openai_auth = false with no actor header: no image tool. In our run with that config, Codex replied: "I don’t have a built-in image generation tool available in this session."
  • requires_openai_auth = false plus the x-openai-actor-authorization header: the tool appears. Our three runs with it (a new image, an edit and a transparent sticker) all called it.
  • requires_openai_auth = true with an API key sign-in: no image tool. Per Codex 0.165.0's code, the check wants a ChatGPT sign-in, and an API key sign-in does not count.

Two smaller conditions sit behind that gate, both in Codex 0.165.0's code: a stored free ChatGPT plan hides the tool even on a custom provider, and the chat model has to accept images, which Codex assumes for model names its own list does not know.

When the tool is missing, Codex either says it has no built-in image tool, as in our run without the header, or the imagegen skill offers its CLI fallback, which needs OPENAI_API_KEY.

The config.toml that turns it on

Open ~/.codex/config.toml. In the provider block for your relay, add the http_headers line and make sure requires_openai_auth is false, its default.

toml
model = "gpt-6.1-sol"            # a chat model your relay serves
model_provider = "relay"

[model_providers.relay]
name = "My relay"
base_url = "https://api.omniakey.com/v1"
env_key = "RELAY_API_KEY"
wire_api = "responses"
requires_openai_auth = false
http_headers = { "x-openai-actor-authorization" = "local-relay" }

[features]
image_generation = true          # already on by default in Codex 0.165.0

model and model_provider are top-level keys, so they must sit above the first [section] line; TOML reads every line after a [section] header as part of that section.

  • requires_openai_auth = false keeps Codex on the key from your environment, the variable named in env_key. OpenAI's auth page (checked October 29, 2026) says: "When requires_openai_auth = true, Codex ignores env_key."
  • http_headers holds the actor header. OpenAI's config reference calls it "Static HTTP headers added to provider requests", and Codex only checks that the value is not empty (the check in Codex's source), so "local-relay" is a placeholder, not a password.
  • [features] image_generation = true is optional in 0.165.0, where the feature is stable and on by default (codex features list prints image_generation stable true). Our runs left it out.
  • wire_api = "responses" is the only value OpenAI's config reference supports.

Set the key and start Codex:

bash
export RELAY_API_KEY="your-relay-key"
codex

If Codex was already running, quit it and open a new session so it reads the new config.

Run one image and find the file

Our October 29, 2026 runs went through a custom provider. Run 2, the check without the header, made no image. The other three each saved one 1024×1024 PNG. The times are the image call, not the whole turn.

RunWhat we askedImage call
1A new app icon29.0 s
3Edit run 1's image37.6 s
4A transparent sticker19.8 s

Run 1 was a single prompt:

Create an app icon for a note-taking app called Inkwell: a fountain pen nib over a deep blue gradient, flat vector style, no text. Generate it with your image tool, then tell me where the file was saved.

Codex opened the imagegen skill by itself, without $imagegen in the prompt, then called the tool. The call took 29.0 seconds and the turn ended with one 1024×1024 PNG.

The file lands at ~/.codex/generated_images/<session id>/<call id>.png; ~/.codex is the default CODEX_HOME. Codex printed the path because the prompt asked. If the image belongs in your project, name the destination and the skill tells Codex to move or copy the file there.

Edit an existing image

Run 1's PNG went into the work folder as inkwell.png, and we asked:

Edit the image ./inkwell.png: change the background to a warm orange gradient and keep the pen nib as it is. Use your built-in image tool, then tell me where the edited file was saved.

Codex passed the file in referenced_image_paths, so the request went to /images/edits. The call took 37.6 seconds and the original inkwell.png stayed as it was. OpenAI's image generation page (checked October 29, 2026) says: "When editing an existing image, say exactly what should change and what must stay the same." The GPT-Image 2 prompt guide covers the rest.

Ivory fountain pen nib on a deep blue gradient, generated by Codex's built-in image tool
New image
The same pen nib after one edit, now on a warm orange gradient
After one edit
Both images came from Codex CLI 0.165.0's built-in image tool through a custom provider on October 29, 2026. The edit asked only for a new background; the nib kept its shape, size and position.

Transparent background

Run 4 asked for a sticker:

Create a PNG sticker of a single fountain pen nib on a fully transparent background (no backdrop at all), flat vector style, no text. Generate it with your built-in image tool, then tell me where the file was saved.

Codex set transparent_background: true, the call took 19.8 seconds, and 85.0% of the pixels in the saved PNG are fully transparent. OpenAI's Images API reference lists transparent backgrounds for gpt-image-2 as "in preview": it worked in our run, but it is still a preview feature.

Golden fountain pen nib sticker on a checkerboard that shows its transparent background
Run 4 on October 29, 2026: a PNG with a transparent background, shown on a checkerboard so the transparent area is visible. 85.0% of its pixels are fully transparent.

What your relay must return (gpt-image-2, b64_json)

Codex sends POST <base_url>/images/generations for a new image and POST <base_url>/images/edits for an edit, both as JSON with the model gpt-image-2, the id of GPT-Image 2, which your relay has to serve. Quality and size are "auto", background is "opaque" or "transparent", and the request leaves out both response_format and n. Both go to the same base URL, with the same key, as your chat requests. An edit carries its source image inside the JSON as a data URL rather than a file upload.

Codex reads a JSON reply with created and a data list whose first item holds b64_json; other fields are ignored, as images.rs shows. A parse failure starts with "failed to decode image generation response:".

You can check a relay without Codex. Save this as relay-check.sh:

bash
curl -s https://api.omniakey.com/v1/images/generations \
  -H "Authorization: Bearer $RELAY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "gpt-image-2", "prompt": "a red apple on a white table", "background": "opaque", "quality": "auto", "size": "auto"}' \
  | python3 -c 'import json,sys; r=json.load(sys.stdin); print(r.get("error") or sorted(r["data"][0]))'

Point the base URL at your relay and export your key as RELAY_API_KEY. On October 29, 2026 the check against our gateway returned HTTP 200 after 25.0 seconds and printed:

text
['asset_id', 'b64_json', 'expires_at', 'revised_prompt', 'url']

If b64_json is missing from that list, Codex fails on the same reply. If the relay returns an error, the check prints the error instead.

Some relays break this because they store the image as a file. The same Images API reference (checked October 29, 2026) says response_format is a "Legacy response format parameter for retired image models. Unsupported for GPT image models, which always return base64-encoded images", and b64_json is "Returned by default for GPT image models". A relay that passes OpenAI's reply through unchanged works; one that sends back only a link breaks Codex.

OmniaKey's gateway had that problem until a fix on October 29, 2026. The fix note says Codex failed with "missing field b64_json", and the gateway now keeps b64_json unless the caller asks for a URL.

If your relay fails the check, OmniaKey serves gpt-image-2 and chat models such as gpt-6.1-sol with one key, and its image replies include b64_json, as the check shows. Set base_url = "https://api.omniakey.com/v1" in that provider block and put your OmniaKey key in the variable that env_key names; the Codex CLI guide covers the rest of the file, and current rates are on the pricing page.

Errors and fixes

Codex says it has no image tool

One of the conditions in the first section is not met. Add the http_headers line, keep requires_openai_auth = false with your env_key, and start a new session. Still missing? Run codex login status; with a free ChatGPT plan, codex logout removes the stored sign-in and the key from env_key is enough.

Codex asks for OPENAI_API_KEY

The built-in tool is unavailable, so the imagegen skill offers its CLI fallback, scripts/image_gen.py, which needs OPENAI_API_KEY. Fix the built-in tool with the config above instead; in built-in mode the key comes from env_key.

failed to decode image generation response: missing field b64_json

The relay replied without b64_json, usually with a link to a stored file. Run the check from the relay section against it and send the result to the operator; Codex wants the base64 string in the first item of data.

The image request fails with model_not_found

Your key has no gpt-image-2 on this relay, and Codex always sends that id with no setting to change it. Our gateway answered an image model it does not serve with HTTP 503 and the code model_not_found. Use a key and a relay that list gpt-image-2.

Reconnecting... 1/5 (stream disconnected before completion)

The chat request dropped and Codex retried it; the counter shows the attempt out of five. It appeared once in run 1 ("Concurrency limit exceeded for account, please retry later") and once in run 3 (a transport error), and both runs finished after the retry. If it keeps returning, check the relay's limits; the Codex compatibility kit covers chat trouble.

FAQ

Do I need OPENAI_API_KEY for imagegen?

No. In built-in mode the key comes from the variable named in env_key; only the skill's CLI fallback reads OPENAI_API_KEY.

Can I choose another image model, size or quality?

Not in Codex 0.165.0. The tool sends gpt-image-2 with quality and size "auto", config.toml has no key for any of them, and every image in our runs came back 1024×1024. For a different size or model, call your relay's image endpoint directly.

Do I have to type $imagegen?

No. In our runs Codex opened the imagegen skill on its own. OpenAI's docs say $imagegen in the prompt invokes the skill explicitly, which helps when Codex does not pick it up.

Does this work in the Codex desktop app?

We did not test the desktop app, only the CLI. The community fix repository says a running Codex Desktop does not pick up new environment variables: its macOS script installs a LaunchAgent, and you quit Codex completely and open a new task afterwards.

Sources checked

Models in this article

Codeximage generationgpt-image-2custom providerconfig.toml

Related articles

Recent posts