Cookbook

Chat completion with curl

The smallest end-to-end call against ezrouter's OpenAI-compatible surface. Run this from any shell with curl installed.

bash
curl https://www.ezrouter.dev/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer ${EZROUTER_API_KEY}" \
  -d '{
        "model": "claude-sonnet-4-6",
        "messages": [
          {"role": "system", "content": "You are a helpful assistant."},
          {"role": "user", "content": "Hello!"}
        ]
      }'

Set EZROUTER_API_KEY to a key from the dashboard before running. The response streams as Server-Sent Events even though stream was not set in the body — see divergences.

Reading the SSE stream

curl prints the SSE frames directly. Each frame looks like:

text
data: {"id":"msg_01...","object":"chat.completion.chunk","choices":[{"delta":{"content":"Hi"}}]}

The terminator is data: [DONE]. To consume the stream programmatically, parse each data: {...} line as JSON; if a line equals data: [DONE], stop. To collect the final response into one JSON object, add --no-buffer and pipe through a small filter:

bash
curl --no-buffer -sS https://www.ezrouter.dev/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer ${EZROUTER_API_KEY}" \
  -d '{ "model": "claude-sonnet-4-6", "messages": [
        {"role": "user", "content": "Hello"} ]}' \
  | grep --line-buffered '^data: ' \
  | grep --line-buffered -v '^data: \[DONE\]' \
  | sed 's/^data: //' \
  | jq -s 'map(.choices[0].delta.content // "") | join("")'

That prints the assembled assistant message as a single JSON string.

Common variations

Switch the model. Pass any ID from GET /v1/models:

bash
-d '{ "model": "deepseek-v4-pro", "messages": [...] }'

Cap output length.

bash
-d '{ "model": "claude-haiku-4-5", "max_tokens": 256, "messages": [...] }'

Send a system prompt. The first message with role: "system".

Multi-turn conversation. Append every prior turn to messages:

bash
-d '{
  "model": "claude-sonnet-4-6",
  "messages": [
    {"role": "user", "content": "What is 2+2?"},
    {"role": "assistant", "content": "4."},
    {"role": "user", "content": "And 3+3?"}
  ]
}'

See multi-round chat for the full pattern.

Error handling

A non-200 response carries a JSON error envelope, not an SSE stream:

json
{"error": {"code": "invalid_api_key", "message": "Invalid API key.", "type": "authentication_error"}}

The typed values you may see are documented in error codes. Do not write retry-on-429 logic — the gateway does not return 429; under load it queues silently and you see longer latency instead.

Next steps

every parameter explained.