Claude API Parallel Tool Calling Example (With Code)
When Claude decides it needs more than one tool to answer a request, it can return multiple tool_use blocks in a single response instead of asking for them one at a time. This is parallel tool calling, and it's how you avoid round-tripping to the model for every individual function call. Instead of "call tool A, wait, call tool B, wait, call tool C," Claude says "I need A, B, and C" in one message, and your code executes them together.
This matters for anything that fans out to multiple data sources: checking weather for three cities, pulling stock prices for a watchlist, querying a database and a search API at the same time. Below is a full working example of how parallel tool calling looks in practice, what the request/response shapes are, and how to handle execution and results correctly.
How parallel tool calling works
The flow is the same as single tool use, with one difference: the assistant's response can contain an array of tool_use content blocks instead of just one. Your job is to:
- Send a message with
toolsdefined and a user prompt that naturally requires multiple tool calls. - Check the response for
stop_reason: "tool_use"and iterate over alltool_useblocks, not just the first. - Execute each tool (concurrently if they're independent, like async HTTP calls).
- Return all results as
tool_resultblocks in a single follow-up user message, matched bytool_use_id. - Send that back to continue the conversation.
Claude decides on its own whether a task needs one tool call or several — you don't need to request parallel behavior explicitly, though your tool descriptions and prompt structure influence how aggressively it batches calls.
Example: weather for multiple cities
Here's a minimal tool definition and the kind of response you'd get back when a user asks about several cities at once.
{
"model": "claude-sonnet-4-5",
"max_tokens": 1024,
"tools": [
{
"name": "get_weather",
"description": "Get current weather for a city",
"input_schema": {
"type": "object",
"properties": {
"city": { "type": "string" }
},
"required": ["city"]
}
}
],
"messages": [
{
"role": "user",
"content": "What's the weather in Berlin, Tokyo, and São Paulo right now?"
}
]
}
A parallel tool call response looks like this — note the three separate tool_use blocks in one content array:
{
"stop_reason": "tool_use",
"content": [
{ "type": "text", "text": "I'll check the weather in all three cities." },
{ "type": "tool_use", "id": "toolu_01A", "name": "get_weather", "input": { "city": "Berlin" } },
{ "type": "tool_use", "id": "toolu_01B", "name": "get_weather", "input": { "city": "Tokyo" } },
{ "type": "tool_use", "id": "toolu_01C", "name": "get_weather", "input": { "city": "São Paulo" } }
]
}
Executing multiple tool calls concurrently
The key implementation detail is running all requested tools concurrently where possible, then packaging every result into the same follow-up message:
const toolUseBlocks = response.content.filter(b => b.type === "tool_use");
const results = await Promise.all(
toolUseBlocks.map(async (block) => {
const data = await getWeather(block.input.city);
return {
type: "tool_result",
tool_use_id: block.id,
content: JSON.stringify(data)
};
})
);
// Send all results back in one message
const followUp = {
model: "claude-sonnet-4-5",
max_tokens: 1024,
tools: [/* same tool definitions */],
messages: [
...previousMessages,
{ role: "assistant", content: response.content },
{ role: "user", content: results }
]
};
A common mistake is sending each tool_result back as a separate API call. Don't — Claude expects all results for the batch in a single user message, matched by tool_use_id. Sending them one at a time breaks the conversation state and causes errors or confused follow-up responses.
Using the same pattern through SubToAPI
If you're already calling Claude through SubToAPI, parallel tool calling works identically — it's the same tools schema and the same tool_use/tool_result lifecycle, just proxied through your sub_live_... application key instead of a raw Anthropic key. That means you get the same multi-tool response shapes, plus per-key usage metadata so you can see which application or team is driving the most tool-heavy requests.
curl https://api.subtoapi.app/v1/messages \
-H "Authorization: Bearer $SUBTOAPI_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-sonnet-4-5",
"max_tokens": 1024,
"tools": [{ "name": "get_weather", "description": "...", "input_schema": {} }],
"messages": [{ "role": "user", "content": "Weather in Berlin and Tokyo?" }]
}'
This is useful when multiple engineers or services share one Claude subscription — each gets a scoped API key, and tool-heavy workloads (which can spike token usage fast) are visible per key instead of buried in one shared bill. See the tool use docs and quickstart for the full request format, or check pricing if you're evaluating plans for a team.
Practical tips for reliable parallel calls
- Keep tool schemas tight. Vague
input_schemadefinitions make Claude less confident about batching calls correctly. - Handle partial failures. If one of three parallel tool calls fails, still return a
tool_resultfor it (with an error message in the content) rather than omitting it — omitting breaks thetool_use_idmatching. - Set reasonable
max_tokens. Parallel tool use responses include multiple blocks plus reasoning text; truncation mid-block causes malformed tool calls. - Don't force parallelism with complex prompting. Trust the model's judgment on when tasks are independent enough to batch; over-engineering the prompt tends to produce less reliable results than a clear, direct request.
Questions
Does Claude always call tools in parallel when multiple are needed? No. Claude decides based on whether tasks are independent. Sequential, dependent tasks (where output of one feeds into another) will still come back one tool call at a time across multiple turns.
Can I force Claude to only use one tool at a time? Yes — if your workflow requires sequential execution, say so explicitly in your system prompt or tool descriptions, or structure the tools so later calls depend on earlier outputs.
What happens if I don't return all tool_result blocks for a batch? The conversation will error or stall — Claude expects a matching tool_result for every tool_use_id it issued in that turn before it can continue.