REST API
LLM GatewayChat

Chat completions (streaming + non-streaming, with reasoning)

POST/v1/chat/completions

OpenAI-compatible chat completions over an upstream provider chosen by model. Set "stream": true for SSE; otherwise the response is a single JSON body.

Reasoning

Opt into model thinking with top-level reasoning_effort (none | minimal | low | medium | high | xhigh | max). Allowed values are per-model — query /v1/models for reasoning_levels. Reasoning is streaming-only: non-streaming responses drop it entirely.

Streaming reasoning surfaces two channels per delta:

  • reasoning_content — display text for live UI (DeepSeek-style extension; concatenate across chunks like content).
  • reasoning_meta — structured snapshot at block close, carrying the signature (Anthropic) or encrypted_content (OpenAI) clients need to replay reasoning on subsequent turns.

Multi-turn replay

Persist reasoning_meta between turns and send it back as a {"type": "reasoning", ...} block on the assistant message — before text and tool calls (Anthropic enforces this order). Required on Anthropic for tool-using turns (the API 400s without the matching thinking block); recommended on OpenAI so the model doesn't re-derive its plan and re-bill reasoning tokens.

OpenAI's Responses API requires id on every replayed reasoning block — the gateway 400s pre-flight if missing. Anthropic ignores id (signatures live per-block instead).

Signatures and encrypted blobs are model-bound: persist model alongside the reasoning meta and refuse to replay across models.

See docs/llm-gateway/REASONING.md for the full contract, JSONL persistence shape, and end-to-end curl examples.

Authorization

bearerAuth
AuthorizationBearer <token>

In: header

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

OpenAI-compatible chat completions request.

model picks the upstream provider (see /v1/models). Set "stream": true to receive text/event-stream of ChatChunk deltas instead of a single ChatResponse body. Tool-calling and reasoning are both streaming-only in v1.

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

application/json

curl -X POST "https://example.com/v1/chat/completions" \  -H "Content-Type: application/json" \  -d '{    "messages": [      {        "role": "user"      }    ],    "model": "gpt-5.6",    "stop": {}  }'
{  "choices": [    {      "finish_reason": "stop",      "index": 0,      "message": {        "content": "string",        "role": "assistant"      }    }  ],  "created": 0,  "id": "string",  "model": "gpt-5.6",  "object": "chat.completion",  "speed": "standard",  "usage": {    "cache_creation_input_tokens": 0,    "cache_read_input_tokens": 0,    "completion_tokens": 0,    "prompt_tokens": 0,    "total_tokens": 0  }}
{  "error": {    "code": "string",    "message": "model not supported: foo",    "request_id": "string",    "service_id": "string",    "type": "invalid_request_error"  }}
{  "error": {    "code": "string",    "message": "model not supported: foo",    "request_id": "string",    "service_id": "string",    "type": "invalid_request_error"  }}
{  "error": {    "code": "string",    "message": "model not supported: foo",    "request_id": "string",    "service_id": "string",    "type": "invalid_request_error"  }}
{  "error": {    "code": "string",    "message": "model not supported: foo",    "request_id": "string",    "service_id": "string",    "type": "invalid_request_error"  }}
{  "error": {    "code": "string",    "message": "model not supported: foo",    "request_id": "string",    "service_id": "string",    "type": "invalid_request_error"  }}
{  "error": {    "code": "string",    "message": "model not supported: foo",    "request_id": "string",    "service_id": "string",    "type": "invalid_request_error"  }}
{  "error": {    "code": "string",    "message": "model not supported: foo",    "request_id": "string",    "service_id": "string",    "type": "invalid_request_error"  }}