Skip to content

AI Gateway OpenAI Compatibility

Varity Team Core Contributors Updated August 2026

“OpenAI-compatible” is a claim about a surface, not a promise about all of it. This page states the boundary. An exclusion you discover at runtime instead of reading it here is a documentation bug. If you hit one, report it.

Everything below was checked against the live gateway at https://varity.app/v1.

EndpointStatus
POST /v1/chat/completionsSupported. Requires a bearer API key.
GET /v1/modelsSupported. Public, no key required.
GET /v1/models/{id}Not implemented. Returns 404. Fetch the list and filter client-side.
POST /v1/completions (legacy text completions)Not implemented. Returns 404.
POST /v1/responsesNot implemented. Returns 404.
POST /v1/embeddingsNot implemented. Returns 404.
/v1/assistantsNot implemented. Returns 404.
/v1/filesNot implemented. Returns 404.
/v1/vector_storesNot implemented. Returns 404.
POST /v1/images/generationsNot implemented. Returns 404.
POST /v1/audio/speechNot implemented. Returns 404.
POST /v1/audio/transcriptionsNot implemented. Returns 404.
POST /v1/moderationsNot implemented. Returns 404.
/v1/batchesNot implemented. Returns 404.
/v1/fine_tuning/jobsNot implemented. Returns 404.

Beyond the OpenAI surface, the gateway serves its own endpoints. These have no OpenAI equivalent, so a client written against the OpenAI spec will not find them, but they are public and stable.

EndpointStatus
GET /v1/openapi.jsonSupported. Public, no key required. The machine-readable contract for this surface, including the data-handling block below.
GET /v1/inference/requestsSupported. Requires a bearer API key. Per-request metadata.
GET /v1/inference/usageSupported. Requires a bearer API key.
GET /v1/inference/policySupported. Requires a bearer API key.
GET /v1/inference/performanceSupported. Requires a bearer API key. Accepts window of 1h, 24h, 7d, or 30d.

For the OpenAI-compatible surface, the gateway is a chat-completions gateway. Text generation is the product; embeddings, files, assistants, batch, fine-tuning, images, audio, and moderation are not part of it. Unimplemented routes return an HTML 404 page, not a JSON error envelope. A client that assumes every failure parses as JSON throws a parse error rather than surfacing a clean status. Branch on the HTTP status code, not on the body.

A non-/v1 health probe is also available:

EndpointStatus
GET /healthSupported. Public. Returns {"status":"healthy","service":"varity-gateway","version":"1.13.49"}.

Compatibility is not uniform across models. Each catalog entry carries a capabilities object, and you must read it. The same request that works against one model can be unsupported on another.

CapabilityModels supporting it
chat_completions42 of 42
streaming42 of 42
tool_calls11 of 42
streaming_tool_calls7 of 42

Tool calling is the exception, not the default

Section titled “Tool calling is the exception, not the default”

Only 11 of the 42 models accept tools / tool_choice. If your agent framework assumes function calling works everywhere, as most do, it will break on the other 31. These are the models reporting tool_calls: true:

Model IDNameTool calls while streaming
model-01e5cfb9cd019cee62a62b13Gemma 4 UncensoredYes
model-afb55f3c0379fce9fb050497Google Gemma 3 27B InstructNo
model-1bcd5b1a9fc32ffb985afc6bGrok 4.20Yes
model-4e27cf37044481968f24c858Grok 4.3Yes
model-7ac496866ed390aa843e23eaGrok 4.5Yes
model-0bf4d9df75eb028b048a51edGrok Build 0.1Yes
model-c09137265edddbdec9dfda8bLlama 3.2 3BNo
llama-3-3-70bLlama 3.3 70BNo
model-ca8c32ffa3e6ec1adee98495Mistral Small 3.2 24B InstructNo
model-38c8e473186cf182a89ee7ffRole Play UncensoredYes
model-665e90a28adb3a74b27bb064Uncensored 1.2Yes

Four of those eleven support tool calls only in non-streaming mode (tool_calls: true, streaming_tool_calls: false): llama-3-3-70b, model-afb55f3c0379fce9fb050497, model-c09137265edddbdec9dfda8b, and model-ca8c32ffa3e6ec1adee98495. Combining stream: true with tools on those is outside the supported surface. Drop stream or pick a model from the seven that report streaming_tool_calls: true.

Resolve this at runtime rather than hardcoding:

models = {m["id"]: m for m in client.models.list().model_dump()["data"]}
def supports_tools(model_id, streaming=False):
caps = models[model_id]["capabilities"]
return caps["streaming_tool_calls"] if streaming else caps["tool_calls"]

Varity model ids are not OpenAI model ids. There is no gpt-4o, no gpt-3.5-turbo, and no aliasing layer that maps OpenAI names onto Varity models. A request naming an OpenAI model id is a request for a model that does not exist here.

Most ids are opaque, in the form model-<hex>; a handful are readable, such as glm-5-1, glm-5-2, llama-3-3-70b, and qwen-3-5-35b-a3b. Always take ids from the catalog.

  • max_completion_tokens is per-model and often small. Values in the catalog run from 4,096 up to 131,072, independent of the context window (which runs from 128,000 to 2,000,000). A 2M-token context does not mean a long reply is allowed.
  • No cached-input discount. Every model returns cached_input equal to input. Prompt caching does not currently reduce price.
  • Rate limits are advertised in response headers. GET /v1/models returns ratelimit-limit: 120 with ratelimit-policy: 120;w=60. Read ratelimit-remaining and ratelimit-reset at runtime instead of assuming a fixed budget.

The error envelope matches OpenAI’s shape and adds two fields:

{
"error": {
"message": "The API key is invalid or revoked.",
"type": "authentication_error",
"code": "invalid_api_key",
"param": null,
"retryable": false,
"request_id": "626e1d39-9b9b-46d6-8781-1dc280dfe85c"
}
}
  • retryable is a boolean OpenAI does not send. Use it instead of guessing from the status code whether to retry.
  • request_id is also returned as the x-request-id response header on every response, successful or not.

Observed authentication codes:

ConditionStatuscode
No Authorization header401authentication_required
Invalid or revoked key401invalid_api_key

Authentication is evaluated before request-body validation, so an unauthenticated request with an invalid model returns the authentication error, not a model error. Do not use the error type to infer that your payload was accepted.

The gateway publishes its data-handling contract as an x-varity-data-handling block at the root of GET /v1/openapi.json. It is machine-readable, so you can assert against it in CI rather than taking a page’s word for it.

FieldValue
inference_metadata_retention_days30
stored_content[]
content_never_storedprompts, responses, tool_arguments, uploaded_content, playground_conversations
financial_and_security_recordsseparate_retention_classes

Prompt and response bodies are never written to the inference records. What is retained for 30 days is request metadata: model and provider identifiers, token counts, latency, fallback count, error code, and timestamps. Read it back with GET /v1/inference/requests.

This is the property usually searched for as zero data retention, or ZDR.

Every model in the catalog reports privacy: "private" with privacy_routes: ["private"]. This field has no OpenAI equivalent; it is Varity-specific catalog metadata describing how the model is routed. There is currently no non-private route to choose between.