Skip to content

Chat Completions

POST /v1/chat/completions

Generate a model response for a given conversation. Fully compatible with the OpenAI Chat Completions API.

ParameterTypeRequiredDescription
modelstringYesModel ID (see Models)
messagesarrayYesConversation messages (see Message types)
streambooleanNoStream partial deltas as SSE. Default: false
stream_optionsobjectNo{ "include_usage": true } to include token counts in the final stream event
temperaturenumberNoSampling temperature, 0–2. Default: model-dependent
top_pnumberNoNucleus sampling threshold, greater than 0 and at most 1
nintegerNoNumber of choices to generate, 1–128
max_tokensintegerNoMaximum tokens to generate (deprecated — use max_completion_tokens)
max_completion_tokensintegerNoUpper bound on generated tokens, including reasoning tokens
stopstring | string[]NoUp to 4 stop sequences
frequency_penaltynumberNoFrequency penalty, -2 to 2
presence_penaltynumberNoPresence penalty, -2 to 2
logprobsbooleanNoReturn log probabilities of output tokens
top_logprobsintegerNoMost likely tokens per position, 0–20
response_formatobjectNo{ "type": "text" }, { "type": "json_object" }, or { "type": "json_schema", "json_schema": {...} }
seedintegerNoSeed for deterministic sampling
toolsarrayNoFunction tools the model may call
tool_choicestring | objectNo"none", "auto", "required", or a specific tool
parallel_tool_callsbooleanNoAllow parallel function calling
reasoning_effortstringNoPer-model — read reasoning_efforts from GET /v1/models. A level the model doesn’t list runs at the next listed level up, or the highest, which can cost more than the level you sent, and X-Reasoning-Effort reports it; a value outside the effort vocabulary is rejected
top_kintegerNoTop-k sampling (provider-specific)
repetition_penaltynumberNoRepetition penalty (provider-specific)
userstringNoEnd-user identifier for abuse tracking

A model can turn reasoning off only if its levels include none. Sending reasoning_effort none to a model that does not publish it is a 400. The error text is on Errors.

{ "role": "system", "content": "You are a helpful assistant." }
{ "role": "user", "content": "What is the capital of France?" }

User messages also accept multimodal content arrays:

{
"role": "user",
"content": [
{ "type": "text", "text": "What's in this image?" },
{ "type": "image_url", "image_url": { "url": "https://...", "detail": "auto" } }
]
}

Supported content types: text, image_url, video_url, audio_url, input_audio, file.

URLs in image_url, video_url, audio_url and file.file_url must meet the URL requirements.

For images, prefer uploading via the Files API and referencing by file_id rather than inline base64 — multi-turn conversations and retries don’t re-send bytes from your client:

{
"role": "user",
"content": [
{ "type": "text", "text": "What's in this image?" },
{ "type": "file", "file": { "file_id": "file-abc123" } }
]
}

The model must have the matching capability (e.g. vision); otherwise the request is rejected with 400 model_capability_mismatch.

PDFs can also be sent inline, in the shape the OpenAI SDK and the Vercel AI SDK use (OpenCode sends PDF attachments this way):

{
"type": "file",
"file": { "filename": "report.pdf", "file_data": "data:application/pdf;base64,JVBERi0x..." }
}

An inline PDF is stored as a purpose: "document" file, as if you had uploaded it to the Files API: it appears in your file list and expires after 30 days. A later request carrying the same PDF reuses that file, so only the first request that sends it waits for its pages to be rendered. The model needs the vision capability, the PDF can have at most 100 pages, and a request can carry at most 16 MiB of PDFs that no earlier request stored; PDFs reused from an earlier request don’t count. For anything larger, upload the PDF to the Files API with purpose: "document" and reference it by file_id. An organization on zero data retention cannot upload files: its inline PDFs are rendered in memory, nothing is stored, and the limits in Inline PDFs apply instead, though the model still needs the vision capability.

{ "role": "assistant", "content": "The capital of France is Paris." }
{ "role": "tool", "tool_call_id": "call_abc123", "content": "{\"result\": 42}" }
{
"id": "chatcmpl-abc123",
"object": "chat.completion",
"created": 1700000000,
"model": "google/gemma-4-31b-it",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "Hello! How can I help you today?"
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 10,
"completion_tokens": 9,
"total_tokens": 19
}
}
FieldTypeDescription
prompt_tokensintegerInput tokens consumed
completion_tokensintegerOutput tokens generated
total_tokensintegerSum of input and output tokens
prompt_tokens_detailsobjectOptional. { cached_tokens, audio_tokens }
completion_tokens_detailsobjectOptional. { reasoning_tokens, audio_tokens }

Reasoning models also return their reasoning in message.reasoning_content and message.reasoning, or delta.reasoning_content and delta.reasoning when streaming. Both hold the same text. See Reasoning.

Set stream: true to receive partial responses as server-sent events.

Terminal window
curl https://api.aiand.com/v1/chat/completions \
-H "Authorization: Bearer sk-your-api-key" \
-H "Content-Type: application/json" \
-d '{
"model": "google/gemma-4-31b-it",
"stream": true,
"messages": [{"role": "user", "content": "Count to 5"}]
}'

Each event contains a data: line with a JSON chunk. The stream ends with data: [DONE].

To include token usage in the final event:

{
"stream": true,
"stream_options": { "include_usage": true }
}

Define tools in the request and the model can choose to call them:

{
"model": "google/gemma-4-31b-it",
"messages": [{ "role": "user", "content": "What's the weather in Tokyo?" }],
"tools": [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get current weather for a location",
"parameters": {
"type": "object",
"properties": {
"location": { "type": "string" }
},
"required": ["location"]
}
}
}
]
}

When the model calls a tool, the response includes tool_calls:

{
"choices": [
{
"message": {
"role": "assistant",
"tool_calls": [
{
"id": "call_abc123",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"location\": \"Tokyo\"}"
}
}
]
},
"finish_reason": "tool_calls"
}
]
}

Send the result back as a tool message to continue the conversation.