← Blog

Claude API Function Calling: JSON Example & Walkthrough

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

Claude's "function calling" — officially called tool use — lets you define JSON-schema functions that the model can request to call. Instead of parsing free-text answers, you get a structured JSON object back with the function name and arguments, which you execute and feed back into the conversation.

This article walks through a complete, working JSON example: defining a tool, sending the request, reading the model's tool call, and returning the result so Claude can finish the task. If you've searched for "claude api function calling json example," this is the end-to-end shape you need.

The basic request shape

A tool-use request has three parts: the model, the messages, and a tools array describing each function as a JSON schema. Here's a minimal weather-lookup example:

{
  "model": "claude-opus-4",
  "max_tokens": 1024,
  "messages": [
    {
      "role": "user",
      "content": "What's the weather in Lisbon right now?"
    }
  ],
  "tools": [
    {
      "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. Lisbon"
          },
          "unit": {
            "type": "string",
            "enum": ["celsius", "fahrenheit"]
          }
        },
        "required": ["city"]
      }
    }
  ]
}

The input_schema is a standard JSON Schema object. Claude uses the description fields — both on the tool and on each property — to decide whether and how to call the function, so write them like documentation, not placeholders.

What Claude returns

When Claude decides to use the tool, the response content includes a tool_use block instead of (or alongside) plain text:

{
  "id": "msg_01abc",
  "role": "assistant",
  "stop_reason": "tool_use",
  "content": [
    {
      "type": "text",
      "text": "Let me check that for you."
    },
    {
      "type": "tool_use",
      "id": "toolu_01xyz",
      "name": "get_weather",
      "input": {
        "city": "Lisbon",
        "unit": "celsius"
      }
    }
  ]
}

Two things matter here: stop_reason is "tool_use" (your code should branch on this), and the input object already matches your schema — no regex parsing of a text response required.

Sending the result back

You execute get_weather("Lisbon", "celsius") in your own code, then send a new message with a tool_result block referencing the same tool_use.id:

{
  "model": "claude-opus-4",
  "max_tokens": 1024,
  "messages": [
    { "role": "user", "content": "What's the weather in Lisbon right now?" },
    {
      "role": "assistant",
      "content": [
        {
          "type": "tool_use",
          "id": "toolu_01xyz",
          "name": "get_weather",
          "input": { "city": "Lisbon", "unit": "celsius" }
        }
      ]
    },
    {
      "role": "user",
      "content": [
        {
          "type": "tool_result",
          "tool_use_id": "toolu_01xyz",
          "content": "18°C, partly cloudy"
        }
      ]
    }
  ],
  "tools": [ /* same tool definitions as before */ ]
}

Claude then produces a final natural-language answer using that result. This round trip — call, execute, return result, get final answer — is the full function-calling loop.

A full curl example

curl https://api.subtoapi.app/v1/messages \
  -H "Authorization: Bearer $SUBTOAPI_KEY" \
  -H "content-type: application/json" \
  -d '{
    "model": "claude-opus-4",
    "max_tokens": 1024,
    "messages": [
      {"role": "user", "content": "Convert 100 USD to EUR"}
    ],
    "tools": [
      {
        "name": "convert_currency",
        "description": "Convert an amount from one currency to another",
        "input_schema": {
          "type": "object",
          "properties": {
            "amount": {"type": "number"},
            "from": {"type": "string"},
            "to": {"type": "string"}
          },
          "required": ["amount", "from", "to"]
        }
      }
    ]
  }'

If you're running this through SubToAPI, the request/response shapes are identical to the native Anthropic API — you're just authenticating with a sub_live_... application key instead of a direct Anthropic key. That matters if you're shipping function calling inside a product and need per-app keys, usage metadata, and team seats rather than one shared account key. See /docs/messages and /docs/tools for the full parameter reference.

Handling multiple tools and multi-step calls

Real applications usually define several tools at once and let Claude pick:

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

Claude can also request multiple tool calls in sequence — look up weather, then convert a temperature unit, for example. Your application loop should:

  1. Send the request with tools.
  2. If stop_reason is "tool_use", extract every tool_use block in content.
  3. Execute each function locally, matching by name.
  4. Return a tool_result for each tool_use_id in a single follow-up message.
  5. Repeat until stop_reason is "end_turn".

This loop is the same whether you call Claude directly or through SubToAPI — the function-calling contract (names, schemas, tool_use/tool_result blocks) doesn't change, only the key and endpoint you authenticate against. Streaming responses follow the same tool-use events, just emitted incrementally; see /docs/streaming if you need partial input deltas for a long-running tool call.

Common mistakes in JSON tool definitions

Getting the JSON schema right the first time saves a lot of debugging later, since Claude's tool selection accuracy depends heavily on how well-described each function is.

questions

Does Claude's function calling return valid JSON automatically? Yes — the tool_use block's input field is a JSON object that conforms to the input_schema you defined, so no manual parsing of free text is needed.

Can I define multiple tools in one request? Yes, the tools array can contain any number of function definitions, and Claude chooses which one (if any) fits the user's request.

How do I test function calling without an Anthropic account? You can run the same JSON examples through SubToAPI using a sub_live_... key from /signup — the request and response format matches the native API exactly.

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 →