Chat Completions API
Use the Chat Completions API to generate a response from SubQ for a list of conversation messages. For server-managed multi-turn conversations with system instructions and built-in web search, see Responses API.
POST /v1/chat/completionsAll requests must include a valid API key in the Authorization header. See Authentication for details.
Request body
Send a JSON object with the required model and messages fields. Omit optional fields unless you need to change generation behavior.
| Field | Type | Required | Description |
|---|---|---|---|
model | string | Yes | Model ID to use, such as subq-preview. See Models. |
messages | array | Yes | Conversation messages in order. Must contain at least one message. |
stream | boolean | No | When false or omitted, returns one JSON response. When true, returns server-sent events. |
temperature | number | No | Sampling temperature from 0 to 2. Higher values make output more random. |
max_tokens | integer | No | Caps generated tokens. Must be at least 1. See Token limits. |
top_p | number | No | Nucleus sampling value from 0 to 1. Use this or temperature, not both, for most requests. |
stop | string or string[] | No | Stop sequence or sequences where generation should stop. |
reasoning_effort | string | No | How much internal reasoning the model should use before answering. See Reasoning effort. |
response_format | object | No | Constrain the assistant reply to a JSON Schema. See Structured outputs. |
tools | array | No | Function tools the model may call. See Function calling. |
tool_choice | string or object | No | Control whether and which tools the model may call ("auto", "required", "none", or a specific function). |
This page documents the non-streaming response. For a non-streaming request, omit stream or set it to false.
Token limits
max_tokens caps the tokens generated in the completion. It is a spending limit, not a
response-length limit.
- Applies only to generated output—not the prompt.
- Reasoning is part of that output. Unless
reasoning_effortisnone, the model reasons before answering from the same allowance, so a request can return200 OKwith an emptycontentandfinish_reasonof"length"—billed, with nothing visible. A largermax_tokensmakes this less likely but does not rule it out;reasoning_effortofnonedoes. - Input and output share the same context window. If
max_tokensplus the input cannot fit, the API returns400withcodecontext_length_exceeded. Do not setmax_tokensto the full window. - Use this parameter exclusively; do not send
max_completion_tokens. - If set, the minimum value is 1. If omitted, the response can use all remaining context space.
- If generation hits the cap,
choices[0].finish_reasonis"length".
{
"model": "subq-preview",
"messages": [
{
"role": "user",
"content": "In three bullets, explain the difference between indemnification, limitation of liability, and insurance requirements in a software contract."
}
],
"max_tokens": 500
}Reasoning effort
Set top-level reasoning_effort to control how much internal reasoning the model uses before it answers. Possible values are none, low, medium, high, and max. Which values are accepted, and what the default is when you omit the field, depends on the model.
- Reasoning tokens are billed as output tokens. They are included in
usage.completion_tokensand counted inmax_tokens. A one-word classification can bill dozens of times more with reasoning enabled than without. - There is no bounded default. Omitting
reasoning_effortdoes not mean light reasoning—the model may reason at length. Set it explicitly on any request with a latency or cost ceiling.
Only none gives a guarantee: zero reasoning tokens and a null reasoning_content, even
when max_tokens is set.
{
"model": "subq-preview",
"messages": [
{
"role": "user",
"content": "Classify this transaction dispute into exactly one category: [FRAUD, BILLING, LOAN, TECHNICAL]. Return only the category name.\n\nTicket: 'I see a charge of $45.22 from a gas station in Ohio, but I live in California and haven't traveled all year. Please cancel my card!'"
}
],
"reasoning_effort": "none"
}Choosing a value
Effort selects a reasoning strategy, not a token budget: higher effort does not reliably mean more tokens, and the relationship differs by prompt and by model version. Benchmark the candidates on your own prompts rather than assuming an ordering.
| Workload | Suggested effort |
|---|---|
| Classification, routing, extraction, short answers | none |
| Open-ended analysis and multi-step work | medium or high; compare both |
Tight max_tokens | none, or expect empty content |
Messages
Each message has a role and content.
| Field | Type | Required | Description |
|---|---|---|---|
role | string | Yes | One of system, user, assistant, or tool. |
content | string or content part[] | Yes | Message text as a plain string, or an array of content parts. |
Use system for durable instructions, user for user input, assistant for prior model responses (including messages that contain tool_calls), and tool for tool result messages already produced by your application. See Function calling.
The simplest content shape is a string:
{
"role": "user",
"content": "Summarize this release note."
}You can also send text content parts:
{
"role": "user",
"content": [
{ "type": "text", "text": "Summarize this release note." }
]
}For document input, send a text instruction and one or more file parts in the same user message:
{
"role": "user",
"content": [
{ "type": "text", "text": "Summarize these documents." },
{
"type": "file",
"filename": "financial-report-2026.pdf",
"mime_type": "application/pdf",
"file_data": "JVBERi0xLjcKJdDUxdgK..."
},
{
"type": "file",
"filename": "meeting-notes.txt",
"mime_type": "text/plain",
"file_data": "U3ViUSBkb2N1bWVudCBub3Rlcy4uLg=="
}
]
}Document file parts accept inline base64 (file_data) or an uploaded file_id. Image, audio, video, URL-based file inputs, and other content part types are rejected. See Sending files for file part examples. For the Responses API, use input_file with file_id instead — see Uploaded files.
Request examples
Use cURL for direct HTTP calls, or use the official OpenAI SDK with SubQ's base URL.
Response
A non-streaming request returns a JSON object with the OpenAI-compatible chat completion shape.
{
"id": "chatcmpl-e1395060-5a57-4182-a833-c5a208137f70",
"object": "chat.completion",
"created": 1784314379,
"model": "subq-preview",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "* **Indemnification** is a contractual obligation where one party agrees to compensate the other for losses, damages, or legal costs arising from third-party claims (such as intellectual property infringement or data breaches), effectively shifting the financial risk of those specific external liabilities to the responsible party.\n* **Limitation of Liability** caps the maximum amount of damages one party can be forced to pay the other for breach of contract or negligence, often excluding consequential or indirect damages, thereby protecting both sides from catastrophic financial exposure beyond a predefined threshold (e.g., fees paid in the prior 12 months).\n* **Insurance Requirements** mandate that one or both parties maintain specific types and minimum amounts of insurance coverage (such as general liability, professional liability, or cyber insurance) to ensure there are financial resources available to cover potential claims, serving as a verification of financial capacity rather than a direct transfer of risk between the contracting parties."
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 110,
"completion_tokens": 188,
"total_tokens": 298
}
}Response fields
| Field | Type | Description |
|---|---|---|
id | string | Unique completion ID. |
object | string | Object type. Non-streaming responses use chat.completion. |
created | integer | Unix timestamp, in seconds, for when the completion was created. |
model | string | Model ID used for the completion. |
choices | array | Generated choices. SubQ returns at least one choice for a successful request. |
usage | object | Token usage for the request. |
Choice fields
| Field | Type | Description |
|---|---|---|
index | integer | Choice index. |
message.role | string | Role of the returned message, usually assistant. |
message.content | string | Generated text. May be null when the model returns tool calls, and an empty string when max_tokens was consumed before the answer began—see Token limits. |
message.reasoning_content | string | The model's internal reasoning for this turn, when reasoning is enabled. null when reasoning_effort is none. Treat it as diagnostic output: do not parse it or show it to end users. |
message.tool_calls | array | Present when the model requests function calls. See Function calling. |
finish_reason | string | Reason generation stopped. Common values include stop, length (hit max_tokens or the remaining window), and tool_calls. Handle unknown string values defensively. |
Usage fields
| Field | Type | Description |
|---|---|---|
prompt_tokens | integer | Tokens counted from the request messages. |
completion_tokens | integer | Tokens generated in the response, including any reasoning tokens. Billed at the output rate. |
reasoning_tokens | integer | Of those generated tokens, how many were internal reasoning. 0 when reasoning_effort is none. |
total_tokens | integer | Sum of prompt and completion tokens. |
The two counters are reported independently—on a truncated response reasoning_tokens can
exceed completion_tokens—so test message.content rather than subtracting them.