Claude API Function Calling Schema Example
What a Claude function calling schema actually looks like
If you're searching for a working example, here's the short answer: Claude's "function calling" is called tool use, and it works by sending a tools array in your API request, where each tool has a name, a description, and an input_schema written in standard JSON Schema. Claude doesn't execute the function itself — it returns a tool_use content block with the arguments it wants to call, and your code runs the actual function and sends the result back.
This is different from older OpenAI-style "functions" parameters in naming but nearly identical in structure. If you've written a JSON Schema before, you already know 90% of what you need.
The minimal tool schema
Here's a bare-bones example: a weather lookup tool.
{
"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"]
}
},
"required": ["city"]
}
}
Three things matter most here:
description— Claude uses this text to decide when to call the tool. Vague descriptions produce unreliable tool selection.input_schema— standard JSON Schema (type,properties,required,enum, nested objects, arrays). Claude validates its own output against this before returning it.required— list only the fields that must always be present; optional fields should simply be omitted from arguments when not needed.
Full request example
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_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 right now?" }
]
}'
Claude's response won't contain a final answer — it contains a tool call:
{
"content": [
{
"type": "tool_use",
"id": "toolu_01A2bC",
"name": "get_weather",
"input": { "city": "Lisbon" }
}
],
"stop_reason": "tool_use"
}
Your application code calls the real weather API, then sends the result back as a tool_result block, using the same id:
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "toolu_01A2bC",
"content": "18°C, partly cloudy"
}
]
}
Claude then generates the final natural-language reply using that result.
Multiple tools and tool_choice
You can define several tools in the same array, and let Claude pick the right one:
"tools": [
{ "name": "get_weather", "description": "...", "input_schema": { ... } },
{ "name": "search_flights", "description": "...", "input_schema": { ... } },
{ "name": "convert_currency", "description": "...", "input_schema": { ... } }
]
Use tool_choice to control behavior:
{"type": "auto"}— default, Claude decides whether to call a tool at all.{"type": "any"}— forces Claude to call one of the tools.{"type": "tool", "name": "get_weather"}— forces a specific tool.
Forcing a specific tool is useful when you're using tool use purely as a structured-output mechanism rather than for real function execution — a common pattern for extracting structured JSON from unstructured text.
Nested and array schemas
Schemas can go as deep as real JSON Schema allows. A booking tool with nested objects:
{
"name": "create_booking",
"description": "Create a hotel booking for one or more guests",
"input_schema": {
"type": "object",
"properties": {
"hotel_id": { "type": "string" },
"check_in": { "type": "string", "format": "date" },
"check_out": { "type": "string", "format": "date" },
"guests": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": { "type": "string" },
"age": { "type": "integer" }
},
"required": ["name"]
}
}
},
"required": ["hotel_id", "check_in", "check_out", "guests"]
}
}
Keep schemas as flat as practical. Deep nesting works, but every extra layer increases the chance Claude misinterprets which field belongs where, especially with ambiguous field names reused across levels.
Common mistakes in tool schemas
- Vague names and descriptions.
"name": "do_thing"gives Claude nothing to reason about. Use verb-first, specific names likesearch_ordersorcancel_subscription. - Overlapping tools. If two tools can plausibly handle the same request, Claude will sometimes pick the wrong one. Make scope boundaries explicit in the description.
- Missing
requiredfields. Without it, Claude may omit fields it should always include, leading to downstream null errors in your handler code. - Forgetting multi-turn tool loops. A single user message can trigger several rounds of tool calls before a final answer — your code needs to loop until
stop_reasonis no longertool_use.
Running this through SubToAPI
If your team already pays for Claude through a subscription rather than per-token API billing, you can still use this exact tool-use schema format. SubToAPI turns your Claude access into a standard HTTPS API with sub_live_... application keys, so the same /v1/messages request shape — including tools, tool_choice, and streaming — works without changing your integration code.
curl https://api.subtoapi.app/v1/messages \
-H "Authorization: Bearer $SUBTOAPI_KEY" \
-H "content-type: application/json" \
-d '{
"model": "claude-sonnet-4-5",
"max_tokens": 1024,
"tools": [ /* same schema as above */ ],
"messages": [{ "role": "user", "content": "Book a room for 2 guests in Lisbon" }]
}'
This is useful when multiple developers on a team need API-style access without each person managing separate billing — see /docs/tools for the full tool-use reference, /docs/messages for request/response formats, and /pricing for Solo, Team, and Scale plans. A free trial is available at /signup.
FAQ
Does Claude support OpenAI-style "functions" syntax? No. Claude uses a tools array with name, description, and input_schema (JSON Schema), returned as a tool_use content block — conceptually similar to OpenAI functions but with different field names and response structure.
Can I force Claude to always call a specific tool? Yes, set tool_choice to {"type": "tool", "name": "your_tool_name"}. This is commonly used to get strictly structured JSON output rather than free-text responses.
Why does Claude call the wrong tool when I have several defined? Usually because tool descriptions overlap or are too generic. Write descriptions that clearly state when a tool should and shouldn't be used, and keep input schemas as flat and explicit as possible.