← Blog

Claude API JSON Schema Tool Definitions, Explained

2026-10-04 · 5 min read · SubToAPI Team

When you give Claude access to tools (also called function calling), each tool needs a JSON schema that describes its name, purpose, and input parameters. Claude reads this schema to decide when to call the tool and what arguments to pass. Getting the schema right is the difference between reliable tool use and Claude guessing at malformed arguments or refusing to call anything at all.

This article covers how Claude API tool definitions are structured, the JSON Schema subset Claude actually supports, common mistakes, and a working example you can adapt directly.

What a tool definition looks like

A tool definition is a plain JSON object with three required fields: name, description, and input_schema. The input_schema field is standard JSON Schema, restricted to the subset Claude's models are trained to parse reliably.

{
  "name": "get_weather",
  "description": "Get the current weather for a given city and unit of measurement.",
  "input_schema": {
    "type": "object",
    "properties": {
      "city": {
        "type": "string",
        "description": "The city name, e.g. 'Berlin' or 'Austin'"
      },
      "unit": {
        "type": "string",
        "enum": ["celsius", "fahrenheit"],
        "description": "Temperature unit to return"
      }
    },
    "required": ["city"]
  }
}

You pass an array of these tool objects in the tools field of your request, alongside your messages. Claude decides on its own whether a tool call is needed, which tool to use, and what arguments to populate — you don't force it unless you use tool_choice.

The JSON Schema subset that actually works well

Claude supports most of core JSON Schema, but a few patterns produce far better results than others:

{
  "name": "tags",
  "type": "array",
  "items": { "type": "string" }
}

Leaving items out is a common source of Claude passing malformed array arguments.

A multi-parameter example

Here's a more realistic tool definition for a function that creates calendar events:

{
  "name": "create_event",
  "description": "Create a calendar event with a title, start time, and optional attendees.",
  "input_schema": {
    "type": "object",
    "properties": {
      "title": {
        "type": "string",
        "description": "Short title of the event"
      },
      "start_time": {
        "type": "string",
        "description": "ISO 8601 datetime, e.g. 2024-06-01T14:00:00Z"
      },
      "duration_minutes": {
        "type": "integer",
        "description": "Event length in minutes",
        "minimum": 5
      },
      "attendees": {
        "type": "array",
        "items": { "type": "string" },
        "description": "Email addresses of attendees"
      }
    },
    "required": ["title", "start_time"]
  }
}

Notice duration_minutes uses minimum as a constraint hint and attendees declares its items type. Claude will generally respect numeric constraints like minimum and maximum as guidance, though it's still good practice to validate the returned arguments server-side before executing anything — the schema shapes Claude's output, it doesn't guarantee it.

Common mistakes to avoid

  1. Vague descriptions. "The input" tells Claude nothing. Be specific about format, units, and edge cases.
  2. Missing required arrays. Without it, Claude may omit fields you actually need.
  3. Overloaded tools. A single tool with 15 optional parameters covering five different actions performs worse than five focused tools. Split by use case.
  4. Forgetting to handle tool_use stop reasons. When Claude decides to call a tool, the response has stop_reason: "tool_use" and a tool_use content block with the arguments. Your code needs to parse that, execute the tool, and send the result back in a tool_result block to continue the conversation.
  5. Not testing with edge-case inputs. Try ambiguous prompts to see if Claude picks the right tool and fills in sensible defaults for optional fields.

Testing your schemas without a full backend

If you're prototyping and don't want to stand up a complete Anthropic integration (billing, key rotation, usage dashboards) just to test tool schemas, SubToAPI gives you an HTTPS endpoint — sub_live_... keys — that wraps Claude access, including tool use and streaming. You send the same tools array and input_schema structure described above:

curl https://api.subtoapi.app/v1/messages \
  -H "Authorization: Bearer $SUBTOAPI_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-3-5-sonnet",
    "max_tokens": 1024,
    "tools": [{
      "name": "get_weather",
      "description": "Get current weather for a city",
      "input_schema": {
        "type": "object",
        "properties": {
          "city": {"type": "string"}
        },
        "required": ["city"]
      }
    }],
    "messages": [{"role": "user", "content": "What is the weather in Porto?"}]
  }'

See the tools documentation for the full request/response shape, or start with the quickstart if you're setting up your first API key. Plans start at Solo (€9) with a free trial at signup; pricing details are on the pricing page.

questions

Do I need to use strict JSON Schema validators, or does Claude handle loose schemas? Claude parses standard JSON Schema but performs best with simple, flat structures. Avoid $ref, complex oneOf/allOf combinations, and undocumented fields — stick to type, properties, required, enum, and items.

Can I force Claude to always call a specific tool? Yes, using tool_choice you can require a specific tool or force any tool call instead of a free-text response. Without it, Claude decides autonomously based on the user's message and the tool descriptions.

What happens if Claude's tool call arguments don't match my schema? Claude is trained to follow the schema closely, but you should still validate the parsed arguments server-side before executing the tool, since no model guarantees 100% schema compliance on every call.

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 →