ZalmirBeta

Requests and outputs

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/embeddings returns 400 embeddings_unsupported.
  • Token-by-token streaming.
  • Stored or background responses.

Every endpoint and field: API reference.