File: structured-outputs.md | Updated: 11/15/2025
Agent Skills are now available! Learn more about extending Claude's capabilities with Agent Skills .
English
Search...
Ctrl K
Search...
Navigation
Capabilities
Structured outputs
Home Developer Guide API Reference Model Context Protocol (MCP) Resources Release Notes
On this page
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 .
Without structured outputs, Claude can generate malformed JSON responses or invalid tool inputs that break your applications. Even with careful prompting, you may encounter:
Structured outputs guarantee schema-compliant responses through constrained decoding:
JSON.parse() errorsShell
Python
TypeScript
Copy
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 (john@example.com) 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
Copy
{
"name": "John Smith",
"email": "john@example.com",
"plan_interest": "Enterprise",
"demo_requested": true
}
Choose the right mode for your use case:
| Use JSON outputs when | Use strict tool use when | | --- | --- | | You need Claude’s response in a specific format | You need validated parameters and tool names for tool calls | | Extracting data from images or text | Building agentic workflows | | Generating structured reports | Ensuring type-safe function calls | | Formatting API responses | Complex 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:
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.
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.
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.
Python
TypeScript
Copy
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 (john@example.com) 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 (john@example.com) 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.
Example usage
Copy
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.Example usage
Copy
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:
minimum, maximum, minLength, maxLength)additionalProperties: false to all objectsThis 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.
Data extraction (JSON outputs)
Extract structured data from unstructured text:
Python
TypeScript
Copy
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}"}]
)
Classification (JSON outputs)
Classify content with structured categories:
Python
TypeScript
Copy
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}"}]
)
API response formatting (JSON outputs)
Generate API-ready responses:
Python
TypeScript
Copy
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: ..."}]
)
Validated tool inputs (strict tool use)
Ensure tool parameters exactly match your schema:
Python
TypeScript
Copy
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\
}\
}]
)
Agentic workflow with multiple validated tools (strict tool use)
Build reliable multi-step agents with guaranteed tool parameters:
Python
TypeScript
Copy
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\
}\
}\
]
)
Grammar compilation and caching
Structured outputs use constrained sampling with compiled grammar artifacts. This introduces some performance characteristics to be aware of:
name or description fields does not invalidate the cachePrompt modification and token costs
When using structured outputs, Claude automatically receives an additional system prompt explaining the expected output format. This means:
output_format parameter will invalidate any prompt cache
for that conversation threadJSON Schema limitations
Structured outputs support standard JSON Schema with some limitations. Both JSON outputs and strict tool use share these limitations.
Supported features
enum (strings, numbers, bools, or nulls only - no complex types)constanyOf and allOf (with limitations - allOf with $ref not supported)$ref, $def, and definitions (external $ref not supported)default property for all supported typesrequired and additionalProperties (must be set to false for objects)date-time, time, date, duration, email, hostname, uri, ipv4, ipv6, uuidminItems (only values 0 and 1 supported)Not supported
$ref (e.g., '$ref': 'http://...')minimum, maximum, multipleOf, etc.)minLength, maxLength)minItems of 0 or 1additionalProperties set to anything other than falseIf you use an unsupported feature, you’ll receive a 400 error with details.
Pattern support (regex)
Supported regex features:
^...$) and partial matching*, +, ?, simple {n,m} cases[], ., \d, \w, \s(...)NOT supported:
\1, \2)(?=...), (?!...))\b, \B{n,m} quantifiers with large rangesSimple 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:
stop_reason: "refusal"Token limit reached (stop_reason: "max_tokens") If the response is cut off due to reaching the max_tokens limit:
stop_reason: "max_tokens"max_tokens value to get the complete structured outputSchema validation errors
If your schema uses unsupported features or is too complex, you’ll receive a 400 error: “Too many recursive definitions in schema”
“Schema is too complex”
strict: trueFor persistent issues with valid schemas, contact support with your schema definition.
Works with:
output_format) and strict tool use (strict: true) together in the same requestIncompatible with:
output_format.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.
Was this page helpful?
YesNo
Search results Google Sheets add-on
Assistant
Responses are generated using AI and may contain mistakes.