Skip to content

POST /v1/chat/completions

The single client-facing LLM endpoint. OpenAI Chat Completions-compatible.

Request

Headers

Header Required Notes
Authorization yes Bearer <SMART_GATEWAY_API_KEY>
Content-Type yes application/json
X-Smart-Gateway-Session recommended Stable session ID.
X-Smart-Gateway-Goal recommended Goal ID inside the session.
X-Task-Id optional Per-request task ID.
X-Goal-Id optional Per-request goal ID.
X-Pro optional Force Pro routing.
X-Scout optional true to invoke Scout first.
X-Failure-Class optional STRUCTURAL, LOCAL, or NONE.
X-Same-Error-Count optional Integer.

Body

{
  "model": "smart-router",
  "messages": [
    {"role": "user", "content": "Reply with the word PONG."}
  ],
  "temperature": 0.2,
  "top_p": 1.0,
  "max_tokens": 8,
  "stream": false,
  "metadata": {
    "sensitive": true,
    "session_id": "proj-A-2026-08-23",
    "goal_id": "fix-flaky",
    "task_id": "task-17"
  }
}

Field summary:

Field Type Notes
model string One of smart-router, smart-router-flash, smart-router-pro, smart-router-free.
messages array OpenAI chat completion messages.
stream bool SSE if true.
temperature number Optional.
top_p number Optional.
max_tokens integer Optional.
stop string or array Optional.
tools array OpenAI function-calling tool definitions. Forwarded unchanged.
tool_choice string or object Forwarded unchanged.
response_format object Forwarded unchanged. JSON-mode works.
metadata object Gateway-specific routing metadata.
user string Optional. Forwarded.

The gateway also accepts any other OpenAI Chat Completions field and forwards it unchanged. Unknown fields are passed through; the gateway does not validate them. OpenRouter will reject unsupported fields with 400.

metadata

Key Type Default Effect
sensitive bool true Required to be false for free models on non-private work.
reasoning string auto high forces Pro (unless blocked by budget soft cap).
routing string auto Hint, not a control. pro/flash/free honored if compatible with privacy.
session_id string Equivalent to X-Smart-Gateway-Session.
goal_id string Equivalent to X-Smart-Gateway-Goal.
task_id string Equivalent to X-Task-Id.
repo_id string Optional, used for logging.

Response (non-streaming)

{
  "id": "gen-1787490793-…",
  "object": "chat.completion",
  "created": 1755000000,
  "model": "deepseek/deepseek-v4-flash-0731",
  "choices": [
    {
      "index": 0,
      "message": {"role": "assistant", "content": "PONG"},
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 17,
    "completion_tokens": 1,
    "total_tokens": 18
  }
}

The model field echoes the real OpenRouter ID, not the alias you sent. The id is the OpenRouter completion ID (gen-…).

If the upstream payload contains reasoning in message.reasoning and message.content is null, the gateway copies the reasoning text into message.content so that OpenAI-compatible clients see a non-empty answer (_normalize_extended_thinking_response).

Response (streaming)

Content-Type: text/event-stream. Each event is a chat.completion.chunk in OpenAI's standard SSE shape. The terminal event is data: [DONE].

See User guide → Streaming for the exact chunk format, the reasoning-delta normalizer, and known caveats.

Status codes

Status When
200 Successful completion (or successful stream).
400 Body is not valid JSON, or contains an unsupported shape (e.g. multimodal image content).
401 Missing or malformed Authorization.
403 Privacy gate (A force-free request that violates privacy policy must fail closed.), Scout on sensitive (Scout cannot be called on sensitive data.), or STOP_FOR_HUMAN for non-ROUTE/SCOUT decisions.
422 Pydantic validation error (e.g. negative max_tokens).
500 OpenRouter returned a non-retryable 4xx, or all retries exhausted.
502 / 503 / 504 Transport error after exhausting retries.

The error body for 4xx/5xx is {"detail": "<message>"}.

Examples

Minimal

curl -sS "$BASE/v1/chat/completions" \
  -H "Authorization: Bearer $KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"smart-router-flash","messages":[{"role":"user","content":"PONG"}],"max_tokens":4}'

With streaming

curl -sN "$BASE/v1/chat/completions" \
  -H "Authorization: Bearer $KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"smart-router-flash","stream":true,"messages":[{"role":"user","content":"hi"}],"max_tokens":64}'

Tool calls

curl -sS "$BASE/v1/chat/completions" \
  -H "Authorization: Bearer $KEY" \
  -H "Content-Type: application/json" \
  -d '{
        "model":"smart-router",
        "messages":[{"role":"user","content":"Weather in Tokyo?"}],
        "tools":[{
          "type":"function",
          "function":{
            "name":"get_weather",
            "description":"Get current weather",
            "parameters":{"type":"object","properties":{"city":{"type":"string"}},"required":["city"]}
          }
        }],
        "tool_choice":"auto"
      }'

Force Pro

curl -sS "$BASE/v1/chat/completions" \
  -H "Authorization: Bearer $KEY" \
  -H "X-Pro: true" \
  -H "Content-Type: application/json" \
  -d '{"model":"smart-router","messages":[{"role":"user","content":"[reasoning:high] design a semaphore"}],"max_tokens":500}'

See also