# Anthropic — Structured outputs (`output_config.format`, strict tools) **Status:** `DOCUMENTED` · `LIVE_VERIFIED` (claude-haiku-4-5-20251001, 8 calls). GA on the Claude API since 2025-12-04 (no beta header; `structured-outputs-2025-11-13` and top-level `output_format` were transition-period only — live: `output_format` now returns 400). **Sources:** [Structured outputs](https://platform.claude.com/docs/en/build-with-claude/structured-outputs) · [Strict tool use](https://platform.claude.com/docs/en/agents-and-tools/tool-use/strict-tool-use) · [Messages API](https://platform.claude.com/docs/en/api/messages/create) · [Release notes](https://platform.claude.com/docs/en/release-notes/api) **Last verified:** 2026-09-18 ## Request ```json {"model": "claude-haiku-4-5-20251001", "max_tokens": 100, "output_config": {"format": {"type": "json_schema", "schema": { "type": "object", "properties": {"name": {"type": "string"}, "age": {"type": "integer"}, "city": {"type": "string"}}, "required": ["name", "age", "city"], "additionalProperties": false}}}, "messages": [{"role": "user", "content": "Ada is 36 and lives in Lyon. Extract the person."}]} ``` Response: a single `text` block containing valid JSON — live `{"name":"Ada","age":36,"city":"Lyon"}` (205 input / 16 output tokens). Strict tools: `tools[].strict: true` → grammar-constrained `tool_use.input` (live with `tool_choice: {type: tool}` → `{"name":"Ada","age":36,"city":"Lyon"}`; the block also carried `caller: {"type": "direct"}`). SDK helpers: Python `client.messages.parse(output_format=PydanticModel)` (→ `parsed_output`, still accepts `output_format` as convenience), TypeScript `zodOutputFormat()` / `jsonSchemaOutputFormat()`, Java `outputConfig(Class)`, Ruby `output_config: {format: Model}`. Python/TS/Ruby/PHP SDKs transform unsupported constraints (strip `minimum`, etc., add `additionalProperties: false`, move constraints into descriptions, validate locally). ## Supported models All active models: Fable 5.1/5, Mythos 5.1/5/Preview, Opus 5, 4.8, 4.7, 4.6, 4.5, Sonnet 5, 4.6, 4.5, Haiku 4.5 (Models API `capabilities.structured_outputs.supported: true` for all 11 listed ids). Bedrock: Opus 4.6, Sonnet 4.6, Sonnet 4.5, Opus 4.5, Haiku 4.5. ## JSON Schema subset | Supported | Not supported (→ 400 with details) | |---|---| | types object, array, string, integer, number, boolean, null | recursive schemas | | `enum` (strings/numbers/bools/nulls) — casing of returned enum/const values not guaranteed | complex types inside `enum` | | `const` | external `$ref` (`http://…`) | | `anyOf`, `allOf` (not `allOf` + `$ref`) | numeric constraints `minimum`/`maximum`/`multipleOf` — live: `400 output_config.format.schema: For 'integer' type, property 'minimum' is not supported` | | `$ref`, `$defs`, `definitions` (internal) | string constraints `minLength`/`maxLength` | | `default` | array constraints other than `minItems` 0/1 | | `required`, `additionalProperties: false` (objects must set it) | `additionalProperties` ≠ false; `patternProperties` — live: `400 … For 'object' type, property 'patternProperties' is not supported` | | formats `date-time`, `time`, `date`, `duration`, `email`, `hostname`, `uri`, `ipv4`, `ipv6`, `uuid` | other formats | | `minItems` 0 or 1 | | | `pattern`: `^…$`, `* + ? {n,m}` (simple), classes `[] . \d \w \s`, groups | backreferences, lookaround, `\b`, large `{n,m}` | **Complexity limits:** 20 strict tools/request; 24 optional parameters total; 16 union-typed parameters (`anyOf`, type arrays); internal grammar size limit → `400 Schema is too complex for compilation`; compile timeout 180 s. ## Behaviour * **Property order**: required properties first (schema order), then optional ones. * **Grammar compilation**: first use of a schema adds latency (live: 2.2 s first call vs 0.9 s streaming re-use; strict tool first call 14.7 s); compiled grammars cached **24 h** since last use; cache keyed on schema structure + tool set (not `name`/`description`). * **Prompt**: an extra system prompt is injected (more input tokens); changing `output_config.format` invalidates the prompt cache. Grammar applies only to the final text output, not to tool calls/results or thinking. * **Invalid outputs**: `stop_reason: "refusal"` (200, may not match schema), `stop_reason: "max_tokens"` (truncated JSON → raise `max_tokens`), enum casing drift. * **Data**: ZDR for prompts/responses, but the schema itself is cached 24 h — never put PHI in schema names/enums/patterns. ## Compatibility | Feature | Result | |---|---| | Streaming | ✔ JSON arrives as ordinary `text_delta` chunks (live) — accumulate then parse | | Token counting | ✔ `count_tokens` accepts `output_config.format` without compiling (live: 205 tokens, same as the real call) | | Batches | ✔ 50 % discount | | Strict tools + JSON output together | ✔ | | Thinking | ✔ grammar state resets between thinking and text | | Citations | ✘ `400 Citations cannot be enabled when output format is set. Please disable citations on uploaded document blocks.` (live) | | Assistant prefill | ✘ | | `max_tokens: 0` pre-warm | ✘ | | On-demand `compaction` | ✘ (rejected on summarize requests) | | Legacy `output_format` | ✘ `400 output_format: This field is deprecated. Use 'output_config.format' instead.` (live) | ## Examples & tests `examples/anthropic/structured-output/` (sh/py/ts) · `tests/anthropic/test_structured_output.py`.