“OpenAI-compatible” is on many product pages and means different things on each of them. For
some, it means a chat endpoint that takes a messages array. For others, it means the official
SDK works if you squint. We would rather be precise, because the phrase is a promise about your
code, and you will find out quickly whether it was kept.
Here is what it means on Zarx, and how to check.
The one-line change
The promise, stated as a test: take an application written against api.openai.com, change the
base URL and the API key, change the model id to one from our catalog, and the application keeps
working.
from openai import OpenAI
client = OpenAI(
base_url="https://api.zarx.ai/v1",
api_key=ZARX_API_KEY,
)
response = client.responses.create(
model="glm-5.2",
input="Summarise this incident report in three bullet points.",
)
print(response.output_text)
The base URL shown is the design target for early access; partners receive their endpoint and keys when onboarded. Everything else in the snippet is the unmodified openai SDK.
Endpoints
Zarx is the gateway NPAW runs in production for its own products, opened to design partners. The endpoints below exist and are documented; we do not list anything that is not implemented.
POST /v1/responsesis the primary endpoint. It implements the OpenAI Responses API with identical request and response shapes: string or chat-arrayinput,instructions,tools,text.formatincluding strict JSON schema,metadata,store,truncation, andprevious_response_idfor server-side conversation chaining.POST /v1/chat/completionsserves the Chat Completions shape (choices,message,usagewith prompt, completion and total tokens) for the models we run ourselves, for code that has not moved to Responses yet.GET /v1/modelslists the models available to your key, including the reasoning effort levels each one supports.GET,POST .../cancelandDELETEon/v1/responses/:id, andGET /v1/responses/:id/input_items, behave as documented by OpenAI.POST /v1/batcheswithPOST /v1/files(purpose: "batch") gives you the asynchronous Batch API for the models we run ourselves.
Streaming
Set "stream": true and read text/event-stream. Every event is the official OpenAI Responses
event: the same event: name, the same data: JSON with the same type, and a monotonically
increasing sequence_number. The sequence for a plain text reply is response.created,
response.in_progress, response.output_item.added, response.content_part.added, a run of
response.output_text.delta, then response.output_text.done, response.content_part.done,
response.output_item.done and finally response.completed with the full usage. Errors end the
stream with response.failed.
Chunks are relayed as the model produces them; nothing is buffered between the GPU and your
client. Streaming code written against api.openai.com runs unchanged.
curl -N https://api.zarx.ai/v1/responses \
-H "Authorization: Bearer $ZARX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "kimi-k2.6",
"input": "List the questions a bank should ask an inference provider about data residency.",
"stream": true
}'
Tools, structure, retries, errors
Function calling works the way you expect: declare tools of type function, control selection
with tool_choice and parallel_tool_calls, receive the call, reply with the result. Structured
output with text.format = { type: "json_schema", schema, strict } validates the model’s answer
against your schema, which is what a downstream system needs when it cannot tolerate prose.
An Idempotency-Key header makes retries safe: the same key returns the same response id. Errors
come back in the OpenAI envelope, { error: { message, type, code, param } }, with the usual HTTP
status codes, and the official SDKs raise the exceptions you already handle.
What is different, and what is missing
Some things are deliberately different, and a few are not there yet. We would rather you read them here than discover them in staging.
- Authentication. Send your key as
Authorization: Bearer <key>, exactly as with OpenAI. The gateway also accepts anX-API-Keyheader if your HTTP client prefers it. - Model ids are ours, not OpenAI’s.
GET /v1/modelsis the source of truth. - No hosted tools. There is no
web_search,file_searchorcode_interpreter. Use afunctiontool and your own backend; it keeps your data on your side anyway. - No background mode. For long requests use an
Idempotency-Keyand retry. - Usage accounting is per key. Every request is recorded with its model and token counts and
rolled up per key and model by hour and by day. Limits (requests per minute, tokens per minute,
daily tokens, monthly spend) can be set per key, per model or per account, and a hard limit
returns an OpenAI-shaped
429withRetry-After.
How to verify it in an afternoon
- Point your existing integration tests at the Zarx base URL with a Zarx key and a model from
GET /v1/models. - Run the streaming path and assert on event names, not on timing.
- Run one structured-output request with
strict: trueand validate the JSON against your schema. - Send the same request twice with one
Idempotency-Keyand check you get the same response id. - Read the usage in
response.completedand compare it with what your account shows.
If any step fails, that is a bug on our side or a gap in this list, and we want to hear about it. Request access and we will get you a key.