Product Surfaces
The exact routes an issued key reaches, the wire shapes they speak, the model vocabulary they accept, and the fields they refuse.
Product Surfaces
The AI Gateway's product boundary is an allowlist of routes. A DevZero issued key reaches exactly these, and the published contract mirrors the allowlist one-to-one -- there is no editorial trimming and nothing outside it is part of the product.
Inference routes
| Route | Wire shape | Notes |
|---|---|---|
POST /v1/chat/completions | OpenAI Chat Completions | The OpenAI-compatible surface. Gemini-shaped callers use this route too. |
POST /v1/responses | OpenAI Responses | |
POST /v1/messages | Native Anthropic Messages | On the Anthropic listener. Anthropic prompt caching (cache_control) passes through unchanged while the compression pipeline is off; with it enabled the lossless cache_align transform may add or relocate the breakpoint to the end of the stable prefix. Either way a Claude Code harness reaches the product by base-URL swap. |
Stored-response state operations
| Route | Purpose |
|---|---|
GET /v1/responses/{response_id} | Retrieve a stored response. |
DELETE /v1/responses/{response_id} | Delete a stored response. |
GET /v1/responses/{response_id}/input_items | List a stored response's input items. |
DELETE /v1/responses/{response_id}/input_items | Forwarded verbatim; the upstream's own answer, including "not supported", is returned unmodified. |
State operations are not inference: no model, no routing decision, no governance gate and no caching. A stored response is mutable server-side state, and these routes go to the account whose credential created it.
Why hostnames, not paths
The OpenAI-compatible surface and the OpenAI native surface publish the same method and paths to different upstreams. Nothing downstream can separate them by path, so hostname or port is the only discriminator -- which is why the surfaces cannot be collapsed onto one listener.
A hosted install is reached through one gateway on :443, multiplexed by
hostname: a base host plus anthropic-, gemini- and openai- prefixed
variants of it. A self-hosted install can opt into the same shape with the
chart's ingress values, which derive the three native hostnames by prefixing the
base host exactly as the hosted provisioner does. It is off by default; without
it, clients address the listener ports directly.
What is deliberately outside the contract
- Passthrough listener traffic -- anything off the routes above.
- WebSocket relays.
POST /v1/messages/count_tokens.
These keep their existing behaviour. They are not broken and not deprecated; they are simply not the product surface, and the published contract makes no promise about them.
Model vocabulary
The model field uses the gateway's catalog vocabulary, author/slug:
anthropic/claude-sonnet-4-5
openai/gpt-4o| Input | Outcome |
|---|---|
A well-formed author/slug id the upstream knows | Served. |
A native vendor spelling, e.g. gpt-4o | Rejected with invalid_model_id. |
| A well-formed id the serving upstream does not know | Rejected with model_not_found. |
Variant suffixes, e.g. :free | Not supported. |
No model at all | The gateway resolves your team's configured default. If no rung of the profile ladder configures one, the request fails with no_default_model -- never a platform default. |
The contract requires model, and new integrations should always send it. The
default-resolution behaviour exists so integrations that predate the contract
keep working, not as a recommended pattern. An explicitly named model is never
substituted.
The pattern for a model id is ^[A-Za-z0-9._-]+/[A-Za-z0-9._-]+$, maximum 256
characters.
Refused body fields
The upstream marketplace's own routing knobs are refused at the top level of
every inference body, with 400 unsupported_routing_field:
provider models route transforms preset pluginsExpress routing intent through dz_router
instead, or configure it server-side as a
routing profile.
Everything else in the body is vendor-owned and passes through unpoliced. Use your vendor SDK's own types: the contract is deliberately loose there so a new vendor field is never blocked by DevZero's schema.
Calling a surface
Point the official openai SDK at your gateway and authenticate with an
issued key. Gateway controls ride X-Dz-* request headers, so the SDK's
own default_headers parameter drives all of them.
from openai import OpenAI
client = OpenAI(
base_url="https://<your-gateway-host>/v1",
api_key="sk-dz-...",
default_headers={"X-Dz-Project": "checkout"},
)
resp = client.chat.completions.create(
model="anthropic/claude-sonnet-4-5",
messages=[{"role": "user", "content": "Hello"}],
)<your-gateway-host> is a placeholder. There is deliberately no default
gateway hostname in the published contract -- nothing should silently point at
an endpoint that is not yours. Your gateway's own URL is shown on its source
detail in the dashboard, and the install flow hands it to you.
Errors
Refusals on the keyed surface use the OpenAI error envelope, and error.code
names the outcome:
| Code | Cause |
|---|---|
invalid_model_id | The model value is not in author/slug form. |
model_not_found | A well-formed id the serving upstream does not know. |
no_default_model | No model was sent and no rung of the profile ladder configures one. |
invalid_dz_router | A malformed override, a repeated X-Dz-Router header, or an unknown field inside the override. |
dz_router_conflict | The override was presented on both carriers. |
dz_router_too_large | The X-Dz-Router header exceeded 8192 bytes. |
unsupported_routing_field | The body carried one of the refused upstream routing fields. |
routing_override_not_permitted | The override tried to enable a substitution mode the profile does not permit. |
auto_not_enabled | auto was requested but no rung enables it. |
Upstream-side failures return a provider-neutral envelope with the upstream's
own detail attached under dz_upstream. Two outcomes worth knowing by name:
502 unknown_upstream-- the request named an upstream connector this installation has not enabled.503 upstream_undetermined-- the routing profile could not be read and the installation has more than one upstream registered, so the request is refused rather than defaulted. It is retryable.
Keys and Credentials
The three kinds of credential in play -- issued keys, your own provider credentials, and DevZero-provisioned managed keys -- and which one pays.
Request Headers
The X-Dz-* request headers that drive attribution, session identity and per-request routing, and the two headers the gateway returns.