← Blog

Claude API Custom Tool Definition Example

2026-10-24 · 4 min read · SubToAPI Team

A custom tool definition in the Claude API is a JSON object that describes a function Claude can choose to call: its name, a description of what it does, and a JSON Schema specifying its input parameters. You pass an array of these definitions in the tools field of your request, and Claude decides whether to respond with text or with a structured tool_use block asking you to run one of them.

This article walks through a full, working example — from schema definition to handling the tool call and returning the result — so you can copy the pattern directly into your own code.

The anatomy of a tool definition

Every tool definition has three required parts:

{
  "name": "get_order_status",
  "description": "Look up the current status and tracking info for a customer order by order ID.",
  "input_schema": {
    "type": "object",
    "properties": {
      "order_id": {
        "type": "string",
        "description": "The unique order identifier, e.g. ORD-48213."
      }
    },
    "required": ["order_id"]
  }
}

A few details that matter more than people expect:

A complete request/response example

Here's the full round trip using curl against the Claude API directly:

curl https://api.anthropic.com/v1/messages \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "content-type: application/json" \
  -d '{
    "model": "claude-sonnet-4-5",
    "max_tokens": 1024,
    "tools": [
      {
        "name": "get_order_status",
        "description": "Look up the current status and tracking info for a customer order by order ID.",
        "input_schema": {
          "type": "object",
          "properties": {
            "order_id": { "type": "string", "description": "e.g. ORD-48213" }
          },
          "required": ["order_id"]
        }
      }
    ],
    "messages": [
      { "role": "user", "content": "Where is my order ORD-48213?" }
    ]
  }'

Claude responds with a tool_use content block instead of plain text:

{
  "role": "assistant",
  "content": [
    {
      "type": "tool_use",
      "id": "toolu_01A2b3",
      "name": "get_order_status",
      "input": { "order_id": "ORD-48213" }
    }
  ],
  "stop_reason": "tool_use"
}

Your code runs the actual lookup, then sends the result back in a follow-up message with a tool_result block:

{
  "role": "user",
  "content": [
    {
      "type": "tool_result",
      "tool_use_id": "toolu_01A2b3",
      "content": "Order ORD-48213: shipped, arriving Thursday."
    }
  ]
}

Claude then produces the final natural-language reply using that result. This three-step loop — definition, tool call, tool result — is the entire pattern, no matter how complex the tool.

Common mistakes in custom tool definitions

Building tool-using apps without managing raw SDK plumbing

The pattern above is the same whether you're calling Claude directly or through a proxy. If you're building a product on top of Claude's tool-use feature and want application-level API keys, usage tracking per key, and streaming support without reimplementing auth and billing yourself, SubToAPI (https://subtoapi.app) wraps your existing Claude access in a standard HTTPS API.

Tool definitions work exactly as shown above — you send the same tools array and get the same tool_use/tool_result flow — but requests go through https://api.subtoapi.app/v1/messages with your own sub_live_... key:

const res = await fetch("https://api.subtoapi.app/v1/messages", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.SUBTOAPI_KEY}`,
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    model: "claude-sonnet-4-5",
    max_tokens: 1024,
    tools: [ /* same tool definitions as above */ ],
    messages: [{ role: "user", content: "Where is my order ORD-48213?" }]
  })
});

This is useful if you're shipping a product to multiple customers or teammates and need separate keys per app or seat, usage metadata per request, and a dashboard — rather than one shared raw API key. See /docs/tools for the full tool-use reference and /docs/quickstart to get a key in minutes. Plans start at €9/month on the Solo tier, with Team and Scale tiers for multi-seat setups — details at /pricing.

Questions

Can a single request define multiple tools? Yes. Pass as many tool objects as you need in the tools array. Claude picks which one (if any) to call based on the user's message and each tool's description. See /docs/tools for examples with more than one function.

What happens if Claude's tool input doesn't match my schema? Claude generally respects required fields and types, but you should still validate input server-side before executing anything, especially for destructive actions, since schema adherence isn't a hard guarantee.

Do I need a different tool definition format for streaming responses? No — tool definitions are identical whether you use standard or streaming requests. The difference is that tool_use blocks arrive incrementally as events rather than in one payload. See /docs/streaming for handling streamed tool-use events.

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 →