← Blog

Claude API JSON Schema Function Calling Example

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

Function calling with Claude works by describing a "tool" using a JSON Schema object, sending it alongside your prompt, and letting Claude decide when to call it. Claude responds with a structured tool_use block containing arguments that match your schema, which your code then parses and executes. This article walks through a complete, working example from schema definition to handling the response.

The core pattern is always the same: define the tool's input_schema using standard JSON Schema (types, required fields, enums, nested objects), pass it in the tools array of your request, and check the response for a tool_use content block instead of plain text.

A minimal function calling example

Suppose you want Claude to extract structured flight search parameters from a user's natural language request. Here's the tool definition:

{
  "name": "search_flights",
  "description": "Search for available flights between two cities",
  "input_schema": {
    "type": "object",
    "properties": {
      "origin": {
        "type": "string",
        "description": "IATA airport code, e.g. JFK"
      },
      "destination": {
        "type": "string",
        "description": "IATA airport code, e.g. LAX"
      },
      "departure_date": {
        "type": "string",
        "format": "date",
        "description": "Date in YYYY-MM-DD format"
      },
      "passengers": {
        "type": "integer",
        "minimum": 1,
        "default": 1
      },
      "cabin_class": {
        "type": "string",
        "enum": ["economy", "premium_economy", "business", "first"]
      }
    },
    "required": ["origin", "destination", "departure_date"]
  }
}

A full request including this tool, using curl against a Messages-style endpoint:

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": "search_flights",
      "description": "Search for available flights between two cities",
      "input_schema": { ... }
    }],
    "messages": [
      {"role": "user", "content": "Find me a business class flight from JFK to LAX on March 15th for 2 people"}
    ]
  }'

Claude's response includes a tool_use block like this:

{
  "type": "tool_use",
  "id": "toolu_01A2b3",
  "name": "search_flights",
  "input": {
    "origin": "JFK",
    "destination": "LAX",
    "departure_date": "2025-03-15",
    "passengers": 2,
    "cabin_class": "business"
  }
}

Your application reads input, which already conforms to the schema — no regex parsing, no "please return valid JSON" prompting tricks required.

Returning the result to Claude

After executing the actual flight search, you send the result back as a tool_result block in the next message so Claude can summarize it for the user:

{
  "role": "user",
  "content": [
    {
      "type": "tool_result",
      "tool_use_id": "toolu_01A2b3",
      "content": "[{\"flight\":\"AA123\",\"price\":412}]"
    }
  ]
}

Claude then produces a natural-language reply based on that data, maintaining the conversation loop.

Schema design tips that reduce errors

A few practical rules make function calling noticeably more reliable:

Forcing a specific tool

Sometimes you don't want Claude to decide whether to call a tool — you want it to always call one, especially for structured extraction tasks. You can force this with tool_choice:

"tool_choice": {"type": "tool", "name": "search_flights"}

This is useful when the entire point of the request is structured output, not conversation — effectively turning Claude into a JSON extraction engine.

Multiple tools in one request

You can register several tools and let Claude pick the right one(s) based on the user's message:

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

Claude may call zero, one, or multiple tools in sequence across a conversation, depending on what the user asks for. Your code is responsible for dispatching based on name and validating input against the schema before executing anything with side effects — treat tool arguments as untrusted input from a model, not as pre-validated data.

Simplifying this in production

If you're building this pattern repeatedly across services or teams, the overhead isn't the schema itself — it's managing API keys, streaming tool-call deltas correctly, logging usage per tool, and giving teammates controlled access without sharing a raw provider key. SubToAPI wraps your existing Claude access behind a standard HTTPS API with sub_live_... application keys, so you can issue separate keys per service that all call tools the same way, with usage visible in one dashboard. Tool definitions and tool_use responses work the same as shown above — see the tools docs for request/response shapes, and streaming docs if you need incremental tool-call deltas rather than waiting for the full response. You can get a key from the signup page and compare plans starting at Solo €9.

FAQ

Does Claude support JSON Schema natively for function calling?

Yes. The input_schema field in a tool definition accepts standard JSON Schema, including types, enums, required fields, and nested objects, which Claude uses to validate and structure its tool_use output.

Can I force Claude to always call a specific tool?

Yes, using tool_choice with {"type": "tool", "name": "<tool_name>"}. This is common when using Claude purely for structured data extraction rather than open-ended conversation.

What happens if Claude's tool input doesn't match my schema?

Claude generally produces well-formed input matching the schema, but you should still validate it in your code before executing side effects, since model outputs should never be treated as fully trusted input.

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 →