https://clawrouter.com/v1/chat/completionsSend a conversation as a list of messages and get the next one back. This is the endpoint to reach for unless you specifically need a provider's native format — every text model is available here, including Claude and Gemini models, translated to and from the OpenAI shape for you.
Request body
modelstringrequiredModel to use. Call GET /v1/models for the names this instance serves.
messagesobject[]requiredThe conversation so far. Each entry has a role of system, user, assistant or tool, and content.
streambooleandefault: falseStream the reply as server-sent events instead of waiting for the whole completion.
toolsobject[]Function definitions the model may call. See the tool calling section.
tool_choicestring | objectdefault: "auto"Force or forbid tool use: "none", "auto", "required", or a specific function.
response_formatobjectSet to {"type": "json_object"} to constrain output to valid JSON.
temperaturenumberdefault: 1Sampling temperature between 0 and 2. Lower is more deterministic. Claude Opus 4.7 and later, Claude Sonnet and Haiku 5.x, and Claude Fable accept only the default, so the gateway leaves it out for those models.
top_pnumberdefault: 1Nucleus sampling. Consider setting this or temperature, not both. Left out for the same Claude models as temperature.
max_tokensintegerUpper bound on the visible answer. On reasoning models (DeepSeek, Doubao, MiniMax, Kimi, GLM and others) the thinking is generated and billed on top of it, so a max_tokens of 50 can produce thousands of billed tokens; the reasoning share is reported in usage.completion_tokens_details.reasoning_tokens.
max_completion_tokensintegerHard cap on everything generated, reasoning included — use this to bound cost. A reasoning model that hits it while still thinking returns an empty answer with finish_reason length.
stopstring | string[]Up to four sequences that end generation when produced.
Example
curl https://clawrouter.com/v1/chat/completions \
-H "Authorization: Bearer $CLAWROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-sonnet-5",
"messages": [
{"role": "system", "content": "You are concise."},
{"role": "user", "content": "Why is the sky blue?"}
]
}'Response
{
"id": "chatcmpl-...",
"object": "chat.completion",
"created": 1750000000,
"model": "claude-sonnet-5",
"choices": [
{
"index": 0,
"message": { "role": "assistant", "content": "Rayleigh scattering..." },
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 24,
"completion_tokens": 61,
"total_tokens": 85
}
}Images in a prompt
Multimodal models accept image parts inside a user message. Pass a URL the provider can fetch, or inline the bytes as a data URI.
{
"model": "claude-sonnet-5",
"messages": [
{
"role": "user",
"content": [
{ "type": "text", "text": "What is in this image?" },
{
"type": "image_url",
"image_url": { "url": "data:image/jpeg;base64,/9j/4AAQ..." }
}
]
}
]
}Tool calling
Describe the functions the model may call. When it chooses one, the reply carries tool_calls instead of content, and you run the function and send the result back as a tool message.
tools = [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Current weather for a city",
"parameters": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"],
},
},
}]
response = client.chat.completions.create(
model="claude-sonnet-5",
messages=[{"role": "user", "content": "Weather in Taipei?"}],
tools=tools,
)
call = response.choices[0].message.tool_calls[0]
print(call.function.name, call.function.arguments)