Claude API Parallel Tool Calls Example
What "parallel tool calls" actually means in the Claude API
When you give Claude multiple tools and a prompt that requires more than one of them, Claude can return several tool_use blocks in a single response instead of calling one tool, waiting for the result, and asking for another. This is what people mean by "parallel tool calls" — it's not multithreading on your side, it's Claude deciding upfront that it needs, say, a weather lookup and a currency conversion, and emitting both tool calls in the same turn.
The practical benefit is fewer round trips. Instead of: prompt → tool call → result → tool call → result → final answer, you get: prompt → two tool calls at once → you execute both (in parallel or sequentially, your choice) → you send both results back → final answer. This guide shows a full working example, how to structure the response handling, and the mistakes that cause parallel tool calls to silently stop working.
A minimal example with two tools
Say you're building an assistant that can check stock prices and convert currency. Define both tools in the request:
const tools = [
{
name: "get_stock_price",
description: "Get the current price of a stock by ticker symbol",
input_schema: {
type: "object",
properties: {
ticker: { type: "string" }
},
required: ["ticker"]
}
},
{
name: "convert_currency",
description: "Convert an amount from one currency to another",
input_schema: {
type: "object",
properties: {
amount: { type: "number" },
from: { type: "string" },
to: { type: "string" }
},
required: ["amount", "from", "to"]
}
}
];
Now send a prompt that naturally needs both:
const response = await client.messages.create({
model: "claude-sonnet-4-5",
max_tokens: 1024,
tools,
messages: [
{
role: "user",
content: "What's AAPL trading at, and what's that price in EUR?"
}
]
});
If Claude decides it needs both tools before it can answer, the response content array will contain two tool_use blocks, each with its own id, name, and input. You won't get a text block in between — both calls arrive together, and it's your job to run both and return both results.
Handling the response correctly
The key detail people miss: you must loop over every tool_use block in the response, not just the first one.
const toolUseBlocks = response.content.filter(
(block) => block.type === "tool_use"
);
const toolResults = await Promise.all(
toolUseBlocks.map(async (block) => {
const result = await runTool(block.name, block.input);
return {
type: "tool_result",
tool_use_id: block.id,
content: JSON.stringify(result)
};
})
);
Promise.all is where the actual parallelism happens on your side — Claude gave you two independent tool calls, and since neither depends on the other's output, you can execute them concurrently instead of one after another.
Then send everything back in a single follow-up message:
const followUp = await client.messages.create({
model: "claude-sonnet-4-5",
max_tokens: 1024,
tools,
messages: [
{ role: "user", content: "What's AAPL trading at, and what's that price in EUR?" },
{ role: "assistant", content: response.content },
{ role: "user", content: toolResults }
]
});
Note that all tool_result blocks go into one user message, matched by tool_use_id. Sending them as separate messages, or in the wrong order, is a common source of "invalid tool_result" errors.
Why Claude sometimes doesn't parallelize
Parallel tool calls aren't guaranteed — Claude decides per-request whether the task actually benefits from calling multiple tools at once. A few things make it more likely:
- Independent sub-tasks in one prompt. "Get the weather in Paris and Tokyo" is a strong parallel-call candidate. "Get the weather in Paris, then tell me if I should also check Tokyo" is sequential by nature.
- Clear, non-overlapping tool descriptions. Vague or overlapping
descriptionfields make Claude less confident about which tools apply, so it tends to call one, evaluate, then decide on the next. - Model choice. Larger models are generally better at recognizing when a request decomposes into independent tool calls.
If you expect parallel calls and consistently get sequential ones, rewrite the prompt to make the independence explicit ("look up both X and Y") rather than assuming Claude will infer it.
Handling partial failures
With multiple tool calls in flight, one can fail while another succeeds. Don't let one failure block the other result — return a tool_result for every tool_use_id, even the failed one, with is_error: true:
{
type: "tool_result",
tool_use_id: block.id,
content: "Rate limit exceeded on currency API",
is_error: true
}
If Claude sent three tool calls and only receives two results, the next request will fail validation. Always match count and order.
If you're running this through SubToAPI
If you're accessing Claude through your existing subscription via SubToAPI rather than a raw Anthropic API key, the request/response shape for tool use is identical — you post to https://api.subtoapi.app/v1/messages with your sub_live_... key and the same tools array, tool_use blocks, and tool_result structure described above. The parallel tool call behavior comes from the model itself, not the transport layer, so nothing changes in your handling logic. See the tool use docs for the exact request format, and the quickstart if you're setting this up for the first time. Plans start at Solo €9/month, with Team and Scale tiers for multi-seat usage — check pricing or grab a free trial at signup.
Practical checklist
- Filter
response.contentfor alltool_useblocks, not just the first - Execute independent tool calls concurrently with
Promise.all(or your language's equivalent) - Return one
tool_resultpertool_use_id, bundled into a single message - Use
is_error: truefor failed calls instead of omitting them - Write tool descriptions that clearly delineate scope, so Claude can recognize independent tasks
Questions
Does Claude always run tool calls in parallel when multiple tools are available? No. Claude decides based on whether the task actually decomposes into independent sub-tasks. Prompts that clearly require unrelated lookups are more likely to trigger multiple tool_use blocks in one response.
Can I force Claude to always parallelize tool calls? Not directly. You can improve the odds with clearer prompts and distinct tool descriptions, but there's no parameter that forces parallel execution — it's a model decision based on the request.
What happens if I only return a result for one of two parallel tool calls? The next API request will fail validation because every tool_use_id from the assistant's turn needs a matching tool_result. Always return one result per tool call, using is_error: true for failures.