Structured outputs constrain Claude's responses to follow a specific schema, ensuring valid, parseable output for downstream processing. Two complementary features are available:
output_format): Get Claude's response in a specific JSON formatstrict: true): Guarantee schema validation on tool names and inputsThese features can be used independently or together in the same request.
Structured outputs are currently available as a public beta feature in the Claude API for Claude Sonnet 4.5, Claude Opus 4.1, Claude Opus 4.5, and Claude Haiku 4.5.
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() errorsJSON outputs control Claude's response format, ensuring Claude returns valid JSON matching your schema. Use JSON outputs when you need to:
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
}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).
Add the output_format parameter
Include the output_format parameter in your API request with type: "json_schema" and your schema definition.
Include the beta header
Add the anthropic-beta: structured-outputs-2025-11-13 header to your request.
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.
For Python and TypeScript developers, you can use familiar schema definition tools like Pydantic and Zod instead of writing raw JSON schemas.
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)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.
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.
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.
Strict tool use validates tool parameters, ensuring Claude calls your functions with correctly-typed arguments. Use strict tool use when you need to:
Building reliable agentic systems requires guaranteed schema conformance. Without strict mode, Claude might return incompatible types ("2" instead of 2) or missing required fields, breaking your functions and 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, the response will always contain passengers: 2.
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": "What is the weather in San Francisco?"}
],
"tools": [{
"name": "get_weather",
"description": "Get the current weather in a given location",
"strict": true,
"input_schema": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"]
}
},
"required": ["location"],
"additionalProperties": false
}
}]
}'Response format: Tool use blocks with validated inputs in response.content[x].input
{
"type": "tool_use",
"name": "get_weather",
"input": {
"location": "San Francisco, CA"
}
}Guarantees:
input strictly follows the input_schemaname is always valid (from provided tools or server tools)Define your tool schema
Create a JSON schema for your tool's input_schema. The schema uses standard JSON Schema format with some limitations (see JSON Schema limitations).
Add strict: true
Set "strict": true as a top-level property in your tool definition, alongside name, description, and input_schema.
Include the beta header
Add the anthropic-beta: structured-outputs-2025-11-13 header to your request.
Handle tool calls
When Claude uses the tool, the input field in the tool_use block will strictly follow your input_schema, and the name will always be valid.
JSON outputs and strict tool use solve different problems and can be used together:
When combined, Claude can call tools with guaranteed-valid parameters AND return structured JSON responses. This is useful for agentic workflows where you need both reliable tool calls and structured final outputs.
response = client.beta.messages.create(
model="claude-sonnet-4-5",
betas=["structured-outputs-2025-11-13"],
max_tokens=1024,
messages=[{"role": "user", "content": "Help me plan a trip to Paris for next month"}],
# JSON outputs: structured response format
output_format={
"type": "json_schema",
"schema": {
"type": "object",
"properties": {
"summary": {"type": "string"},
"next_steps": {"type": "array", "items": {"type": "string"}}
},
"required": ["summary", "next_steps"],
"additionalProperties": False
}
},
# Strict tool use: guaranteed tool parameters
tools=[{
"name": "search_flights",
"strict": True,
"input_schema": {
"type": "object",
"properties": {
"destination": {"type": "string"},
"date": {"type": "string", "format": "date"}
},
"required": ["destination", "date"],
"additionalProperties": False
}
}]
)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 cacheWhen 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 threadStructured outputs support standard JSON Schema with some limitations. Both JSON outputs and strict tool use share these limitations.
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.
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 outputIf 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.