POST /v1/chat/completions accepts the standard OpenAI tools array. The model emits structured tool_calls in its response when it decides a tool is the right move; your code runs the tool and round-trips the result back as a role: "tool" message.
Tool schema
Each tool is a function declaration with a JSON-schema parameter object:tool_choice field controls how the model picks a tool:
| Value | Behavior |
|---|---|
"auto" (default if tools is set) | Model decides per turn whether to call a tool. |
"none" | Disable tool calls for this turn. |
"required" | Force the model to call at least one tool. Returns 400 tool_choice_required_unsupported if the model lacks the capability. |
{ "type": "function", "function": { "name": "..." } } | Force a specific tool. |
Single-turn example
Round-tripping the tool result
After the model emits a tool call, run the tool locally, then re-callchat.completions.create with the original assistant message AND a new role: "tool" message carrying the result:
Node.js (OpenAI SDK)
tool_call_id on the role: "tool" message must match the id field on the assistant’s tool_calls entry. The model may emit multiple tool calls in a single turn — round-trip them all in one follow-up.
Parallel tool calls
If the model emits two or more tool calls in a single turn (message.tool_calls.length > 1), run them in parallel and send all results back in the next request:
Forcing a specific tool
Pin the tool the model must call by name:response_format, this is the building block for “extract structured data from text” flows: define a tool whose parameters match the schema you want and force it.
Streaming and tools
Whenstream: true, tool-call arguments arrive as delta.tool_calls[*].function.arguments fragments that you must concatenate per id until you see finish_reason: "tool_calls". The OpenAI Node and Python SDKs both expose tool_calls accumulators on their streaming helpers — prefer those over hand-parsing deltas.
Errors
tool_choice_required_unsupported(400) — you passedtool_choice: "required"to a model whoseaurous_metadata.capabilitiesdoesn’t includetool_choice_required. List models viaGET /v1/modelsto check capability flags before setting this.response_format_too_large(400) — the JSON schema inresponse_formatexceeds the platform’s payload cap. Trim the schema (fewer properties, shorter descriptions) and retry.response_format_too_deep(400) — the JSON schema nests deeper than the parser’s cap. Flatten nested definitions or pull them into$defsreferences.

