Pydantic + parse (recommended)
from pydantic import BaseModel
class ContactInfo(BaseModel):
name: str
email: str
plan: str
demo_requested: bool
response = client.messages.parse(
model="claude-fable-5",
max_tokens=16000,
messages=[{"role": "user", "content": "Extract: Jane Doe (jane@co.com) wants Enterprise, wants a demo."}],
output_format=ContactInfo,
)
contact = response.parsed_output # a validated ContactInfo instance
print(contact.name) # "Jane Doe"
Raw schema
When you don't want Pydantic, pass the schema directly. Note it's output_config.format — the older top-level output_format param on create() is deprecated:
response = client.messages.create(
model="claude-fable-5",
max_tokens=16000,
messages=[{"role": "user", "content": document}],
output_config={"format": {
"type": "json_schema",
"schema": {
"type": "object",
"properties": {"name": {"type": "string"}, "email": {"type": "string"}},
"required": ["name", "email"],
"additionalProperties": False,
},
}},
)
Strict tool parameters
Add "strict": true to a tool definition and the API guarantees the tool call's input matches your schema — no more hand-validating enum fields.
Limits worth knowing
- Every object needs
additionalProperties: false. No recursive schemas; no numeric/string constraints likeminimumormaxLength(the Python/TS SDKs strip those and validate client-side). - First request with a new schema pays a one-time compilation cost; it's cached for 24 hours after.
- Incompatible with citations. If
stop_reasonismax_tokens, the JSON may be truncated — raise the cap.
Moral: never parse what you can guarantee.