← Blog

Claude API Function Calling Best Practices

2026-10-06 · 5 min read · SubToAPI Team

Function calling (Claude calls it "tool use") lets Claude invoke your code mid-conversation instead of just returning text. Getting it to work reliably in production is different from getting a demo to work once. The best practices below cover tool definition, execution flow, error handling, and validation — the parts that actually break when real users hit your app.

The short version: define tools with strict, narrow schemas; always validate Claude's input before executing anything; handle the full tool_use → tool_result loop explicitly; and treat tool errors as recoverable conversation turns, not exceptions that crash your request.

Design tools like you'd design a public API

Claude decides when and how to call a tool based entirely on the tool's name, description, and JSON schema. If that metadata is vague, Claude guesses — and guessing produces wrong arguments, wrong tool choices, or unnecessary calls.

Handle the tool_use loop explicitly

A tool call isn't a single request — it's a conversation turn. Claude returns a stop_reason of tool_use along with one or more tool_use blocks. Your code executes the tool(s) and sends the results back as tool_result blocks in a new user message, continuing the same message history.

{
  "role": "assistant",
  "content": [
    { "type": "tool_use", "id": "toolu_01", "name": "get_order_status", "input": { "order_id": "A1234" } }
  ]
}
{
  "role": "user",
  "content": [
    { "type": "tool_result", "tool_use_id": "toolu_01", "content": "Order A1234: shipped, arriving Tuesday." }
  ]
}

Common mistakes here:

Validate before you execute

Claude's tool arguments come from a JSON schema it tries to respect, but it is not a guarantee. Treat every tool_use.input like untrusted input from a web form:

Handle tool errors as conversation, not crashes

When a tool fails — a timeout, a 404, invalid input — don't throw and end the request. Send the error back to Claude as a tool_result with is_error: true and a short, actionable message. Claude will usually retry with corrected arguments or explain the failure to the user instead of hallucinating a result.

{
  "type": "tool_result",
  "tool_use_id": "toolu_01",
  "content": "Order not found: A1234 does not exist.",
  "is_error": true
}

This single pattern eliminates a large share of "Claude made up data" bug reports — most of them are actually unhandled tool failures that never reached the model.

Parallel tool calls and latency

Claude can request multiple tool calls in a single turn when they're independent (e.g., looking up weather for three cities). Execute these concurrently in your code — Promise.all in JavaScript, asyncio.gather in Python — rather than sequentially, and return all results together in one tool_result message. Sequential execution of independent calls is one of the most common unnecessary latency sources in tool-use apps.

Keep tool definitions stable across a conversation

Changing the tool list mid-conversation (adding/removing tools between turns) can confuse Claude about what's available. If you need conditional tools, decide the full set before the first message in a session and keep it consistent for the life of that conversation.

Monitor what's actually happening

Once tool use is in production, the failures that matter are the ones you can't see in a terminal: which tools get called most, which ones error out, and how much latency the tool loop adds per request. If you're running Claude behind a standard HTTPS API — like the one SubToAPI exposes over your existing Claude access — every tool-use request shows up with full metadata (tokens, latency, tool calls) in one dashboard, which makes it much faster to spot a tool that's silently failing 20% of the time. See the tool use docs and messages docs for request formats, or start with the quickstart.

Questions

Does Claude support parallel tool calls in one turn? Yes. Claude can return multiple tool_use blocks in a single response when the calls are independent. Execute them concurrently and return all corresponding tool_result blocks in one follow-up message.

What happens if Claude sends invalid arguments to my tool? Nothing stops it from happening — you must validate input yourself. If validation fails, return a tool_result with is_error: true describing the problem; Claude will typically retry with corrected arguments.

How many tools can I give Claude in one request? There's no hard cap on tool count, but accuracy drops as the tool list grows and tools overlap in purpose. Keep definitions narrow and distinct, and only include tools relevant to the current conversation.

Turn your Claude access into an HTTPS API

SubToAPI gives you application API keys, streaming, tool use and usage insights on top of your existing Claude access — set up in minutes.

Start free  Read the quickstart →