What lock-in actually looks like with an LLM API
Lock-in with an LLM integration rarely shows up as a contract clause — it shows up as code. Build directly against one provider's SDK and its request shape, its streaming format, its tool-call schema, and its error codes end up threaded through your app. Moving to a second provider later means rewriting all of it, not just changing a config value.
A routing layer can make this worse or better depending on what it stands on. If the layer invents its own proprietary request format, you've just moved the lock-in one level up — now you depend on the router's dialect instead of a provider's. If it implements the *standard* dialects instead, the code you write is portable by construction.
Standing on the standard, not a proprietary layer
AnyRouter implements the request shapes that already exist rather than inventing a new one: OpenAI's Chat Completions, Anthropic's Messages, and OpenAI's newer Responses API, all on one endpoint. Whichever SDK your codebase already speaks keeps working unchanged.
| Dialect | Endpoint | For |
|---|---|---|
| OpenAI chat | /api/v1/chat/completions | Drop-in for OpenAI's chat SDK |
| Anthropic messages | /api/v1/messages | Drop-in for Claude clients |
| OpenAI Responses | /api/v1/responses | The newer OpenAI Responses surface |
| Embeddings | /api/v1/embeddings | OpenAI-style vector embeddings |
Because these are public standards rather than a house format, the same client code that talks to AnyRouter also talks to the origin API — nothing about your integration is AnyRouter-specific.
A two-line swap, and a two-line swap back
Pointing an existing OpenAI client at AnyRouter changes the base URL and the key — nothing else:
from openai import OpenAI
client = OpenAI(
base_url="https://anyrouter.dev/api/v1", # was https://api.openai.com/v1
api_key="sk-ar-v1-...",
)
resp = client.chat.completions.create(
model="openai/gpt-5.5",
messages=[{"role": "user", "content": "Hello"}],
)Reversing it is the same two lines in the other direction. That symmetry is the actual test for lock-in: if leaving costs the same two-line diff as arriving did, you were never locked in.
Model choice becomes a config value
Model ids are provider/model strings across 170+ models from 28+ providers, so switching models is editing a string, not re-integrating a new SDK, a new auth scheme, and a new error-handling path. anthropic/claude-opus-4-8 today, google/gemini-2.5-pro tomorrow — same client, same key, same endpoint.

Owning your keys keeps the exit open too
The deepest form of lock-in is a billing relationship you can't leave. $0-markup BYOK avoids that: attach your own provider keys and AnyRouter charges nothing on top — no per-request fee, no surcharge, you pay only the provider. That means the underlying provider relationship is still yours, not intermediated.
- Standard dialects only — Chat Completions, Messages, Responses, Embeddings — no proprietary request format to depend on.
- Model ids are config values (
provider/model), not SDK integrations. - $0-markup BYOK keeps the provider billing relationship yours.
- The same client code works pointed at the origin provider — the swap back is as cheap as the swap in.
Route on the standard API surface — no proprietary dialect, no lock-in.
Get a key freeRoute your first request in 2 minutes
Start free with your own keys, or top up and pay per token. Get $4/mo in credits and free models on Go — $2/mo, or free when you donate a provider key.
Start free