← Blog

Claude Function Calling JSON Schema Example Guide

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

Claude's "function calling" — officially called tool use — lets the model call functions you define instead of just returning text. You describe each function as a JSON Schema object, Claude decides when to use it, and returns structured arguments you can parse and execute. This article walks through real, working JSON Schema examples for Claude's tool use, from a single simple tool to nested objects and multiple tools in one request.

The short answer: a Claude tool definition is a JSON object with name, description, and input_schema, where input_schema is standard JSON Schema (type: "object", properties, required). Claude reads the schema, decides whether to call the tool, and responds with a tool_use content block containing arguments that match that schema.

The Basic Shape of a Claude Tool

Every tool you pass to the Claude API follows this structure:

{
  "name": "get_weather",
  "description": "Get the current weather for a given city",
  "input_schema": {
    "type": "object",
    "properties": {
      "city": {
        "type": "string",
        "description": "City name, e.g. 'Berlin'"
      },
      "unit": {
        "type": "string",
        "enum": ["celsius", "fahrenheit"],
        "description": "Temperature unit"
      }
    },
    "required": ["city"]
  }
}

A few things matter here:

Full Request Example

Here's a complete request using the schema above against the Claude Messages API:

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-3-5-sonnet-20241022",
    "max_tokens": 1024,
    "tools": [
      {
        "name": "get_weather",
        "description": "Get the current weather for a given city",
        "input_schema": {
          "type": "object",
          "properties": {
            "city": { "type": "string" },
            "unit": { "type": "string", "enum": ["celsius", "fahrenheit"] }
          },
          "required": ["city"]
        }
      }
    ],
    "messages": [
      { "role": "user", "content": "What is the weather in Lisbon?" }
    ]
  }'

If Claude decides to use the tool, the response contains a tool_use block like:

{
  "type": "tool_use",
  "id": "toolu_01A09q90qw90lq917835lq9",
  "name": "get_weather",
  "input": {
    "city": "Lisbon",
    "unit": "celsius"
  }
}

Your code reads input, runs the actual logic (calling a weather API, querying a database, whatever the tool represents), and sends the result back as a tool_result message so Claude can finish its answer.

Nested Objects and Arrays

JSON Schema supports nesting, and Claude handles it well as long as the schema is well-formed. Here's a tool for creating a calendar event with a nested location object and an array of attendees:

{
  "name": "create_event",
  "description": "Create a calendar event with attendees",
  "input_schema": {
    "type": "object",
    "properties": {
      "title": { "type": "string" },
      "start_time": {
        "type": "string",
        "description": "ISO 8601 datetime, e.g. 2024-06-01T14:00:00Z"
      },
      "location": {
        "type": "object",
        "properties": {
          "name": { "type": "string" },
          "address": { "type": "string" }
        }
      },
      "attendees": {
        "type": "array",
        "items": { "type": "string" },
        "description": "List of attendee email addresses"
      }
    },
    "required": ["title", "start_time"]
  }
}

Keep nesting shallow where possible. Deeply nested schemas (3+ levels) increase the chance Claude fills fields incorrectly or skips optional branches. If you need deep nesting, add explicit descriptions at every level, not just the top.

Multiple Tools in One Request

You can pass several tools in the same tools array. Claude picks whichever one fits the user's request, or none at all if the message doesn't need a tool:

"tools": [
  { "name": "get_weather", "description": "...", "input_schema": { ... } },
  { "name": "search_flights", "description": "...", "input_schema": { ... } },
  { "name": "convert_currency", "description": "...", "input_schema": { ... } }
]

If names and descriptions overlap conceptually, Claude can pick the wrong one. Keep tool names specific (search_flights rather than search) and make descriptions mention concrete trigger conditions, e.g. "Use this when the user asks about flight availability or prices between two cities."

Common Schema Mistakes

A few patterns consistently cause problems:

Serving Tool Use Through an API Layer

If you're building a product on top of Claude's tool use rather than experimenting in a script, you'll eventually need to manage API keys per customer, track usage per tool call, and expose streaming — without reimplementing all of that yourself. SubToAPI wraps your existing Claude access into a standard HTTPS API with per-application keys (sub_live_...), so your JSON Schema tool definitions work exactly as shown above, just pointed at https://api.subtoapi.app/v1/messages with Authorization: Bearer $SUBTOAPI_KEY. Usage metadata and team seats are handled on the dashboard side, which is useful once tool use moves from a prototype into something customers depend on. See the tool use docs and quickstart for the exact request format.

Questions

Does Claude support the full JSON Schema spec for tools? No — Claude supports a practical subset: type, properties, required, enum, items, and description. Advanced keywords like oneOf, allOf, or $ref are not reliably supported and should be avoided in tool schemas.

Can Claude call multiple tools in a single response? Yes. Claude can return multiple tool_use blocks in one response if it determines several tools are needed to answer the request, and you send results back for each before Claude continues.

What happens if Claude's tool_use input doesn't match my schema exactly? In practice this is rare when descriptions are clear, but you should still validate input against your schema before executing it, since tool arguments come from a model and not a type-checked client.

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 →