Multi-provider API proxy with an Anthropic-compatible endpoint. Drop-in replacement for api.anthropic.com -- routes requests through OpenCode with automatic fallback across 14 providers. When no OpenCode API key is configured, Puter is used as primary (free Claude models).
cp .env.example .env # add your API keys
npm install
npm start # starts on http://0.0.0.0:4000Point Claude Code at the proxy (~/.claude/settings.json):
{
"env": {
"ANTHROPIC_API_KEY": "YOUR_API_KEY",
"ANTHROPIC_BASE_URL": "http://localhost:4000",
"CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1"
}
}Client
| POST /v1/messages (Anthropic format)
v
Express server
|-- routeFor() -- map model name to backend model ID
|-- getModelConfig() -- pick endpoint + protocol
|-- sanitizeMessages() -- repair JSON, coerce roles, strip surrogates
|-- buildChain() -- build 14-provider fallback chain
|-- tryChain() -- parallel (opus=3, sonnet=2) then sequential
| |-- cooldown-aware skip
| |-- rate-limit header parsing + bucket state tracking
| |-- circuit breaker (3 consecutive failures -> 5min cooldown)
| |-- jittered backoff (1s, 2s, 4s, 8s)
| |-- content-type validation (detect error-page HTML)
| |-- per-provider TTFB timeouts (8s-25s)
| |-- fetch with proxy agent
| v
|-- format conversion -- openaiToAnthropic / anthropicToOpenAI
| |-- streaming think scrubber (<think>/<reasoning> at SSE boundaries)
| |-- mid-stream silent retry
| |-- Ollama tool-call slot fix
|-- logRequest() -- persist to SQLite (degradation-safe)
v
Response (Anthropic format)
| # | Provider | Key Required | Tier | Notes |
|---|---|---|---|---|
| 1 | OpenCode | Yes | Primary | Skipped if OPENCODE_API_KEY is unset |
| 2 | Puter | Yes (token) | Free | Primary when no OpenCode key; uses native Claude IDs (claude-sonnet-4-6, claude-opus-4-8, claude-haiku-4-5); 200k context |
| 3 | Ollama | No | Local | Self-hosted, no rate limits |
| 4 | NVIDIA NIM | No | Free | Rate-limited, free tier |
| 5 | Kimi (Moonshot) | Yes | Fallback | 256k context; models mapped as kimi-k2.* |
| 6 | OpenRouter | Yes | Fallback | Broad model selection |
| 7 | Cerebras | Yes | Fallback | Fast inference |
| 8 | GitHub Models | Yes | Fallback | Azure-backed |
| 9 | Mistral | Yes | Fallback | Le Chat Mistral |
| 10 | HuggingFace | Yes | Fallback | Serverless Inference API |
| 11 | Novita | Yes | Fallback | Pay-as-you-go |
| 12 | OpenAI | Yes | Fallback | Quota-limited |
| 13 | Gemini | Yes | Fallback | Quota-limited |
| 14 | Groq | Yes | Fallback | Fast but rate-limited; tried last |
| Variable | Default | Description |
|---|---|---|
SECRET_KEY |
-- | API key clients send as x-api-key |
OPUS_MAP_MODEL |
deepseek-v4-flash-free |
Model for opus requests |
SONNET_MAP_MODEL |
mimo-v2.5-free |
Model for sonnet requests |
HAIKU_MAP_MODEL |
north-mini-code-free |
Model for haiku requests |
PRIMARY_PROVIDER |
-- | Force a specific provider first (e.g. puter) |
PUTER_AUTH_TOKEN |
-- | JWT token from puter.com/dashboard for Puter API |
KIMI_API_KEY / MOONSHOT_API_KEY |
-- | API key for Kimi (Moonshot) |
HOST |
0.0.0.0 |
Bind address |
PORT |
4000 |
Listen port |
OPENCODE_BASE_URL |
https://opencode.ai |
Upstream OpenCode API base URL |
OPENCODE_PROXY |
-- | HTTP proxy URL for upstream requests |
| Method | Path | Description |
|---|---|---|
| POST | /v1/messages |
Anthropic Messages API (main) |
| POST | /anthropic/v1/messages |
Alias for /v1/messages |
| GET | /v1/models |
List configured models |
| GET | /v1/providers |
List providers with health status |
| GET | /health |
Health check (Docker-compatible) |
| GET | /dash |
Live web dashboard |
| GET | /dash/data |
Dashboard stats (JSON) |
Runtime: Node.js 20+ | Language: TypeScript (via tsx) | Framework: Express 5 | DB: SQLite (better-sqlite3) | TUI: blessed | Dashboard: Server-side HTML with ANIMO dark theme (#0f131c / #caf979)
MIT