Configure automatic model fallbacks for high availability on OpenRouter. Use when building resilient systems that need to survive provider outages. Triggers: 'openrouter fallback', 'model fallback', 'openrouter failover', 'openrouter backup model'.
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
A direct command skips the review prompt. Inspect the source before running it.
Configure automatic model fallbacks for high availability on OpenRouter. Use when building resilient systems that need to survive provider outages. Triggers: 'openrouter fallback', 'model fallback', 'openrouter failover', 'openrouter backup model'.
Designed for Claude Code, also compatible with Codex and OpenClaw
OpenRouter Fallback Config
Overview
OpenRouter supports native model fallbacks: pass multiple model IDs and OpenRouter tries each in order until one succeeds. You can also use provider.order to control which provider serves a specific model. This skill covers native fallbacks, provider routing, client-side fallback chains, and timeout configuration.
Prerequisites
An OpenRouter API key (sk-or-v1-...) exported as OPENROUTER_API_KEY — see the openrouter-install-auth skill for setup
Python 3.8+ with the OpenAI SDK (pip install openai) for the fallback patterns; curl and jq for the Testing Fallbacks step
A ranked list of acceptable models for your workload, matched by capability (tool calling, vision, context length) so a fallback never silently drops a feature you depend on
Instructions
Start with Native Model Fallback (Server-Side): pass a models array plus route: "fallback" in extra_body and let OpenRouter try each model in order.
Log response.model after every call — it tells you which model actually served the request, which is how you detect that a fallback fired.
If you need the same model from specific vendors (e.g., Claude via Anthropic direct vs AWS Bedrock), use Provider Fallback with provider.order and allow_fallbacks.
For per-model timeouts and custom error handling, implement the Client-Side Fallback Chain: resilient_completion() walks FALLBACK_CHAIN (primary → secondary → budget-fallback → last-resort) and raises once every entry fails.
Pick chains per feature with Fallback with Capability Matching — CAPABILITY_CHAINS keeps tool-calling, vision, long-context, and budget workloads on models that actually support them.
Verify the behavior with Testing Fallbacks: send the curl request with an invalid primary model and confirm the response comes back from openai/gpt-4o-mini.
# Pass multiple models -- OpenRouter tries each in order
"anthropic/claude-3.5-sonnet"
# Primary (used for param validation)
"role"
"user"
"content"
"Explain recursion"
500
"models"
"anthropic/claude-3.5-sonnet"
"openai/gpt-4o"
"google/gemini-2.0-flash-001"
"route"
"fallback"
# Try in order until one succeeds
# Check which model actually served the request
print
f"Served by: {response.model}"
Provider Fallback (Same Model, Different Providers)
# Route to specific providers in priority order
response = client.chat.completions.create(
model="anthropic/claude-3.5-sonnet",
messages=[{"role": "user", "content": "Hello"}],
max_tokens=200,
extra_body={
"provider": {
"order": ["Anthropic", "AWS Bedrock", "GCP Vertex"],
"allow_fallbacks": True, # Fall to next provider if first fails
},
},
)
Client-Side Fallback Chain
import logging
from openai import OpenAI, APIError, APITimeoutError
log = logging.getLogger("openrouter.fallback")
FALLBACK_CHAIN = [
{"model": "anthropic/claude-3.5-sonnet", "timeout": 30.0, "label": "primary"},
{"model": "openai/gpt-4o", "timeout": 25.0, "label": "secondary"},
{"model": "openai/gpt-4o-mini", "timeout": 15.0, "label": "budget-fallback"},
{"model": "google/gemini-2.0-flash-001", "timeout": 15.0, "label": "last-resort"},
]
defresilient_completion(messages: list[dict], max_tokens: int = 1024, **kwargs):
"""Try each model in the fallback chain until one succeeds."""
last_error = Nonefor config in FALLBACK_CHAIN:
try:
client = OpenAI(
base_url="https://openrouter.ai/api/v1",
api_key=os.environ["OPENROUTER_API_KEY"],
timeout=config["timeout"],
default_headers={"HTTP-Referer": "https://my-app.com", "X-Title": "my-app"},
)
response = client.chat.completions.create(
model=config["model"],
messages=messages,
max_tokens=max_tokens,
**kwargs,
)
log.info(f"Served by {config['label']}: {response.model}")
return response
except (APIError, APITimeoutError) as e:
last_error = e
log.warning(f"{config['label']} failed ({config['model']}): {e}")
continueraise RuntimeError(f"All fallbacks exhausted. Last error: {last_error}")
# Test with an invalid model to trigger fallback
curl -s https://openrouter.ai/api/v1/chat/completions \
-H "Authorization: Bearer $OPENROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "invalid/model-name",
"messages": [{"role": "user", "content": "test"}],
"max_tokens": 10,
"models": ["invalid/model-name", "openai/gpt-4o-mini"],
"route": "fallback"
}' | jq '{model: .model, content: .choices[0].message.content}'# Should succeed with openai/gpt-4o-mini
Output
A configured fallback setup produces:
Chat completions whose response.model field reveals the model that actually served each request — the primary when healthy, a chain entry when a fallback fired
Log lines from resilient_completion(): Served by primary: anthropic/claude-3.5-sonnet on success, primary failed (anthropic/claude-3.5-sonnet): ... warnings per failed hop
A RuntimeError("All fallbacks exhausted. Last error: ...") when every model in FALLBACK_CHAIN fails — the signal to alert on
From the Testing Fallbacks curl: a {model, content} JSON showing the request survived an invalid primary model
Examples
Force a fallback by putting an invalid model first in the models array: