Structured outputs constrain Claude’s responses to follow a specific schema, ensuring valid, parseable output for downstream processing. Use JSON outputs (output_format) for structured data responses, or strict tool use (strict: true) for guaranteed schema validation on tool names and inputs.
Structured outputs are currently available as a public beta feature in the Claude API for Claude Sonnet 4.5 and Claude Opus 4.1.To use the feature, set the beta header structured-outputs-2025-11-13.
Share feedback using this form.

Why use structured outputs

Without structured outputs, Claude can generate malformed JSON responses or invalid tool inputs that break your applications. Even with careful prompting, you may encounter:
  • Parsing errors from invalid JSON syntax
  • Missing required fields
  • Inconsistent data types
  • Schema violations requiring error handling and retries
Structured outputs guarantee schema-compliant responses through constrained decoding:
  • Always valid: No more JSON.parse() errors
  • Type safe: Guaranteed field types and required fields
  • Reliable: No retries needed for schema violations
  • Two modes: JSON for tasks like data extraction, and strict tools for situations like complex tools and agentic workflows

Quick start

curl https://api.anthropic.com/v1/messages \
  -H "content-type: application/json" \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "anthropic-beta: structured-outputs-2025-11-13" \
  -d '{
    "model": "claude-sonnet-4-5",
    "max_tokens": 1024,
    "messages": [
      {
        "role": "user",
        "content": "Extract the key information from this email: John Smith ([email protected]) is interested in our Enterprise plan and wants to schedule a demo for next Tuesday at 2pm."
      }
    ],
    "output_format": {
      "type": "json_schema",
      "schema": {
        "type": "object",
        "properties": {
          "name": {"type": "string"},
          "email": {"type": "string"},
          "plan_interest": {"type": "string"},
          "demo_requested": {"type": "boolean"}
        },
        "required": ["name", "email", "plan_interest", "demo_requested"],
        "additionalProperties": false
      }
    }
  }'
Response format: Valid JSON matching your schema in response.content[0].text
{
  "name": "John Smith",
  "email": "[email protected]",
  "plan_interest": "Enterprise",
  "demo_requested": true
}

When to use JSON outputs vs strict tool use

Choose the right mode for your use case:
Use JSON outputs whenUse strict tool use when
You need Claude’s response in a specific formatYou need validated parameters and tool names for tool calls
Extracting data from images or textBuilding agentic workflows
Generating structured reportsEnsuring type-safe function calls
Formatting API responsesComplex tools with many and/or nested properties

Why strict tool use matters for agents

Building reliable agentic systems requires guaranteed schema conformance. Invalid tool parameters break your functions and workflows. Claude might return incompatible types ("2" instead of 2) or missing fields, causing runtime errors. Strict tool use guarantees type-safe parameters:
  • Functions receive correctly-typed arguments every time
  • No need to validate and retry tool calls
  • Production-ready agents that work consistently at scale
For example, suppose a booking system needs passengers: int. Without strict mode, Claude might provide passengers: "two" or passengers: "2". With strict: true, you’re guaranteed passengers: 2.

How structured outputs work

Implement JSON structured outputs with these steps:
1

Define your JSON schema

Create a JSON schema that describes the structure you want Claude to follow. The schema uses standard JSON Schema format with some limitations (see JSON Schema limitations).
2

Add the output_format parameter

Include the output_format parameter in your API request with type: "json_schema" and your schema definition.
3

Include the beta header

Add the anthropic-beta: structured-outputs-2025-11-13 header to your request.
4

Parse the response

Claude’s response will be valid JSON matching your schema, returned in response.content[0].text.

Working with JSON outputs in SDKs

The Python and TypeScript SDKs provide helpers that make it easier to work with JSON outputs, including schema transformation, automatic validation, and integration with popular schema libraries.

Using Pydantic and Zod

For Python and TypeScript developers, you can use familiar schema definition tools like Pydantic and Zod instead of writing raw JSON schemas.
JSON outputs onlySDK helpers (Pydantic, Zod, parse()) only work with JSON outputs (output_format).These helpers transform and validate Claude’s output to you. Strict tool use validates Claude’s input to your tools, which use the existing input_schema field in tool definitions.For strict tool use, define your input_schema directly in the tool definition with strict: true.
from pydantic import BaseModel
from anthropic import Anthropic, transform_schema

class ContactInfo(BaseModel):
    name: str
    email: str
    plan_interest: str
    demo_requested: bool

client = Anthropic()

# With .create() - requires transform_schema()
response = client.beta.messages.create(
    model="claude-sonnet-4-5",
    max_tokens=1024,
    betas=["structured-outputs-2025-11-13"],
    messages=[
        {
            "role": "user",
            "content": "Extract the key information from this email: John Smith ([email protected]) is interested in our Enterprise plan and wants to schedule a demo for next Tuesday at 2pm."
        }
    ],
    output_format={
        "type": "json_schema",
        "schema": transform_schema(ContactInfo),
    }
)

print(response.content[0].text)

# With .parse() - can pass Pydantic model directly
response = client.beta.messages.parse(
    model="claude-sonnet-4-5",
    max_tokens=1024,
    betas=["structured-outputs-2025-11-13"],
    messages=[
        {
            "role": "user",
            "content": "Extract the key information from this email: John Smith ([email protected]) is interested in our Enterprise plan and wants to schedule a demo for next Tuesday at 2pm."
        }
    ],
    output_format=ContactInfo,
)

print(response.parsed_output)

SDK-specific methods

Python: client.beta.messages.parse() (Recommended) The parse() method automatically transforms your Pydantic model, validates the response, and returns a parsed_output attribute.
The parse() method is available on client.beta.messages, not client.messages.
from pydantic import BaseModel
import anthropic

class ContactInfo(BaseModel):
    name: str
    email: str
    plan_interest: str

client = anthropic.Anthropic()

response = client.beta.messages.parse(
    model="claude-sonnet-4-5",
    betas=["structured-outputs-2025-11-13"],
    max_tokens=1024,
    messages=[{"role": "user", "content": "..."}],
    output_format=ContactInfo,
)

# Access the parsed output directly
contact = response.parsed_output
print(contact.name, contact.email)
Python: transform_schema() helper For when you need to manually transform schemas before sending, or when you want to modify a Pydantic-generated schema. Unlike client.beta.messages.parse(), which transforms provided schemas automatically, this gives you the transformed schema so you can further customize it.
from anthropic import transform_schema
from pydantic import TypeAdapter

# First convert Pydantic model to JSON schema, then transform
schema = TypeAdapter(ContactInfo).json_schema()
schema = transform_schema(schema)
# Modify schema if needed
schema["properties"]["custom_field"] = {"type": "string"}

response = client.beta.messages.create(
    model="claude-sonnet-4-5",
    betas=["structured-outputs-2025-11-13"],
    max_tokens=1024,
    output_format=schema,
    messages=[{"role": "user", "content": "..."}],
)

How SDK transformation works

Both Python and TypeScript SDKs automatically transform schemas with unsupported features:
  1. Remove unsupported constraints (e.g., minimum, maximum, minLength, maxLength)
  2. Update descriptions with constraint info (e.g., “Must be at least 100”), when the constraint is not directly supported with structured outputs
  3. Add additionalProperties: false to all objects
  4. Filter string formats to supported list only
  5. Validate responses against your original schema (with all constraints)
This means Claude receives a simplified schema, but your code still enforces all constraints through validation. Example: A Pydantic field with minimum: 100 becomes a plain integer in the sent schema, but the description is updated to “Must be at least 100”, and the SDK validates the response against the original constraint.

Common use cases

Extract structured data from unstructured text:
from pydantic import BaseModel
from typing import List

class Invoice(BaseModel):
    invoice_number: str
    date: str
    total_amount: float
    line_items: List[dict]
    customer_name: str

response = client.beta.messages.parse(
    model="claude-sonnet-4-5",
    betas=["structured-outputs-2025-11-13"],
    output_format=Invoice,
    messages=[{"role": "user", "content": f"Extract invoice data from: {invoice_text}"}]
)
Classify content with structured categories:
from pydantic import BaseModel
from typing import List

class Classification(BaseModel):
    category: str
    confidence: float
    tags: List[str]
    sentiment: str

response = client.beta.messages.parse(
    model="claude-sonnet-4-5",
    betas=["structured-outputs-2025-11-13"],
    output_format=Classification,
    messages=[{"role": "user", "content": f"Classify this feedback: {feedback_text}"}]
)
Generate API-ready responses:
from pydantic import BaseModel
from typing import List, Optional

class APIResponse(BaseModel):
    status: str
    data: dict
    errors: Optional[List[dict]]
    metadata: dict

response = client.beta.messages.parse(
    model="claude-sonnet-4-5",
    betas=["structured-outputs-2025-11-13"],
    output_format=APIResponse,
    messages=[{"role": "user", "content": "Process this request: ..."}]
)
Ensure tool parameters exactly match your schema:
response = client.beta.messages.create(
    model="claude-sonnet-4-5",
    betas=["structured-outputs-2025-11-13"],
    messages=[{"role": "user", "content": "Search for flights to Tokyo"}],
    tools=[{
        "name": "search_flights",
        "strict": True,
        "input_schema": {
            "type": "object",
            "properties": {
                "destination": {"type": "string"},
                "departure_date": {"type": "string", "format": "date"},
                "passengers": {"type": "integer", "enum": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]}
            },
            "required": ["destination", "departure_date"],
            "additionalProperties": False
        }
    }]
)
Build reliable multi-step agents with guaranteed tool parameters:
response = client.beta.messages.create(
    model="claude-sonnet-4-5",
    betas=["structured-outputs-2025-11-13"],
    messages=[{"role": "user", "content": "Help me plan a trip to Paris for 2 people"}],
    tools=[
        {
            "name": "search_flights",
            "strict": True,
            "input_schema": {
                "type": "object",
                "properties": {
                    "origin": {"type": "string"},
                    "destination": {"type": "string"},
                    "departure_date": {"type": "string", "format": "date"},
                    "travelers": {"type": "integer", "enum": [1, 2, 3, 4, 5, 6]}
                },
                "required": ["origin", "destination", "departure_date"],
                "additionalProperties": False
            }
        },
        {
            "name": "search_hotels",
            "strict": True,
            "input_schema": {
                "type": "object",
                "properties": {
                    "city": {"type": "string"},
                    "check_in": {"type": "string", "format": "date"},
                    "guests": {"type": "integer", "enum": [1, 2, 3, 4]}
                },
                "required": ["city", "check_in"],
                "additionalProperties": False
            }
        }
    ]
)

Important considerations

Grammar compilation and caching

Structured outputs use constrained sampling with compiled grammar artifacts. This introduces some performance characteristics to be aware of:
  • First request latency: The first time you use a specific schema, there will be additional latency while the grammar is compiled
  • Automatic caching: Compiled grammars are cached for 24 hours from last use, making subsequent requests much faster
  • Cache invalidation: The cache is invalidated if you change:
    • The JSON schema structure
    • The set of tools in your request (when using both structured outputs and tool use)
    • Changing only name or description fields does not invalidate the cache

Prompt modification and token costs

When using structured outputs, Claude automatically receives an additional system prompt explaining the expected output format. This means:
  • Your input token count will be slightly higher
  • The injected prompt costs you tokens like any other system prompt
  • Changing the output_format parameter will invalidate any prompt cache for that conversation thread

JSON Schema limitations

Structured outputs support standard JSON Schema with some limitations. Both JSON outputs and strict tool use share these limitations.
  • All basic types: object, array, string, integer, number, boolean, null
  • enum (strings, numbers, bools, or nulls only - no complex types)
  • const
  • anyOf and allOf (with limitations - allOf with $ref not supported)
  • $ref, $def, and definitions (external $ref not supported)
  • default property for all supported types
  • required and additionalProperties (must be set to false for objects)
  • String formats: date-time, time, date, duration, email, hostname, uri, ipv4, ipv6, uuid
  • Array minItems (only values 0 and 1 supported)
  • Recursive schemas
  • Complex types within enums
  • External $ref (e.g., '$ref': 'http://...')
  • Numerical constraints (minimum, maximum, multipleOf, etc.)
  • String constraints (minLength, maxLength)
  • Array constraints beyond minItems of 0 or 1
  • additionalProperties set to anything other than false
If you use an unsupported feature, you’ll receive a 400 error with details.
Supported regex features:
  • Full matching (^...$) and partial matching
  • Quantifiers: *, +, ?, simple {n,m} cases
  • Character classes: [], ., \d, \w, \s
  • Groups: (...)
NOT supported:
  • Backreferences to groups (e.g., \1, \2)
  • Lookahead/lookbehind assertions (e.g., (?=...), (?!...))
  • Word boundaries: \b, \B
  • Complex {n,m} quantifiers with large ranges
Simple regex patterns work well. Complex patterns may result in 400 errors.
The Python and TypeScript SDKs can automatically transform schemas with unsupported features by removing them and adding constraints to field descriptions. See SDK-specific methods for details.

Invalid outputs

While structured outputs guarantee schema compliance in most cases, there are scenarios where the output may not match your schema: Refusals (stop_reason: "refusal") Claude maintains its safety and helpfulness properties even when using structured outputs. If Claude refuses a request for safety reasons:
  • The response will have stop_reason: "refusal"
  • You’ll receive a 200 status code
  • You’ll be billed for the tokens generated
  • The output may not match your schema (the refusal takes precedence)
Token limit reached (stop_reason: "max_tokens") If the response is cut off due to reaching the max_tokens limit:
  • The response will have stop_reason: "max_tokens"
  • The output may be incomplete and not match your schema
  • Retry with a higher max_tokens value to get the complete structured output

Schema validation errors

If your schema uses unsupported features or is too complex, you’ll receive a 400 error: “Too many recursive definitions in schema”
  • Cause: Schema has excessive or cyclic recursive definitions
  • Solution: Simplify schema structure, reduce nesting depth
“Schema is too complex”
  • Cause: Schema exceeds complexity limits
  • Solution: Break into smaller schemas, simplify structure, or reduce the number of tools marked as strict: true
For persistent issues with valid schemas, contact support with your schema definition.

Feature compatibility

Works with:
  • Batch processing: Process structured outputs at scale with 50% discount
  • Token counting: Count tokens without compilation
  • Streaming: Stream structured outputs like normal responses
  • Combined usage: Use JSON outputs (output_format) and strict tool use (strict: true) together in the same request
Incompatible with:
  • Citations: Citations require interleaving citation blocks with text, which conflicts with strict JSON schema constraints. Returns 400 error if citations enabled with output_format.
  • Message Prefilling: Incompatible with JSON outputs
Grammar scope: Grammars apply only to Claude’s direct output, not to tool use calls, tool results, or thinking tags (when using Extended Thinking). Grammar state resets between sections, allowing Claude to think freely while still producing structured output in the final response.