# OpenRouter residency and ZDR: split the base URL and retention controls

> Split OpenRouter residency (us/eu base URLs + Guardrails) from ZDR retention. Ship the base URL map, fail-closed catalog, provider.zdr, and app logging.
> By Dave · 2026-09-14
> Source: https://otf-kit.dev/blog/openrouter-residency-zdr-product-controls

Customer contracts that touch AI inference usually ask two separate questions in the same paragraph: where may prompts be processed, and may anyone keep them after the completion returns. Those are not one checkbox. A US-or-EU processing clause is a geography control. A zero-retention clause is a retention control. Mixing them up is how teams ship a “compliant” gateway call that still fails the questionnaire.

OpenRouter now exposes both knobs as product controls builders can wire in code: regional base URLs (`us.openrouter.ai` / `eu.openrouter.ai`) plus Guardrails for data-region pins, and Zero Data Retention (ZDR) via account settings, Guardrails, or per-request `provider.zdr`. This post is the change list for that split — the base-URL map, fail-closed regional catalog behavior, ZDR route flags, and the app logging / tool policies vendor ZDR never covers. Related OpenRouter surfaces stay linked later: [hosted shell](/blog/openrouter-shell-owned-repo) is rented Linux seconds; [Fusion](/blog/openrouter-fusion-selective-escalation) is multi-model deliberation. Neither substitutes for residency or retention routing.

## What the two controls actually do

**In-Region Routing (US + EU).** Point API traffic at a region host instead of the global `openrouter.ai` base:

- `https://us.openrouter.ai/api/v1`
- `https://eu.openrouter.ai/api/v1`

Account API keys, model ids, provider preferences, fallbacks, and privacy settings carry over. OpenRouter’s announcement states the residency claim plainly: on those hosts, requests are decrypted inside the named region and routed only to providers running in that region for the full request lifecycle ([In-Region Routing](https://openrouter.ai/blog/announcements/us-in-region-routing/)). If no in-region provider can serve the model, the call fails with `404` (`No endpoints found supporting your data region.`) instead of quietly leaving the region.

That is end-to-end regional routing, not inference-only pinning. Inference-only designs can keep a GPU in-region while decrypting the gateway hop elsewhere — and server tools (web search, and similar) can still send prompts to global infrastructure. OpenRouter’s write-up says tools that would send data outside the region are disabled on the regional host rather than falling back to global infra. When you evaluate any gateway residency claim, ask two questions: where is the request decrypted, and where do tools run?

In-Region Routing is on Business and Enterprise plans. Guardrails can pin allowed data regions for a workspace, team, or API key so a covered request on the wrong hostname is rejected. The regional catalog is a subset of the global list under the same model ids; call `/api/v1/models` on the regional domain (or filter the models page by In-Region Routing) for the live set.

**Zero Data Retention (ZDR).** ZDR means an eligible inference provider processes the prompt, returns the completion, and does not persist either afterward ([ZDR guide](https://openrouter.ai/blog/insights/zero-data-retention/)). It is a retention guarantee at the provider endpoint. It does not keep data inside your VPC, erase your application logs, or auto-cover plugins and tools attached to the request.

On OpenRouter you can require ZDR through account privacy settings (including per model group), Guardrails, or the per-request `provider.zdr: true` field. Related but separate: `provider.data_collection: "deny"` excludes endpoints that store user data non-transiently and may train on it. OpenRouter publishes the current ZDR endpoint list at `https://openrouter.ai/api/v1/endpoints/zdr` so routing can follow live policy instead of a stale spreadsheet.

## Residency and retention are different contract lines

Compliance language often collapses “stay in the US/EU” and “do not keep our prompts” into one checkbox. They are not the same control.

| Policy question | Control | What it does not do |
|---|---|---|
| Where is the request decrypted and inferred? | In-region base URL + region Guardrails | Does not guarantee zero retention |
| Does the provider store prompts/completions after inference? | ZDR (`provider.zdr`, account, Guardrails) | Does not pin geography |
| May the provider train on stored inputs? | `data_collection: "deny"` / no-training filters | Does not equal ZDR by itself |
| Do we log prompts in our app? | Your logging policy | Not covered by vendor ZDR |
| May tools/plugins retain data? | Tool allowlists in your app | Not covered by inference ZDR |

A US lab model on the global host can still run outside the US. A ZDR request can still process outside your preferred country. A “we do not train on your data” promise can still allow temporary retention for abuse or legal review — and OpenRouter does not treat those retaining endpoints as ZDR. If the contract names a processing location **and** a retention rule, you need both routing knobs, plus your own log and tool policies.

![Region and ZDR as two separate policy controls](https://cdn.otf-kit.dev/blog/openrouter-in-region-zdr-owned-repo/inbody-01-controls-20260914a.jpg)

## Concrete changes builders should ship this week

Treat the following as product code work, not a settings screenshot in Slack.

### 1. Split the OpenRouter base URL by residency class

Stop hardcoding `https://openrouter.ai/api/v1` as the only client. Introduce a residency class on the tenant, workspace, or API-key scope you already use for billing and permissions:

```ts
type ResidencyClass = "global" | "us" | "eu"

const OPENROUTER_BASE: Record<ResidencyClass, string> = {
  global: "https://openrouter.ai/api/v1",
  us: "https://us.openrouter.ai/api/v1",
  eu: "https://eu.openrouter.ai/api/v1",
}

function openRouterBaseUrl(residency: ResidencyClass): string {
  return OPENROUTER_BASE[residency]
}
```

Wire that map behind one factory your agents and humans must use. Pair it with OpenRouter Guardrails that reject covered traffic on the wrong hostname, so a misconfigured deploy cannot “fix” residency by pointing at global.

### 2. Fail closed when the regional catalog cannot serve the model

Regional hosts return `404` when no in-region endpoint exists for the model. That is useful for compliance reviews. Catch it in your adapter, map it to a product error (“model unavailable in this data region”), and never retry the same prompt on `openrouter.ai` for a residency-bound tenant. Retries that cross hosts are the fastest way to break an audit narrative.

Keep a small, reviewed allowlist of models per residency class next to the app. Refresh it from the regional `/models` response on a schedule; do not paste marketing model names into production without checking the regional catalog.

### 3. Turn ZDR into an enforceable route flag

For surfaces that handle regulated or contractual content, set ZDR at the narrowest layer that matches the risk:

```json
{
  "model": "meta-llama/llama-3.3-70b-instruct",
  "messages": [{ "role": "user", "content": "Summarize the attached claim file." }],
  "provider": {
    "zdr": true,
    "data_collection": "deny"
  }
}
```

Prefer account or Guardrail ZDR for whole workspaces that must never leave ZDR, and use the per-request field when only some routes need it. OpenRouter composes these as OR: if any layer turns ZDR on, enforcement applies; the request flag cannot loosen a stricter account or Guardrail rule.

Remember the boundaries OpenRouter documents: provider-side in-memory prompt caching can still be compatible with ZDR; response caching is a separate storage path (account-level ZDR disables it; the per-request `zdr` field does not). Tools and plugins have their own operators — review them before you mark a workflow “zero retention.”

### 4. Cover what vendor ZDR does not

Vendor ZDR stops at the inference endpoint. Your product still decides:

- **Application logging** — prompts, redacted prompts, metadata only, retention windows, who can export.
- **Tool / plugin policy** — web search, fetch, MCP tools, and any path that can receive customer text after the model returns.
- **Evidence** — sample request paths (hostname, region failure mode, ZDR flag), links to the announcements, and the date of the last ZDR endpoint diff.

If those only live in a founder’s head or a page no agent reads, coding agents will keep pointing clients at the global host because that is what every tutorial shows.

![Logging and tool policy beside region and ZDR controls](https://cdn.otf-kit.dev/blog/openrouter-in-region-zdr-owned-repo/inbody-02-policy-20260914b.jpg)

### 5. Verify ZDR eligibility on a cadence

Put a job (or a release checklist step) that hits `https://openrouter.ai/api/v1/endpoints/zdr` and diffs against the model allowlist you pin in version control. When an endpoint drops off ZDR, fail the deploy or page the owner — do not wait for a customer questionnaire. The five verification questions from OpenRouter’s ZDR guide are worth encoding as acceptance criteria: what data is covered, per-provider vs per-endpoint scope, what falls outside (metadata, tools, caches, logs), how enforcement works, and how you re-check eligibility over time.

## Checklist to keep next to the app

Gateway features do not invent your compliance story. Keep these artifacts where the product ships:

1. **Residency matrix** — which tenants/workspaces are `us`, `eu`, or `global`, who may change that field, and which features are disabled under each class.
2. **Model allowlists per region** — reviewed lists, not “whatever the chat UI offers today.”
3. **ZDR surface map** — which routes require `zdr: true`, which may use non-ZDR endpoints, and which ban plugins entirely.
4. **Logging policy** — what the app stores, for how long, and who can export.
5. **Tool / plugin allowlist** — anything that can receive customer text after inference.
6. **Guardrail IDs and Management API config** — in env templates or infra-as-code so recreating a workspace does not lose region or ZDR pins.
7. **Audit evidence pack** — hostname samples, regional `404` behavior, ZDR flags, last endpoint-list diff date.

## Related OpenRouter surfaces (not substitutes)

OpenRouter’s September surface area is easy to blur. Keep three lines:

| Capability | Buys you | Still yours |
|---|---|---|
| US/EU in-region + ZDR | Geography and provider retention controls | Residency class, ZDR route map, logging, tool bans — this post |
| Hosted shell / Files API | Rented Linux seconds for tool-calling models | Network policy and promotion rules — [shell post](/blog/openrouter-shell-owned-repo) |
| Fusion | Multi-model deliberation on hard prompts | Escalation predicates and cost caps — [Fusion post](/blog/openrouter-fusion-selective-escalation) |

Two practical collisions matter for compliance teams:

- OpenRouter’s shell docs treat hosted shell as global-endpoint only today; in-region hosts reject it. Residency-bound tenants need a split: regional inference for prompts, and either a different executor or an explicit rule that shell stays off for those tenants.
- Fusion multiplies completions and can attach web tools. Pair it with ZDR and residency only after the panel path, judge, and tools all meet the same region and retention bar — or keep Fusion off those workspaces.

Do not “solve compliance” by renting a shell or by sending every prompt through a multi-model panel. Solve it by pinning hostname + ZDR + your own logs in code you review.

## A practical adoption sequence

1. Inventory tenants that have contractual residency or retention language. Tag them `us`, `eu`, or `global` in the same place you store plan entitlements.
2. Upgrade the OpenRouter plan if you need In-Region Routing, then create Guardrails that pin allowed data regions for those workspaces and keys.
3. Ship the base-URL factory and fail-closed regional `404` handling before you flip any production tenant.
4. Turn on account or Guardrail ZDR for the regulated surfaces; add `provider.zdr: true` on the remaining high-risk routes.
5. Disable or gate plugins/tools that can retain or exfiltrate prompts for those surfaces; re-read caching settings.
6. Add the ZDR endpoint list diff to CI or a weekly job; store the last green run as audit evidence.
7. Update customer questionnaires and your security FAQ with the exact hosts, the fail-closed behavior, and what ZDR does **not** cover (your logs, your tools).
8. Only then enable regional traffic for the first pilot tenant and watch for model `404`s against your allowlist.

## What not to do this week

- Do not claim “US/EU processing” while still calling `openrouter.ai` for those tenants.
- Do not treat a US lab brand name as a residency guarantee on the global host.
- Do not equate “no training” with ZDR, or ZDR with data residency.
- Do not retry a regional `404` on the global host for a residency-bound workspace.
- Do not enable shell, broad web tools, or Fusion on ZDR/residency tenants without a separate review.
- Do not leave residency and ZDR rules only in OpenRouter’s dashboard — encode them where your coding agents and humans actually ship changes.

US and EU in-region hosts plus enforceable ZDR change the default for compliance-bound products on OpenRouter: pick the hostname that matches the contract, require ZDR where retention is forbidden, verify endpoints on a cadence, and keep logging and tool bans under your own review. The gateway supplies the routing knobs. The product you ship still owns the split between geography and retention.

## Sources

- [In-Region Routing: Keep your data in the US or EU (OpenRouter, September 9, 2026)](https://openrouter.ai/blog/announcements/us-in-region-routing/)
- [Zero Data Retention (ZDR): What It Means for AI APIs (OpenRouter, September 11, 2026)](https://openrouter.ai/blog/insights/zero-data-retention/)
- [ZDR endpoints list (OpenRouter API)](https://openrouter.ai/api/v1/endpoints/zdr)
- Related internal posts: [OpenRouter hosted shell](/blog/openrouter-shell-owned-repo), [OpenRouter Fusion](/blog/openrouter-fusion-selective-escalation)
