Image Generation in Codex

Trigger image generation from inside the Codex CLI: a custom slash command /imagegen calls gpt-image-2 through Codex's built-in bash tool. Submission is asynchronous (submit task → poll for result), no extra software needed.

Prerequisites

  1. Codex CLI installed and ~/.codex/config.toml configured per the Codex Quick Start (base_url = "https://relay.upthos.com").
  2. Your API Key belongs to a Codex / OpenAI tier group (Codex Lite / Codex Pro / Codex Max). Keys in Claude / Gemini groups cannot call the image API.
  3. sandbox_mode = "danger-full-access" in ~/.codex/config.toml — the Quick Start template no longer ships this line, so add it yourself; otherwise Codex cannot execute curl.

1. Expose your API key to Codex's bash tool

The key in ~/.codex/auth.json is only injected into Codex's connection to the upstream — it is not available to bash subprocesses, so curl won't see it. Pick one:

Option A: shell environment variable (recommended)

# macOS / Linux —— add to ~/.zshrc or ~/.bashrc
echo 'export OPENAI_API_KEY="sk-relay-YOUR_KEY"' >> ~/.zshrc
source ~/.zshrc
# Windows PowerShell
[Environment]::SetEnvironmentVariable("OPENAI_API_KEY", "sk-relay-YOUR_KEY", "User")

Option B: inject at launch

OPENAI_API_KEY=$(jq -r .OPENAI_API_KEY ~/.codex/auth.json) codex

Verify: in Codex, type run echo $OPENAI_API_KEY. If you see the key prefix, you're good.


2. Create the slash command

In ~/.codex/prompts/ (create with mkdir -p ~/.codex/prompts if missing), create imagegen.md:

---
description: Generate an image via Upthos Relay (gpt-image-2)
---

The user wants to generate an image. Description: {{args}}

Use the bash tool to execute the following flow (**parse responses by exact field path — do not invent the structure**):

### Step 1: submit the task

curl -sS -X POST https://relay.upthos.com/v1/images/tasks \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-image-2",
    "prompt": "<insert the user's description, escape double quotes>",
    "size": "1:1",
    "resolution": "1k"
  }'

Response: `{"code":0,"data":[{"status":"submitted","task_id":"task_xxx"}]}`
Extract task ID from `data[0].task_id`.

### Step 2: poll for result

Call every 3 seconds (max 60 attempts, ~3 minutes):

curl -sS https://relay.upthos.com/v1/images/tasks/<task_id> \
  -H "Authorization: Bearer $OPENAI_API_KEY"

Branch on `data.status`:
- `processing` → wait and retry
- `completed` → extract image URL from `data.result.images[0].url[0]` and present it
- `failed` → report `data.error.message` to the user, stop

### Step 3: output format

Render with markdown image syntax:

![generated](IMAGE_URL)

Followed by one line: resolution, elapsed time, expiry (convert unix timestamp to human-readable).

### Parameters (use defaults if user did not specify)

- `size`: `1:1` / `16:9` / `9:16` / `3:2` / `2:3` / `auto`
- `resolution`: `1k` (default) / `2k` / `4k`
- Multiple images: `n` supports 1..4 — a single task can generate multiple images (or you can submit multiple tasks in parallel)

### Error handling

- HTTP 402 / `INSUFFICIENT_BALANCE` → tell the user to top up at https://relay.upthos.com/dashboard
- HTTP 403 → current key's group doesn't support the image API; switch to a Codex-tier key
- HTTP 429 → rate limit hit, suggest retry later

{{args}} is replaced with whatever the user types after /imagegen .


3. Try it

cd into any project, run codex, then enter:

/imagegen a cyberpunk cat with neon backlight

With parameters:

/imagegen a cat, 2k, 16:9

Codex will submit the task, poll until completion, and render the result inline as markdown. Image URLs have a finite lifetime — download or re-host before they expire.


4. Pricing

gpt-image-2 is billed per image and is independent of your Codex subscription tier (subscription discounts apply only to text/code models, not images). Charged from balance — even subscription users pay from balance, image gen does not consume subscription quota.

Resolution Price per image Best for
1k ¥0.041 thumbnails, fast iteration
2k ¥0.082 mainstream illustrations, social media
4k ¥0.123 high-resolution, print assets

low / medium / high quality cost the same — switch freely.

Swap model for gpt-image-2.5-flare or gpt-image-2.5-sunburst to use GPT Image 2.5 — prices are identical to the table above. Omitting model still defaults to gpt-image-2.


5. Advanced: image-to-image (reference images)

Pass an image_urls array to the submit request with 1–N publicly reachable image URLs:

{
  "model": "gpt-image-2",
  "prompt": "convert this image to watercolor style",
  "size": "1:1",
  "resolution": "1k",
  "image_urls": ["https://example.com/source.png"]
}

If you need to upload a local file first, call POST /v1/images/uploads (multipart, single file) to get a short-lived public URL, then pass it via image_urls. You can chain this step into the same imagegen.md so Codex handles uploads automatically.


FAQ

Q: I got 404 / "Images API is not supported for this platform".
A: Your key is not in an OpenAI / Codex-tier group. Create a new key in the console and choose any of Codex Lite / Codex Pro / Codex Max.

Q: I got 402 INSUFFICIENT_BALANCE.
A: Image generation always charges balance, never subscription quota. Top up at the dashboard.

Q: Codex says OPENAI_API_KEY: unbound variable.
A: The env var didn't reach the bash subshell Codex spawned. Verify step 1 succeeded; run echo $OPENAI_API_KEY in your current shell to confirm it is exported.

Q: Can Codex generate images automatically in normal chat (without typing /imagegen)?
A: Yes. Move the prompt content into ~/.codex/AGENTS.md (Codex's global system prompt) and tell it "when the user mentions drawing / generating an image, follow this flow…". The model will trigger on its own without a slash command.

Q: How long do image URLs live?
A: The response contains expires_at (unix timestamp), typically a few days. Download or re-host before expiry.

Q: Can I call this from Python / Node SDK instead?
A: Yes — it's plain HTTP. The slash command is purely a convenience for in-Codex workflows; any HTTP client works.