← Blog

Claude API Tool Use for Multi-Step Workflows

2026-11-01 · 5 min read · SubToAPI Team

When people search for "Claude API tool use multi step workflows," they're usually stuck on one specific problem: Claude's tool use feature works fine for a single function call, but breaks down once you need Claude to call multiple tools in sequence, react to results, and decide what to do next. This article covers exactly that — how to structure the request/response loop, manage state across steps, and avoid the common failure modes that show up once a workflow has more than one hop.

The short answer is that multi-step tool use isn't a special API mode. It's a loop you write yourself: send a message, check if Claude's response contains a tool_use block, execute that tool, send the result back as a tool_result, and repeat until Claude returns a plain text response. Anthropic's API doesn't run your tools for you — it only decides when to call them and what arguments to pass. The orchestration logic lives entirely in your application code.

The core loop

Every multi-step tool workflow follows the same pattern, regardless of how many tools or steps are involved:

  1. Send the user's request plus your tool definitions.
  2. Inspect the response's stop_reason. If it's tool_use, extract the tool call(s).
  3. Execute the tool(s) locally — call your database, hit an external API, run a calculation.
  4. Append the tool result to the conversation as a tool_result message.
  5. Send the updated conversation back to Claude.
  6. Repeat from step 2 until stop_reason is end_turn.
async function runWorkflow(messages, tools) {
  while (true) {
    const response = await client.messages.create({
      model: "claude-opus-4",
      max_tokens: 1024,
      messages,
      tools,
    });

    messages.push({ role: "assistant", content: response.content });

    if (response.stop_reason !== "tool_use") {
      return response; // final answer reached
    }

    const toolUseBlocks = response.content.filter(
      (block) => block.type === "tool_use"
    );

    const toolResults = await Promise.all(
      toolUseBlocks.map(async (block) => ({
        type: "tool_result",
        tool_use_id: block.id,
        content: await executeTool(block.name, block.input),
      }))
    );

    messages.push({ role: "user", content: toolResults });
  }
}

This loop is the entire architecture. Everything else — error handling, logging, step limits — is built around it.

Handling parallel and sequential tool calls differently

Claude can return more than one tool_use block in a single response when the tools don't depend on each other — for example, looking up weather for three cities at once. Run those with Promise.all as shown above.

Sequential dependencies are different: if step two needs the output of step one, Claude will only request one tool at a time, waiting for your tool_result before issuing the next call. You don't need to detect this yourself — just keep looping. The model naturally spaces out dependent calls across turns.

Preventing runaway loops

The biggest practical risk in a multi-step workflow is Claude getting stuck in a call-result-call cycle, either because a tool keeps returning errors or because the task genuinely requires more steps than expected. Always cap the loop:

let steps = 0;
const MAX_STEPS = 8;

while (steps < MAX_STEPS) {
  steps++;
  // ... loop body
}
throw new Error("Workflow exceeded max steps");

Eight to ten steps is usually enough for real workflows like "look up an order, check inventory, calculate shipping, confirm with the user." If you're regularly hitting the cap, that's a sign your tool descriptions are ambiguous rather than a sign you need a higher limit.

Feeding errors back as tool results, not exceptions

A common mistake is letting a failed tool call throw and crash the loop. Instead, catch the error and return it as the tool_result content with an is_error flag. Claude can often recover — retrying with different arguments, trying a different tool, or asking the user for clarification.

async function executeTool(name, input) {
  try {
    return await tools[name](input);
  } catch (err) {
    return { is_error: true, content: err.message };
  }
}

This single change turns brittle one-shot tool calls into workflows that self-correct, which is the whole point of giving Claude multiple steps instead of one.

Keeping state and context manageable

Multi-step workflows accumulate conversation history fast — every tool call and result gets appended to messages. For long workflows this inflates token usage and cost. Two practical fixes:

If you're running this kind of workflow in production and want usage visibility per request without building your own logging, SubToAPI exposes token and tool-call metadata on every response, which makes it easier to spot which step in a workflow is driving cost. See /docs/tools for the exact request/response shapes, or /docs/messages for the base message format this loop builds on.

Designing tools for multi-step reliability

Tool use loops only work as well as the tool definitions behind them. For multi-step chains specifically:

If you're prototyping this against the Claude API through an existing Claude subscription rather than a direct Anthropic API key, SubToAPI gives you the same tool_use/tool_result flow over HTTPS with streaming and usage metadata, which is useful for testing multi-step loops before committing to a billing setup — see /docs/quickstart or start a trial at /signup.

questions

Do I need a different API endpoint for multi-step tool use? No. It's the same /v1/messages endpoint used for single calls. Multi-step behavior comes entirely from looping client-side: send, check stop_reason, execute, send the result back, repeat.

How do I stop Claude from calling tools indefinitely? Set a hard step cap in your loop (8–10 is typical) and treat hitting it as an error state to log, not retry. If you hit the cap often, fix tool descriptions and schemas rather than raising the limit.

Can Claude call multiple independent tools in one step? Yes — when tools don't depend on each other, Claude returns multiple tool_use blocks in a single response. Execute them concurrently and return all tool_result blocks together in the next message.

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 →