Guides
What the OpenAI Chat Completions and Responses routes honor, drop, or refuse, and how structured output, prompt caching, reusable reasoning, provider fallback, and data retention behave when a model is served across several providers.
POST https://api-pr-2007.preview.experientiallabs.ai/v1/chat/completions and POST https://api-pr-2007.preview.experientiallabs.ai/v1/responses take the standard OpenAI request bodies. Every field is handled one of three ways:
x-experiential-ignored-parameters (on a stream the same key rides in the chunk that carries the finish). Examples: top_p on a rung that does not sample, text.verbosity and client_metadata on a non-OpenAI rung.400 with code: unsupported_parameter (no route serves it) or code: invalid_parameter (malformed) and param naming the field. Nothing is charged.Fields refused on every route today: audio, modalities, logit_bias, seed, functions / function_call, prediction, prompt_cache_retention, web_search_options, and the OpenRouter-style plugins, provider, and route objects. Hosted (non-function) tool types such as web_searchare carried only when every rung on the model's route is OpenAI's own Responses API (a BYOK OpenAI key); on any other route they are refused with param: tools. The gateway does not run a web search of its own. Unknown message-level keys (for example messages[].agent) are rejected exactly as OpenAI rejects them.
Chat Completions takes response_format with {"type":"json_object"} or {"type":"json_schema","json_schema":{"name","schema","strict"}}; the Responses API takes the same under text.format. Structured output is a per-rung capability the gateway learns by probing each provider, never by assertion. A rung that cannot honor it is skipped; if no rung on the model's route can, the request is refused with 400, code: unsupported_capability and param: response_format. The gateway never downgrades a schema request to prose silently.
curl "https://api-pr-2007.preview.experientiallabs.ai/v1/chat/completions" \-H "Authorization: Bearer $EXPLABS_API_KEY" \-H "Content-Type: application/json" \-d '{"model": "gpt-5.6-luna","max_tokens": 2048,"messages": [{"role": "user", "content": "Ada Lovelace was born in 1815 and died in 1852."}],"response_format": {"type": "json_schema", "json_schema": {"name": "person", "strict": true,"schema": {"type": "object", "properties": {"name": {"type": "string"}, "age": {"type": "integer"}}, "required": ["name", "age"], "additionalProperties": false}}}}'
strict: true: those providers enforce the schema themselves.max_tokens thinking. Too small a budget returns an empty content with finish_reason: "length" (a Responses call is marked incomplete). Raise max_tokens.person {name, age} schema on gpt-5.6-luna and glm-5.2. Some models honor json_object but not json_schema(for example deepseek-v4.1-flash); the model page's supported parameters say which.Caching is done by the provider, not by the gateway. The gateway forwards your request so the provider can reuse a repeated prefix, keeps a conversation on the same rung so the warm cache is not abandoned, and honors prompt_cache_key as a routing hint on rungs whose provider routes by it (the value itself never leaves the gateway). What the provider reports comes back unchanged:
usage.prompt_tokens_details.cached_tokensusage.input_tokens_details.cached_tokens/v1/messages): usage.cache_read_input_tokensCached input is billed at the model's cached rate, the Cached $/M price on the model page. Whether a prefix caches depends on the provider that served the request: OpenAI, Anthropic, DeepSeek, Novita, OpenRouter, and Tencent report cache hits, while some providers (Azure-hosted third-party models, for example) report none. The top-level provider field on every finished completion names the rung that served, so a cached_tokens: 0 can be attributed to the provider that answered.
# Send the same long system prompt twice; the second call reports the cache hit.curl -s "https://api-pr-2007.preview.experientiallabs.ai/v1/chat/completions" \-H "Authorization: Bearer $EXPLABS_API_KEY" \-H "Content-Type: application/json" \-d '{"model": "gpt-5.6-luna", "messages": [{"role": "system", "content": "<your long, unchanging system prompt>"}, {"role": "user", "content": "Hello"}]}' \| jq '{provider, cached: .usage.prompt_tokens_details.cached_tokens, cost: .usage.cost}'
On the Responses API, include: ["reasoning.encrypted_content"] returns the model's reasoning as encrypted items you replay in later turns, so a multi-turn agent keeps its hidden reasoning without the gateway storing anything.
curl "https://api-pr-2007.preview.experientiallabs.ai/v1/responses" \-H "Authorization: Bearer $EXPLABS_API_KEY" \-H "Content-Type: application/json" \-d '{"model": "gpt-5.6-luna","store": false,"include": ["reasoning.encrypted_content"],"reasoning": {"effort": "medium"},"input": [{"role": "user", "content": "Plan the first step, then stop."}]}'# Replay the returned output items (including type: reasoning) as input on the next turn.
previous_response_id continuation works on any gateway worker for 30 days from the last turn, and only while your organization keeps prompt capture on (see Data controls). An unknown or expired id gets an explicit 400 previous_response_not_found asking you to resend the full conversation, never silent state.x-gateway-replay-repair: encrypted_reasoning_stripped. Your messages, tool calls, and tool results are kept; only that hidden reasoning continuity is lost.Every model resolves through a platform-managed waterfall of provider rungs. A provider error, a throttle, or a timeout waiting for the response headers or the first token fails the request over to the next rung automatically, before any rung has committed to the request. Once a rung commits, the response comes from that rung and the top-level provider field on the finished completion names it.
429 to you instead of moving to a cold rung, so the cache you paid to warm is not thrown away. A cold conversation fails over.You cannot reorder the platform's rungs, and the OpenRouter provider.order and routefields are refused. An organization with its own provider keys (BYOK) orders its own rungs per model from the model page ("Ways to use") or with PUT /api/models/{slug}/waterfall. How rungs are ordered, what falls back, and what BYOK changes is in The waterfall.
GET https://api-pr-2007.preview.experientiallabs.ai/api/models/{slug} returns a retention verdict for the model, folded over the platform rungs its active route actually serves (a rung the route skips never counts). GET https://api-pr-2007.preview.experientiallabs.ai/api/models?retention=zdr_all_rungs or ?retention=zdr_enforceable lists only the models that meet that bar.
| retention | Meaning |
|---|---|
| zdr_all_rungs | Every platform rung the active route serves resolves to zero data retention. Whichever rung answers, the provider keeps nothing. |
| zdr_enforceable | At least one platform rung is zero-data-retention, but not all. Failover can move a request onto a rung with different terms unless your organization's require-ZDR provider policy is on, which keeps the model on a compliant route. |
| not_zdr | No platform rung on the route is zero-data-retention. |
The verdict is nullfor a model with no platform rungs (your organization's own models). Because fallback can change which provider answers, a zdr_enforceable model is only guaranteed zero-data-retention when the require-ZDR policy is set; the policy, the response headers that name the serving provider, and what the gateway itself stores are in Data controls.
The gate errors an OpenAI client meets on the platform, all in the standard OpenAI error envelope with a stable code:
| Status and code | What it means |
|---|---|
| 429 insufficient_quota | Your organization is out of platform credits; the message carries the balance. Add credits or serve the model on your own provider key. |
| 429 card_required | Your organization has not yet unlocked platform-credit spend: the owner must complete the $1 card verification (credited back to the balance). The message links the verify page. Your own provider keys (BYOK) work regardless. |
| 429 free_limit_reached | The model's free-tier allowance is spent for this window. The message names the limit and its reset when one exists. |
| 429 model_requires_payment / model_requires_purchase | Every lane of this model your organization can reach needs a verified card (a completed top-up, the $1 verification counts) or a real credit purchase. The message names the remedy. |
| 400 unsupported_capability | No rung on the model's route can honor a capability the request asked for; param names the field (response_format for structured output). Pick a model whose supported parameters include it. |
| 400 unsupported_parameter / invalid_parameter | One field is refused on every route (unsupported_parameter) or malformed (invalid_parameter); param names it. Remove or fix the field and resend. |
The full code table, the envelope, and what is safe to retry are in Errors.
The Anthropic API page covers the same models over /v1/messages. The full route surface is in the API reference.