| name | codex2api-reverse-proxy |
| description | Codex2API is a production-ready reverse proxy that converts Codex account pools into OpenAI/Anthropic-compatible API gateways with account management, scheduling, and admin dashboard. |
| triggers | ["set up codex2api proxy server","configure codex account pool gateway","deploy openai compatible codex proxy","manage codex refresh tokens with api","create anthropic compatible codex endpoint","configure codex2api with postgresql redis","troubleshoot codex2api account scheduler","use codex2api admin dashboard"] |
Codex2API Reverse Proxy
Skill by ara.so — Codex Skills collection.
Codex2API is a Go + Gin + React production gateway that transforms a pool of Codex accounts into observable, schedulable OpenAI/Anthropic-compatible API endpoints. It manages Refresh Token/Access Token lifecycles, health scoring, dynamic concurrency, rate-limit recovery, usage tracking, and admin operations through a built-in dashboard.
What It Does
- Unified Gateway: Exposes
/v1/chat/completions, /v1/responses, /v1/messages, /v1/images/generations, /v1/images/edits, and /v1/models endpoints
- Account Pool Management: Handles Refresh Tokens and Access Tokens with automatic health scoring and cooldown recovery
- Dynamic Scheduling: Selects accounts based on health tier, concurrency limits, rate limits, and recent usage
- Admin Dashboard: React/Vite UI for account import, API key management, proxy pools, image studio, prompt filtering, usage analytics
- Flexible Storage: Production mode (PostgreSQL + Redis) or lightweight mode (SQLite + in-memory cache)
Installation
Standard Production Deployment (PostgreSQL + Redis)
git clone https://github.com/james-6-23/codex2api.git
cd codex2api
cp .env.example .env
docker compose pull
docker compose up -d
docker compose logs -f codex2api
Lightweight SQLite Deployment
git clone https://github.com/james-6-23/codex2api.git
cd codex2api
cp .env.sqlite.example .env
docker compose -f docker-compose.sqlite.yml pull
docker compose -f docker-compose.sqlite.yml up -d
docker compose -f docker-compose.sqlite.yml logs -f codex2api
Local Development
cp .env.example .env
cd frontend && npm ci && npm run build && cd ..
go run .
Frontend dev server:
cd frontend && npm ci && npm run dev
Configuration
Environment Variables (.env)
Server:
CODEX_PORT=8080
ADMIN_SECRET=your-secure-admin-password
TZ=Asia/Shanghai
PostgreSQL Mode:
DATABASE_DRIVER=postgres
DATABASE_HOST=localhost
DATABASE_PORT=5432
DATABASE_USER=codex2api
DATABASE_PASSWORD=secure-db-password
DATABASE_NAME=codex2api
DATABASE_SSLMODE=disable
CACHE_DRIVER=redis
REDIS_ADDR=localhost:6379
REDIS_PASSWORD=secure-redis-password
REDIS_DB=0
SQLite Mode:
DATABASE_DRIVER=sqlite
DATABASE_PATH=/data/codex2api.db
CACHE_DRIVER=memory
Redis TLS (Aiven, Upstash, etc.):
REDIS_ADDR=rediss://default:password@host:port/0
REDIS_ADDR=host:port
REDIS_TLS=true
REDIS_INSECURE_SKIP_VERIFY=false
REDIS_USERNAME=default
REDIS_PASSWORD=your-password
Runtime Settings (Database)
After first startup, configure via admin dashboard at /admin/settings:
MaxConcurrency: Global concurrent request limit
GlobalRPM: Global requests per minute
TestModel: Model for account health checks
TestConcurrency: Test request concurrency
ProxyURL: Global proxy (e.g., http://proxy:port)
PgMaxConns: PostgreSQL connection pool size
RedisPoolSize: Redis connection pool size
- Auto-cleanup settings for logs and usage records
API Usage
OpenAI Chat Completions
package main
import (
"context"
"fmt"
"os"
"github.com/sashabaranov/go-openai"
)
func main() {
config := openai.DefaultConfig(os.Getenv("CODEX2API_KEY"))
config.BaseURL = "http://localhost:8080/v1"
client := openai.NewClientWithConfig(config)
resp, err := client.CreateChatCompletion(
context.Background(),
openai.ChatCompletionRequest{
Model: "claude-code",
Messages: []openai.ChatCompletionMessage{
{
Role: openai.ChatMessageRoleUser,
Content: "Explain how Codex2API account scheduling works",
},
},
},
)
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
fmt.Println(resp.Choices[0].Message.Content)
}
Anthropic Messages (Compatible Endpoint)
import os
import anthropic
client = anthropic.Anthropic(
api_key=os.environ.get("CODEX2API_KEY"),
base_url="http://localhost:8080/v1"
)
message = client.messages.create(
model="claude-code",
max_tokens=1024,
messages=[
{"role": "user", "content": "Explain dynamic concurrency in Codex2API"}
]
)
print(message.content[0].text)
Native Codex Responses
curl -X POST http://localhost:8080/v1/responses \
-H "Authorization: Bearer $CODEX2API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-code",
"messages": [
{
"role": "user",
"content": "Write a hello world in Go"
}
],
"stream": false
}'
Image Generation
curl -X POST http://localhost:8080/v1/images/generations \
-H "Authorization: Bearer $CODEX2API_KEY" \
-H "Content-Type: application/json" \
-d '{
"prompt": "A serene mountain landscape at sunset",
"model": "gemini-2.0-flash-exp-image",
"n": 1,
"size": "1024x1024"
}'
Image Editing
curl -X POST http://localhost:8080/v1/images/edits \
-H "Authorization: Bearer $CODEX2API_KEY" \
-F "image=@original.png" \
-F "prompt=Add a rainbow in the sky" \
-F "model=gemini-2.0-flash-exp-image" \
-F "n=1"
List Models
curl http://localhost:8080/v1/models \
-H "Authorization: Bearer $CODEX2API_KEY"
Account Management API
Upload Refresh Tokens
curl -X POST http://localhost:8080/api/admin/accounts/upload \
-H "X-Admin-Key: $ADMIN_SECRET" \
-H "Content-Type: application/json" \
-d '{
"tokens": [
"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."
]
}'
Upload Access Tokens
curl -X POST http://localhost:8080/api/admin/accounts/upload \
-H "X-Admin-Key: $ADMIN_SECRET" \
-H "Content-Type: application/json" \
-d '{
"tokens": [
"sess-abc123...",
"sess-def456..."
],
"type": "access_token"
}'
Test Account Health
curl -X POST http://localhost:8080/api/admin/accounts/test \
-H "X-Admin-Key: $ADMIN_SECRET"
curl -X POST http://localhost:8080/api/admin/accounts/test \
-H "X-Admin-Key: $ADMIN_SECRET" \
-H "Content-Type: application/json" \
-d '{"account_id": "550e8400-e29b-41d4-a716-446655440000"}'
List Accounts
curl http://localhost:8080/api/admin/accounts \
-H "X-Admin-Key: $ADMIN_SECRET"
Delete Account
curl -X DELETE http://localhost:8080/api/admin/accounts/550e8400-e29b-41d4-a716-446655440000 \
-H "X-Admin-Key: $ADMIN_SECRET"
API Key Management
Create API Key
curl -X POST http://localhost:8080/api/admin/apikeys \
-H "X-Admin-Key: $ADMIN_SECRET" \
-H "Content-Type: application/json" \
-d '{
"name": "Production Client",
"key": "sk-custom-key-123",
"max_rpm": 100,
"max_tpm": 50000
}'
Response:
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Production Client",
"key": "sk-custom-key-123",
"max_rpm": 100,
"max_tpm": 50000,
"enabled": true,
"created_at": "2026-05-16T10:30:00Z"
}
List API Keys
curl http://localhost:8080/api/admin/apikeys \
-H "X-Admin-Key: $ADMIN_SECRET"
Disable/Enable API Key
curl -X PATCH http://localhost:8080/api/admin/apikeys/550e8400-e29b-41d4-a716-446655440000 \
-H "X-Admin-Key: $ADMIN_SECRET" \
-H "Content-Type: application/json" \
-d '{"enabled": false}'
Common Patterns
Account Scheduler Logic
The scheduler selects accounts based on:
- Health Tier:
Active (healthy) > Cooldown (recovering) > Inactive (failed)
- Concurrency: Current concurrent requests < account's max concurrency
- Rate Limits: RPM (requests per minute) and TPM (tokens per minute) not exceeded
- Score: Weighted by success rate, recent failures, and last success time
- Cooldown Recovery: Accounts in cooldown automatically transition to Active after configured interval
score := (successRate * 0.5) +
(1.0 - recentFailureRate * 0.3) +
(timeSinceLastSuccess * 0.2)
Health Check Workflow
Proxy Configuration
Set per-account proxy:
curl -X PATCH http://localhost:8080/api/admin/accounts/550e8400-e29b-41d4-a716-446655440000 \
-H "X-Admin-Key: $ADMIN_SECRET" \
-H "Content-Type: application/json" \
-d '{"proxy_url": "http://proxy.example.com:8080"}'
Global proxy via settings page or environment:
PROXY_URL=http://global-proxy:8080
Streaming Responses
import os
import anthropic
client = anthropic.Anthropic(
api_key=os.environ.get("CODEX2API_KEY"),
base_url="http://localhost:8080/v1"
)
with client.messages.stream(
model="claude-code",
max_tokens=1024,
messages=[{"role": "user", "content": "Count to 10"}]
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)
Prompt Filter (Block/Warn/Modify)
Configure in admin dashboard under "Prompt Filter":
{
"enabled": true,
"rules": [
{
"pattern": "(?i)nuclear",
"action": "block",
"message": "Content violates policy"
},
{
"pattern": "(?i)medical advice",
"action": "warn",
"message": "Consider consulting a professional"
}
]
}
Docker Commands
Standard Mode
docker compose up -d
docker compose logs -f codex2api
docker compose restart codex2api
docker compose down
docker compose pull && docker compose up -d
SQLite Mode
docker compose -f docker-compose.sqlite.yml up -d
docker compose -f docker-compose.sqlite.yml logs -f codex2api
docker compose -f docker-compose.sqlite.yml pull
docker compose -f docker-compose.sqlite.yml up -d
Backup and Restore
PostgreSQL:
docker exec codex2api-postgres pg_dump -U codex2api codex2api > backup_$(date +%Y%m%d_%H%M%S).sql
docker exec -i codex2api-postgres psql -U codex2api codex2api < backup_20260516_103000.sql
SQLite:
docker exec codex2api sqlite3 /data/codex2api.db ".backup /data/backup_$(date +%Y%m%d_%H%M%S).db"
cp /path/to/data/codex2api.db /path/to/backup/codex2api_$(date +%Y%m%d_%H%M%S).db
Troubleshooting
No Healthy Accounts Available
Symptom: API returns 503 or "No available account"
Solutions:
- Check account health in admin dashboard
- Run account tests:
POST /api/admin/accounts/test
- Verify Refresh Tokens are valid (not expired)
- Check cooldown settings and wait for recovery
- Review logs for authentication failures
curl http://localhost:8080/api/admin/accounts \
-H "X-Admin-Key: $ADMIN_SECRET" | jq '.[] | {id, email, status, health_tier}'
curl -X POST http://localhost:8080/api/admin/accounts/test \
-H "X-Admin-Key: $ADMIN_SECRET"
Database Connection Failed
PostgreSQL:
docker exec codex2api-postgres pg_isready -U codex2api
docker logs codex2api-postgres
grep DATABASE_ .env
SQLite:
docker exec codex2api ls -la /data/codex2api.db
docker inspect codex2api | jq '.[0].Mounts'
Redis Connection Failed
docker exec codex2api-redis redis-cli ping
docker exec codex2api-redis redis-cli -a "$REDIS_PASSWORD" ping
Rate Limit Exceeded
Symptom: 429 Too Many Requests
Solutions:
- Check API key limits in admin dashboard
- Increase
max_rpm or max_tpm for the key
- Review global
GlobalRPM setting
- Add more accounts to the pool
- Verify account-level rate limits
curl -X PATCH http://localhost:8080/api/admin/apikeys/YOUR_KEY_ID \
-H "X-Admin-Key: $ADMIN_SECRET" \
-H "Content-Type: application/json" \
-d '{"max_rpm": 200, "max_tpm": 100000}'
High Concurrency Blocking
Symptom: Requests queue or timeout during high load
Solutions:
- Increase
MaxConcurrency in settings
- Add more healthy accounts
- Adjust per-account concurrency limits
- Scale horizontally (multiple Codex2API instances with shared PostgreSQL/Redis)
curl http://localhost:8080/api/admin/stats \
-H "X-Admin-Key: $ADMIN_SECRET" | jq '.current_concurrency'
Image Generation Fails
Common issues:
- Model doesn't support images (only
gemini-*-image models work)
- Image file format not supported (use PNG/JPEG)
- File size exceeds limits
- No accounts with image capability
curl http://localhost:8080/v1/models \
-H "Authorization: Bearer $CODEX2API_KEY" | jq '.data[] | select(.id | contains("image"))'
Admin Dashboard 401 Unauthorized
Symptom: Login fails or /api/admin/* returns 401
Solutions:
- Verify
ADMIN_SECRET in .env matches login password
- Check
X-Admin-Key header in requests
- Restart after changing
ADMIN_SECRET
docker exec codex2api env | grep ADMIN_SECRET
docker compose restart codex2api
Memory or CPU Usage High
PostgreSQL mode:
docker stats codex2api codex2api-postgres codex2api-redis
SQLite mode:
docker exec codex2api du -h /data/codex2api.db
docker exec codex2api sqlite3 /data/codex2api.db "VACUUM;"
Advanced Configuration
Custom Test Model
curl -X PATCH http://localhost:8080/api/admin/settings \
-H "X-Admin-Key: $ADMIN_SECRET" \
-H "Content-Type: application/json" \
-d '{"test_model": "claude-sonnet-4"}'
Auto-Cleanup Policies
Configure in admin settings:
AutoCleanupEnabled: Enable automatic cleanup
LogRetentionDays: Keep request logs for N days (default 30)
UsageRetentionDays: Keep usage records for N days (default 90)
Horizontal Scaling
Multiple Codex2API instances can share PostgreSQL + Redis:
services:
codex2api-1:
image: ghcr.io/james-6-23/codex2api:latest
environment:
- DATABASE_HOST=postgres
- REDIS_ADDR=redis:6379
codex2api-2:
image: ghcr.io/james-6-23/codex2api:latest
environment:
- DATABASE_HOST=postgres
- REDIS_ADDR=redis:6379
Use a load balancer (nginx, Caddy, Traefik) to distribute requests.
Health Check Endpoint
curl http://localhost:8080/health
Response:
{
"status": "healthy",
"database": "ok",
"cache": "ok",
"timestamp": "2026-05-16T10:30:00Z"
}
Use in Kubernetes liveness/readiness probes or Docker healthchecks.
Resources