n4nAI

OpenRouter to n4n: preserving fallback and routing behavior

Practical step-by-step guide to migrate OpenRouter to n4n preserving fallback and routing behavior with OpenAI-compatible client code.

n4n Team4 min read798 words

Audio narration

Coming soon — every post will get a voice note here.

Migrating from OpenRouter to n4n preserving fallback behavior is mostly a client configuration change, not a rewrite. Both gateways expose an OpenAI-compatible surface, but fallback semantics and routing headers need explicit mapping to avoid silent regressions.

Step 1: Inventory your OpenRouter routing and fallback configuration

Before changing endpoints, capture exactly how your current stack selects models and degrades. In OpenRouter, fallback is typically expressed either through a comma-separated model list in the model field or via a route: fallback header combined with a candidate array.

# Existing OpenRouter call
client = OpenAI(
    base_url="https://openrouter.ai/api/v1",
    api_key=os.environ["OPENROUTER_KEY"],
)
resp = client.chat.completions.create(
    model="openai/gpt-4o,anthropic/claude-3.5-sonnet",
    messages=[{"role": "user", "content": "Summarize this"}],
    extra_headers={"route": "fallback"},
)

If you use a config file, extract the ordered model list and any cache-control hints. Note whether you rely on provider-specific fields such as Anthropic cache_control inside message objects. Record the exact header names (route, x-foo) and body extensions (weight, models) you send today.

Step 2: Repoint the OpenAI client to the n4n endpoint

The only mandatory code change is the base_url and key. n4n.ai exposes a single OpenAI-compatible endpoint that addresses 240+ models, so your model strings stay identical.

import os
from openai import OpenAI

client = OpenAI(
    base_url="https://api.n4n.ai/v1",  # n4n.ai OpenAI-compatible endpoint
    api_key=os.environ["N4N_KEY"],
)

If your code reads the base URL from an environment variable, just swap OPENROUTER_URL to https://api.n4n.ai/v1. No request schema changes are required for basic chat completions. Keep your timeout and retry settings; they are orthogonal to the gateway.

Step 3: Translate fallback semantics without losing control

OpenRouter to n4n preserving fallback means you must decide between explicit client-driven fallback and n4n’s automatic provider fallback. n4n honors client routing directives, so if you already send a route header or a multi-model string, keep it. The gateway will also automatically reroute when a provider is rate-limited or degraded, which covers cases you previously handled with manual fallback lists.

# Explicit fallback preserved
resp = client.chat.completions.create(
    model="openai/gpt-4o,anthropic/claude-3.5-sonnet",
    messages=[{"role": "user", "content": "Translate this PR description"}],
    extra_headers={"route": "fallback"},
)

If you prefer to rely on automatic fallback, drop the route header and let n4n switch providers on 429/5xx. Either way, the model field accepts the same slash-qualified names (openai/gpt-4o, anthropic/claude-3.5-sonnet).

For weighted routing, OpenRouter uses route: weighted with a models array and weight. n4n forwards client routing directives, so pass the same header and body shape:

resp = client.chat.completions.create(
    model=["openai/gpt-4o", "anthropic/claude-3.5-sonnet"],
    messages=[{"role": "user", "content": "Code review"}],
    extra_headers={"route": "weighted"},
    # weights passed via provider-specific extension
    extra_body={"weight": [0.7, 0.3]},
)

If your OpenRouter integration used a different field name for weights, map it to the equivalent extension field your n4n setup expects. The key point for OpenRouter to n4n preserving fallback is that no routing logic is lost—you either keep the explicit directive or gain automatic coverage.

Step 4: Forward provider cache-control hints unchanged

Prompt caching reduces cost and latency on long contexts. OpenRouter forwards Anthropic cache_control blocks; n4n does the same. Preserve the exact message structure:

messages = [
    {"role": "system", "content": "You are a strict linter."},
    {
        "role": "user",
        "content": large_codebase,
        "cache_control": {"type": "ephemeral"},
    },
    {"role": "user", "content": "Find unused imports."},
]
resp = client.chat.completions.create(
    model="anthropic/claude-3.5-sonnet",
    messages=messages,
)

Do not strip these fields during migration. They are passed through to the upstream provider, and n4n meters token usage including cached tokens if the provider reports them. If you used OpenRouter’s cache-control HTTP header instead of message-level blocks, send that header unchanged in extra_headers.

Step 5: Capture per-token usage for cost accountability

Both gateways return OpenAI-style usage objects. After the call, log prompt_tokens, completion_tokens, and total_tokens. n4n provides per-token usage metering, so you can reconcile against your own logs:

print(resp.usage.model_dump())
# {'prompt_tokens': 1200, 'completion_tokens': 80, 'total_tokens': 1280}

If you previously used OpenRouter’s usage extension for cache breaks, check the response for provider-specific fields and forward them to your analytics pipeline. Instrument a thin wrapper that emits model, usage.total_tokens, and the routing header value to your metrics store. This makes later regression checks trivial.

Step 6: Verify fallback and routing end-to-end

A migration is not done until you have proven degradation handling. Write a small probe that forces a failure on the primary model. The simplest method is to temporarily use a nonexistent model qualifier as the first entry; n4n’s automatic fallback (or your explicit list) should still return a valid completion.

def test_fallback():
    r = client.chat.completions.create(
        model="openai/does-not-exist,anthropic/claude-3.5-sonnet",
        messages=[{"role": "user", "content": "ping"}],
        extra_headers={"route": "fallback"},
        timeout=10,
    )
    assert r.choices[0].message.content
    print("Fallback OK, model used:", r.model)

test_fallback()

Success criteria:

  1. The call returns a completion despite the invalid first model.
  2. Response headers (if exposed) show a routing directive was honored, or your n4n dashboard indicates a provider switch.
  3. usage is populated and matches expectations for the secondary model.

For cache-control, send a request with a cache_control block and confirm the provider returns cached token counts (e.g., prompt_tokens_details in Anthropic responses). If those details appear, forwarding works.

Finally, run your full integration suite against the new endpoint with production-like traffic shapes. Monitor error rates for 429s; n4n’s automatic fallback should mask transient provider limits without code changes. If you rely on explicit fallback, inject fault injection at the network layer to confirm your route header triggers the secondary model.

Caveats and edge cases

  • Some OpenRouter-only extensions (e.g., transforms, route with alternatives) may need mapping to n4n’s routing directive format. Audit your extra_body payloads.
  • If you used OpenRouter’s models endpoint to list capabilities, replace it with n4n’s equivalent model list call, but the chat completion path remains unchanged.
  • Per-token metering is accurate only if you do not bypass the gateway with direct provider keys.
  • When preserving fallback from OpenRouter to n4n, keep the same model name casing. Provider qualifiers are case-sensitive in both systems.

Following these steps, OpenRouter to n4n preserving fallback becomes a configuration swap plus a verification harness, not a re-architecture.

Tagsfallbackroutingopenrouter

Written by

n4n Team

The team building n4n — a single OpenAI-compatible API in front of 240+ models, with automatic fallback, load balancing and pay-per-token metering.

More from n4n Team →

All migrating from openrouter to n4n posts →