Docs
Status
OverviewQuickstartSetup promptsThe core loopAuthenticationOverviewModelsThe waterfallAdding modelsData controlsOpenAI compatibilityAnthropic APIErrorsIntegrate the gatewayCost APIAccount APICoding agentsCredits & billingSpend & intelligenceTelemetryBecome a providerProvider guideAPI reference

Get started

  • Overview
  • Quickstart
  • Setup prompts
  • The core loop
  • Authentication

Guides

  • Overview
  • Models
  • The waterfall
  • Adding models
  • Data controls
  • OpenAI compatibility
  • Anthropic API
  • Errors

Integrations

  • Integrate the gateway
  • Cost API
  • Account API
  • Coding agents

Billing & usage

  • Credits & billing
  • Spend & intelligence
  • Telemetry

Providers

  • Become a provider
  • Provider guide

Reference

  • API reference
PreviousData controlsNextAnthropic API

Guides

OpenAI compatibility

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.

Request fields

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:

  • Honoredon the rung that serves the request, when that rung's provider supports it.
  • Dropped with disclosure when the serving rung cannot honor it but the request is otherwise servable: the field is removed and named in the top-level response body array 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.
  • Refused before the request is admitted, as a 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.

Structured output

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.

response_format: json_schema
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}
}}
}'
  • On providers other than OpenAI, set strict: true: those providers enforce the schema themselves.
  • A reasoning model spends part of max_tokens thinking. Too small a budget returns an empty content with finish_reason: "length" (a Responses call is marked incomplete). Raise max_tokens.
  • Verified with a 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.

Prompt caching

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:

  • Chat Completions: usage.prompt_tokens_details.cached_tokens
  • Responses: usage.input_tokens_details.cached_tokens
  • Messages (/v1/messages): usage.cache_read_input_tokens

Cached 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.

Reading cached_tokens and provider
# 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}'

Reusable reasoning

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.

include: reasoning.encrypted_content
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.
  • An encrypted reasoning item is sealed by the provider account that produced it. Replay one sealed by another provider or organization and the gateway strips it, re-dials once, and discloses the repair in the response header x-gateway-replay-repair: encrypted_reasoning_stripped. Your messages, tool calls, and tool results are kept; only that hidden reasoning continuity is lost.

Provider fallback

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.

A throttle is the one exception a warm cache can override: when your organization's recent traffic on the throttled rung was mostly cache hits, the gateway returns the 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.

Data retention per model

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.

retentionMeaning
zdr_all_rungsEvery platform rung the active route serves resolves to zero data retention. Whichever rung answers, the provider keeps nothing.
zdr_enforceableAt 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_zdrNo 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.

Errors you will see

The gate errors an OpenAI client meets on the platform, all in the standard OpenAI error envelope with a stable code:

Status and codeWhat it means
429 insufficient_quotaYour organization is out of platform credits; the message carries the balance. Add credits or serve the model on your own provider key.
429 card_requiredYour 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_reachedThe 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_purchaseEvery 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_capabilityNo 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_parameterOne 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.

See also

The Anthropic API page covers the same models over /v1/messages. The full route surface is in the API reference.