OpenAI's chat completions API became the shape most tools speak: a POST to /v1/chat/completions with a model name and a list of messages, a response with choices, a usage block of token counts, and streaming as server-sent events. Vendors, inference servers and gateways adopted the same shape so that the SDKs, frameworks and products already written against it would work unchanged. 'OpenAI-compatible' means: point the client's base URL here, give it this key, keep the code.
The standard is informal and has a core and edges. The core - messages, model, temperature, max tokens, streaming, tool definitions and tool calls, response format for structured output, the embeddings endpoint and the models list - is widely honoured. The edges vary: vision inputs, audio, reasoning-effort parameters, cached-prefix accounting, vendor-specific fields in usage. A compatible service documents which it supports and passes unknown fields through or ignores them explicitly.
For a router the compatible endpoint is how it gets into an existing stack without a rewrite. The application keeps its client; the router receives the request, decides which model should answer and forwards it in that vendor's dialect, then returns the answer in the OpenAI shape with the real model's name in the response. A model value of 'auto' hands the decision over entirely; a concrete model name pins it; a name with an at-sign - a model at a named provider - pins the endpoint too.
Compatibility also runs the other way. This router's served endpoint accepts the Anthropic messages dialect alongside OpenAI's, so clients written for either vendor can route; the TypeScript and Python SDKs wrap both. What a compatible endpoint cannot hide is a capability a chosen model lacks - a tool call sent to a model without tool support must be routed around, which is a routing concern, not a protocol one.