OpenRouter's EU route from configuration

OpenRouter serves the same account on two endpoints: https://openrouter.ai/api/v1 (global) and https://eu.openrouter.ai/api/v1, where requests are decrypted and served in the EU only and a model with no EU provider answers 404. The key is account-level, so the EU endpoint is a second route to the same account, never a second account.

What the configuration says

The OpenAI provider module registers an OpenRouterEU catalog source next to OpenRouter. It is configured like the OpenRouter section:

Key Meaning
OpenRouterEU:Models:N The model ids to seed under Provider/OpenRouterEU
OpenRouterEU:Endpoint An override of the EU default https://eu.openrouter.ai/api/v1

There is no OpenRouterEU:ApiKey. The seeded Provider/OpenRouterEU node carries credentialFrom: Provider/OpenRouter and no key: the resolver follows that reference one hop, root catalog only, to whatever key the instance binds on Provider/OpenRouter (vault-seeded or set in Settings → Models). There is one key to rotate.

The route ranks at Order 7, after the global route's 6, so a bare wire id both routes carry keeps resolving where it did; a tier that means the EU node names it by path (below). There is no OpenRouterEU:Order and no Features:Ai:Providers:OpenRouterEU switch: providers are gated by their MODULE being loaded, and nothing reads a per-provider feature flag.

On a Hosting record the same keys come from the ai.openRouterEU block (models, endpoint), rendered to OpenRouterEU__Models__N and OpenRouterEU__Endpoint (an order or enabled on that block renders nothing); ai.requiredDataResidency renders AI__RequiredDataResidency, and each section's dataResidency / dataRetention renders {Section}__DataResidency / __DataRetention.

Two ways a route differs from an ordinary source

A route is a LanguageModelCatalogSource with CredentialFrom set.

  1. It is seeded only where it is configured — OpenRouterEU:Models or OpenRouterEU:Endpoint set. An ordinary source always seeds its provider node so an admin can add a key later; a route has no key of its own to wait for, so an unconfigured one would be an empty duplicate of the account on every instance.
  2. Its model ids are de-duplicated within the route only. The catalog otherwise lets the first source win a shared wire id. For a route the shared id is the point: z-ai/glm-5.3 exists as Provider/OpenRouter/z-ai/glm-5.3 AND Provider/OpenRouterEU/z-ai/glm-5.3, told apart by node path.

Naming an EU model in a tier

With the same wire id on both routes, a bare id does not say which endpoint is meant. A tier (ModelTier:Heavy, i.e. the record's ai.tiers.heavy) may therefore name the model by node path:

ModelTier__Heavy = Provider/OpenRouterEU/z-ai/glm-5.3

Tier resolution matches the configured value against each candidate's node path first, then its wire id, and answers the matched candidate's selection: the path when the id is shared, the bare id when it is not. A bare shared id is answered with the path of the lowest-ranked node carrying it (order, then path), never with the ambiguous id.

A route's model never falls back to the global route

A node path selects one node, and its credential is that node's bound provider. When the exact node yields no key, a node that pins nothing may fall through to the same-id walk (the keyless catalog entry against a user's keyed copy). A node on a route may not: the same id on the other route is the same model on a DIFFERENT endpoint, so falling through would send an EU selection to the global endpoint with the global key and nothing to say so. A route's node resolves through its reference or not at all. OpenRouterEURouteMeshTest.ARouteWhoseReferencedKeyIsMissing_FailsClosed_NeverOnTheGlobalRoute pins it (removing the guard turns it red with the global endpoint).

The OpenRouter prompt-cache policy applies to the route as to any *.openrouter.ai host. The upstream-routing guard (OpenRouterProviderRoutingPolicy) applies to any node on it that pins providerRouting — the governed review model does; the config-seeded models pin nothing.

Which Provider/OpenRouterEU wins

Two things can create the node: the governed standard pr.review-provider-eu.create (the PR steward's setup) and a deployment's OpenRouterEU configuration. Both write the same meaning — the EU endpoint and credentialFrom: Provider/OpenRouter.

The authored node wins. The static import skips a target whose syncBehavior is not Include, so the standard creates its node CLAIMED (syncBehavior: ExcludeThisOnly, a CreateNode executor argument). A deployment that later configures the route then imports the models UNDER the governed node and leaves the node itself alone. An unclaimed authored node would be overwritten on the next import whose fingerprint changed; AnUnclaimedAuthoredRouteNode_IsOverwritten_WhichIsWhyTheStandardClaimsIt shows it.

In the other order, the configuration seeds the node first (claimed the same way, as every seeded provider is), and the standard's create is refused as an existing node — there the standard is not needed.

Recycling after a deploy

The catalog is served from Provider; after the AI module reaches an instance, recycle Provider/OpenRouterEU (and Provider/OpenRouter when its models changed) so a live activation re-reads.