Local npx shim that injects OpenRouter provider routing for Claude Code and OpenAI-compatible harnesses
npm install openrouter-provider-shimLocal npx-runnable shim that enforces OpenRouter provider routing (e.g., Fireworks-only) for AI agent tools that cannot configure it natively. Primarily for Claude Code and Droid - other tools like OpenCode and OpenHands have native OpenRouter provider support.
Some AI agent harnesses can point at an OpenAI-compatible base URL, but they cannot attach OpenRouter's per-request provider routing object. This includes Claude Code, which uses the Anthropic Messages API and has no way to specify provider preferences.
OpenRouter supports a provider object for routing preferences including only, order, ignore, sort (price, throughput, latency), performance thresholds, and max price. This shim injects these fields server-side, so end users do not need OpenRouter account-wide settings.
Note: Tools like OpenCode and OpenHands have native OpenRouter provider configuration and don't need this shim. See When You DON'T Need This Shim below.
- Multi-protocol support: Anthropic Messages API, OpenAI Chat Completions, and OpenAI Responses API
- Provider routing enforcement: Merge, override, or strict modes for provider policies
- Flexible authentication: Passthrough or upstream-key auth modes
- Zero dependencies for runtime: Uses only Node.js built-ins
- Privacy-first logging: Logs metadata only, never prompt content
- Cross-platform: Works on macOS, Linux, and Windows
``bashRun without installing
npx openrouter-provider-shim serve --port 8787 --provider-only fireworks --sort throughput --no-fallbacks
Quick Start
$3
Automatic key substitution
If you have both
ANTHROPIC_API_KEY and OPENROUTER_API_KEY set, the shim will automatically detect and substitute your Anthropic key with your OpenRouter key:`bash
export OPENROUTER_API_KEY="sk-or-v1-..."
export ANTHROPIC_MODEL="moonshotai/kimi-k2.5"
npx openrouter-provider-shim serve --port 8787 --provider-only fireworks --sort throughput --no-fallbacks &export ANTHROPIC_BASE_URL="http://127.0.0.1:8787"
claude
`
$3
Rate limiting: The shim includes automatic retry with custom backoff delays for Claude Code (detected by its use of the Anthropic Messages API). Retries use delays: 1s, 2s, 4s, 8s, 12s, 18s, 24s, 32s. If you hit rate limits:
- Add your own Fireworks API key to OpenRouter (BYOK) at https://openrouter.ai/settings/integrations
- Use the
--provider-order option to allow fallback providers
- Wait a moment between requests and manually retry or prompt "Continue"$3
Some AI tools have native OpenRouter provider routing support and don't need this shim:
OpenCode - Has built-in OpenRouter provider configuration. In
~/.config/opencode/opencode.json:
`json
{
"provider": {
"openrouter": {
"models": {
"moonshotai/kimi-k2.5": {
"options": {
"provider": {
"order": ["fireworks"],
"allow_fallbacks": false
}
}
}
}
}
}
}
`OpenHands - Uses LiteLLM in-process and supports provider routing via
LLM_LITELLM_EXTRA_BODY:
`bash
export LLM_LITELLM_EXTRA_BODY='{"provider":{"order":["fireworks"],"allow_fallbacks":false}}'
export LLM_API_KEY="$OPENROUTER_API_KEY"
export LLM_MODEL="openrouter/moonshotai/kimi-k2.5"
openhands --override-with-envs
`$3
Use this shim for tools that cannot configure OpenRouter's per-request provider routing:
#### Claude Code (Primary Use Case)
Uses Anthropic Messages API - cannot set OpenRouter provider routing. This is the primary use case for this shim.
`bash
export OPENROUTER_API_KEY="your-api-key"
npx openrouter-provider-shim serve --port 8787 --provider-only fireworksexport ANTHROPIC_BASE_URL="http://127.0.0.1:8787"
export ANTHROPIC_MODEL="moonshotai/kimi-k2.5"
claude
`#### Droid (Factory) - When Tool Calls Fail
Droid supports OpenRouter via
generic-chat-completion-api, but tool calls may not work reliably with native OpenRouter integration. If they ever address this, you should be able to simply configure a custom model with OpenRouter provider settings like this:
`json
{
"model": "moonshotai/kimi-k2.5",
"id": "custom:Kimi-K2.5-[OR-->-Fireworks]-2",
"index": 2,
"baseUrl": "https://openrouter.ai/api/v1",
"apiKey": "sk-or-v1-REDACTED",
"displayName": "Kimi K2.5 [OR -> Fireworks]",
"maxOutputTokens": 131072,
"extraArgs": {
"provider": {
"order": [
"fireworks"
],
"allow_fallbacks": false
}
},
"noImageSupport": false,
"provider": "generic-chat-completion-api"
}
`For the time being, however, testing has shown tool calls to fail with the above setup, however. Use this shim for better compatibility.
1. Start the shim:
`bash
export OPENROUTER_API_KEY="sk-or-v1-..."
npx openrouter-provider-shim serve --port 8787 --provider-only fireworks
`2. Add to
~/.factory/settings.json in the customModels array:
`json
{
"model": "moonshotai/kimi-k2.5",
"id": "custom:Kimi-K2.5-[shim-->-Fireworks]-2",
"index": 2,
"baseUrl": "http://127.0.0.1:8787/v1",
"apiKey": "sk-or-v1-REDACTED",
"displayName": "Kimi K2.5 [shim -> Fireworks]",
"maxOutputTokens": 131072,
"noImageSupport": false,
"provider": "generic-chat-completion-api"
}
`
CLI Commands
$3
Starts the local shim server.
`bash
npx openrouter-provider-shim serve \
--port 8787 \
--provider-only fireworks \
--sort throughput \
--no-fallbacks \
--auth-mode passthrough
`$3
Validates config and checks connectivity to OpenRouter.
`bash
npx openrouter-provider-shim doctor --provider-only fireworks
`$3
Prints copy-paste environment variables for Claude Code and OpenAI clients.
`bash
npx openrouter-provider-shim print-env --port 8787
`Configuration
Configuration can be provided via:
1. CLI flags (highest priority)
2. Environment variables
3. Config file (lowest priority)
$3
The shim supports several authentication modes:
passthrough mode (default)
- Forwards the
Authorization header from the inbound request to OpenRouter
- Smart substitution: If the inbound auth looks like an Anthropic API key (starts with sk-ant-) and you have OPENROUTER_API_KEY set, the shim automatically substitutes it with your OpenRouter key
- This allows you to keep ANTHROPIC_API_KEY set for other tools while using OpenRouter via the shimupstream-key mode
- Always uses the configured OpenRouter API key, ignoring inbound auth
- Useful when you don't want clients to know the OpenRouter key
`bash
Default passthrough with smart substitution
npx openrouter-provider-shim serve --port 8787Explicit upstream key (never use inbound auth)
npx openrouter-provider-shim serve --port 8787 --auth-mode upstream-key --upstream-key "sk-or-v1-..."
`$3
| Option | Description |
|--------|-------------|
|
--config | Path to config JSON file |
| --host | Host to bind (default: 127.0.0.1) |
| --port | Port to bind (default: 8787) |
| --merge-mode | Provider merge mode: merge, override, strict |
| --provider-only | Comma-separated list of allowed providers |
| --provider-order | Comma-separated provider priority order |
| --provider-ignore | Comma-separated list of providers to skip |
| --sort | Sort by: price, throughput, latency |
| --no-fallbacks | Disable fallback providers |
| --require-parameters | Require providers to support all parameters |
| --data-collection | Data collection policy |
| --zdr | Enforce Zero Data Retention |
| --quantizations | Comma-separated quantization list |
| --auth-mode | passthrough or upstream-key |
| --upstream-key | OpenRouter API key |
| --local-api-key | Local authentication key |$3
| Variable | Description |
|----------|-------------|
|
OPENROUTER_API_KEY | Your OpenRouter API key |
| SHIM_HOST | Host to bind |
| SHIM_PORT | Port to bind |
| SHIM_AUTH_MODE | passthrough or upstream-key |
| SHIM_LOCAL_API_KEY | Local authentication key |
| SHIM_MERGE_MODE | merge, override, or strict |
| SHIM_PROVIDER_ONLY | Comma-separated allowed providers |
| SHIM_PROVIDER_ORDER | Comma-separated provider order |
| SHIM_PROVIDER_IGNORE | Comma-separated ignored providers |
| SHIM_PROVIDER_SORT | price, throughput, or latency |
| SHIM_PROVIDER_ALLOW_FALLBACKS | true or false |
| SHIM_PROVIDER_REQUIRE_PARAMETERS | true or false |
| SHIM_PROVIDER_DATA_COLLECTION | allow or deny |
| SHIM_PROVIDER_ZDR | true or false |
| SHIM_PROVIDER_QUANTIZATIONS | Comma-separated quantizations |
| SHIM_PROVIDER_PREFERRED_MIN_THROUGHPUT | Number or JSON thresholds |
| SHIM_PROVIDER_PREFERRED_MAX_LATENCY | Number or JSON thresholds |
| SHIM_PROVIDER_MAX_PRICE | JSON: {"prompt":1.0,"completion":4.0} |$3
Create a
shim-config.json:`json
{
"host": "127.0.0.1",
"port": 8787,
"merge_mode": "merge",
"policy": {
"only": ["fireworks"],
"sort": "throughput",
"allow_fallbacks": false
},
"auth_mode": "passthrough",
"log_level": "info"
}
`Run with:
npx openrouter-provider-shim serve --config shim-config.jsonMerge Modes
$3
- If request has no provider, inject the configured policy
- If request has provider, merge missing fields from policy without overriding$3
- Replace request provider entirely with policy provider (hard enforcement)$3
- If request provider exists and differs from policy for any enforced fields, reject with HTTP 422
- Useful for regulated enterprise policiesAPI Endpoints
| Endpoint | Description |
|----------|-------------|
|
POST /v1/messages | Anthropic Messages API |
| POST /v1/chat/completions | OpenAI Chat Completions API |
| POST /v1/responses | OpenAI Responses API |
| GET /v1/models | List available models (pass-through) |
| GET /healthz | Health check |
| GET /version | Version information |
| GET /config | Current configuration (sanitized) |Testing
`bash
Chat Completions
curl http://127.0.0.1:8787/v1/chat/completions \
-H "Authorization: Bearer $OPENROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "moonshotai/kimi-k2.5",
"messages": [{"role":"user","content":"Say hello"}],
"stream": false
}'Anthropic Messages
curl http://127.0.0.1:8787/v1/messages \
-H "Authorization: Bearer $OPENROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "moonshotai/kimi-k2.5",
"max_tokens": 256,
"messages": [{"role":"user","content":"Hello from anthropic messages"}]
}'Responses API
curl http://127.0.0.1:8787/v1/responses \
-H "Authorization: Bearer $OPENROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "moonshotai/kimi-k2.5",
"input": "Hello from responses"
}'
``MIT