Zalmir accepts the OpenAI chat format. Fields the gateway does not use itself are passed to the model unchanged; whether a model honors them depends on the model. Add "provider": { "require_parameters": true } to use only endpoints that list support for every parameter you send.
Structured outputs
response_format takes json_object or json_schema.
curl "$BASE_URL/chat/completions" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "<model id>",
"messages": [{ "role": "user", "content": "Name a city and its country." }],
"response_format": {
"type": "json_schema",
"json_schema": {
"name": "place",
"strict": true,
"schema": {
"type": "object",
"properties": { "city": { "type": "string" }, "country": { "type": "string" } },
"required": ["city", "country"],
"additionalProperties": false
}
}
},
"provider": { "require_parameters": true }
}'Tool calling
Send tools and tool_choice; the model answers with tool_calls. Zalmir never runs tools: you run them and send the result back as a tool message. Responses carry X-Zalmir-Tool-Execution: none.
curl "$BASE_URL/chat/completions" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "<model id>",
"messages": [{ "role": "user", "content": "What is the weather in Paris?" }],
"tools": [{
"type": "function",
"function": {
"name": "get_weather",
"parameters": { "type": "object", "properties": { "city": { "type": "string" } }, "required": ["city"] }
}
}],
"tool_choice": "auto"
}'Images
Message content can mix text and image_url parts. Zalmir passes the URL to the model and does not fetch it. Other part types are refused with 400 invalid_request.
curl "$BASE_URL/chat/completions" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "<vision model id>",
"messages": [{
"role": "user",
"content": [
{ "type": "text", "text": "Describe this image." },
{ "type": "image_url", "image_url": { "url": "https://example.com/photo.jpg" } }
]
}]
}'Reasoning
reasoning_effort is passed to the model.
curl "$BASE_URL/chat/completions" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "<reasoning model id>",
"messages": [{ "role": "user", "content": "Plan a three-step test." }],
"reasoning_effort": "high"
}'Output length and choices
max_tokens or max_completion_tokens sets the output cap, from 1 up to the endpoint's limit; if you send both they must match. Only n: 1 is supported.
Responses API
POST /v1/responses runs statelessly over chat. instructions becomes a system message, max_output_tokens the output cap, and text.format may be text, json_object or json_schema. Function tools work; built-in tools do not. store must be false, and previous_response_id, conversation and background are refused.
curl "$BASE_URL/responses" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "<model id>",
"instructions": "Answer in one sentence.",
"input": "What is an API key?",
"text": { "format": { "type": "text" } }
}'Legacy completions
POST /v1/completions takes one string prompt. suffix, echo, best_of, logprobs and token-array prompts are refused.
Streaming
With "stream": true, Zalmir reads the whole answer, checks the seller's signature and charges for it, then sends it as server-sent events. You get the complete answer as the first chunk, not token by token. stream_options.include_usage adds a usage chunk. The Responses API streams named events with sequence_number.
Not supported yet
- Embeddings:
POST /v1/embeddingsreturns400 embeddings_unsupported. - Token-by-token streaming.
- Stored or background responses.
Every endpoint and field: API reference.