The two sides of this change are more than 400 edits apart, too far apart to line up, so this is the differ's own diff of it and the words inside a line are not marked.
from line 55
5555
5656Structured outputs guarantee schema-compliant responses through constrained decoding:
5757
58* **Always valid:** No more `JSON.parse()` errors
58* **Always valid:** No JSON parsing errors
5959* **Type safe:** Guaranteed field types and required fields
6060* **Reliable:** No retries needed for schema violations
6161
from line 203
203203 ```text Output wrap
204204 name='John Smith' email='[email protected]' plan_interest='Enterprise' demo_requested=True
205205 ```
206
207 If you know a field’s keys, use a nested Pydantic model, not a `dict`. The SDK sends a `dict` field as an object with empty `properties`, so Claude can only return `{}` for it. If you don’t know the keys in advance, see [Objects with arbitrary keys](https://platform.claude.com/docs/en/build-with-claude/structured-outputs#objects-with-arbitrary-keys).
206208 </Tab>
207209
208210 <Tab title="TypeScript">
from line 244
242244
243245 The previous example outputs:
244246
245 ```javascript Output
247 ```text Output wrap
246248 {
247249 name: 'John Smith',
from line 252
250252 demo_requested: true
251253 }
252254 ```
255
256 If you know a field’s keys, use `z.object()`, not `z.record()`. The SDK sends a `z.record()` field as an object with empty `properties`, so Claude can only return `{}` for it. If you don’t know the keys in advance, see [Objects with arbitrary keys](https://platform.claude.com/docs/en/build-with-claude/structured-outputs#objects-with-arbitrary-keys).
253257 </Tab>
254258
255259 <Tab title="C#">
from line 401
397401
398402 Key points:
399403
400 * **Local validation** occurs without sending requests to the remote AI model.
401 * **Remote validation** is also performed by the AI model upon receiving the JSON schema.
404 * **Local validation:** The SDK validates the schema without sending a request.
405 * **Remote validation:** The API also validates the JSON schema when it receives the request.
402406 * **Version compatibility:** If the SDK version is outdated, local validation might reject a schema that remote validation accepts.
403407 * **Disabling local validation:** Pass `JsonSchemaLocalValidation.NO` if you encounter compatibility issues:
404408
from line 446
442446 * There are no fields or getter methods in the class
443447 * All `public` members are annotated with `@JsonIgnore`
444448 * All non-`public` members lack `@JsonProperty` annotations
445 * A field uses a `Map` type, which produces an empty `"properties"` field
449 * A field uses a `Map` type, which produces an empty `"properties"` field (to avoid this, see [Objects with arbitrary keys](https://platform.claude.com/docs/en/build-with-claude/structured-outputs#objects-with-arbitrary-keys))
446450 </Accordion>
447451
448452 <Accordion title="Composition and inheritance">
from line 697
694698 "and wants to schedule a demo for next Tuesday at 2pm."
695699 }],
696 output_config: {format: ContactInfo}
700 output_config: { format: ContactInfo }
697701 )
698702
699703 contact = message.parsed_output
700704 puts contact
701705 ```
702706
703 Define a class that extends `Anthropic::BaseModel` and pass it to `messages.create()` as `output_config: {format: Model}`. The SDK derives a JSON schema from the class, transforms it, and assigns the parsed result to the response’s `parsed_output` attribute as a typed Ruby object.
707 Define a class that extends `Anthropic::BaseModel` and pass it to `messages.create()` as `output_config: { format: Model }`. The SDK derives a JSON schema from the class, transforms it, and assigns the parsed result to the response’s `parsed_output` attribute as a typed Ruby object.
704708
705709 The previous example outputs:
706710
from line 733
729733 message = client.messages.create(
730734 model: Anthropic::Model::CLAUDE_OPUS_5_5,
731735 max_tokens: 1024,
732 messages: [{role: "user", content: "give me some famous numbers"}],
733 output_config: {format: Output}
736 messages: [{ role: "user", content: "give me some famous numbers" }],
737 output_config: { format: Output }
734738 )
735739
736740 message.parsed_output
from line 934
930934
931935 The previous example outputs:
932936
933 ```javascript Output
937 ```text Output wrap
935939 ```
936940 </Tab>
from line 1141
11371141 ])),
11381142 );
11391143
1140 $textBlock = array_find($message->content, static fn ($block): bool => $block->type === 'text');
1144 $textBlock = array_find($message->content, static fn ($block): bool => $block instanceof \Anthropic\Messages\TextBlock)
1145 ?? throw new \RuntimeException('Expected a text block in the response.');
11411146 $contact = json_decode($textBlock->text, associative: true);
11421147 var_dump($contact);
11431148 ```
11441149
1145 Pass the schema as an associative array to `OutputConfig::with()`, and decode the response with `json_decode()`.
1150 Pass the schema as an associative array to `JSONOutputFormat::with()` inside `OutputConfig::with()`, and decode the response with `json_decode()`.
11461151
11471152 The previous example outputs:
11481153
from line 1227
12221227 "messages": [
12231228 {
12241229 "role": "user",
1225 "content": "Extract invoice data from: Invoice #12345, Date: 2024-01-15, Total: $500.00"
1230 "content": "Extract invoice data from: Invoice #12345, Date: 2024-01-15, Customer: Acme Corp, 2 widgets at $150.00 each, 1 setup fee at $200.00, Total: $500.00"
12261231 }
12271232 ],
12281233 "output_config": {
from line 1241
12361241 "total_amount": {"type": "number"},
12371242 "line_items": {
12381243 "type": "array",
1239 "items": {"type": "object", "additionalProperties": false}
1244 "items": {
1245 "type": "object",
1246 "properties": {
1247 "description": {"type": "string"},
1248 "quantity": {"type": "number"},
1249 "unit_price": {"type": "number"}
1250 },
1251 "required": ["description", "quantity", "unit_price"],
1252 "additionalProperties": false
1253 }
12401254 },
12411255 "customer_name": {"type": "string"}
12421256 },
from line 1268
12541268 max_tokens: 4096
12551269 messages:
12561270 - role: user
1257 content: "Extract invoice data from: Invoice #12345, Date: 2024-01-15, Total: $500.00"
1271 content: |
1272 Extract invoice data from:
1273 Invoice #12345
1274 Date: 2024-01-15
1275 Customer: Acme Corp
1276 2 widgets at $150.00 each
1277 1 setup fee at $200.00
1278 Total: $500.00
12581279 output_config:
12591280 format:
12601281 type: json_schema
from line 1287
12661287 total_amount: {type: number}
12671288 line_items:
12681289 type: array
1269 items: {type: object, additionalProperties: false}
1290 items:
1291 type: object
1292 properties:
1293 description: {type: string}
1294 quantity: {type: number}
1295 unit_price: {type: number}
1296 required: [description, quantity, unit_price]
1297 additionalProperties: false
12701298 customer_name: {type: string}
12711299 required: [invoice_number, date, total_amount, line_items, customer_name]
12721300 additionalProperties: false
from line 1305
12771305 from pydantic import BaseModel
12781306
12791307
1308 class LineItem(BaseModel):
1309 description: str
1310 quantity: float
1311 unit_price: float
1312
1313
12801314 class Invoice(BaseModel):
12811315 invoice_number: str
12821316 date: str
12831317 total_amount: float
1284 line_items: list[dict]
1318 line_items: list[LineItem]
12851319 customer_name: str
12861320
12871321
12881322 client = anthropic.Anthropic()
1289 invoice_text = "Invoice #12345, Date: 2024-01-15, Total: $500.00"
1323 invoice_text = """
1324 Invoice #12345
1325 Date: 2024-01-15
1326 Customer: Acme Corp
1327 2 widgets at $150.00 each
1328 1 setup fee at $200.00
1329 Total: $500.00
1330 """
12901331
12911332 response = client.messages.parse(
12921333 model="claude-opus-5-5",
from line 1347
13061347
13071348 const client = new Anthropic();
13081349
1350 const LineItemSchema = z.object({
1351 description: z.string(),
1352 quantity: z.number(),
1353 unit_price: z.number()
1354 });
1355
13091356 const InvoiceSchema = z.object({
13101357 invoice_number: z.string(),
13111358 date: z.string(),
13121359 total_amount: z.number(),
1313 line_items: z.array(z.record(z.string(), z.any())),
1360 line_items: z.array(LineItemSchema),
13141361 customer_name: z.string()
13151362 });
13161363
1317 const invoiceText = "Invoice #12345, Date: 2024-01-15, Total: $500.00";
1364 const invoiceText = `
1365 Invoice #12345
1366 Date: 2024-01-15
1367 Customer: Acme Corp
1368 2 widgets at $150.00 each
1369 1 setup fee at $200.00
1370 Total: $500.00
1371 `;
1372
13181373 const response = await client.messages.parse({
13191374 model: "claude-opus-5-5",
13201375 max_tokens: 4096,
from line 1382
13271382 ```csharp C#
13281383 AnthropicClient client = new();
13291384
1330 string invoiceText = "Invoice #12345, Date: 2024-01-15, Total: $500.00";
1385 string invoiceText = """
1386 Invoice #12345
1387 Date: 2024-01-15
1388 Customer: Acme Corp
1389 2 widgets at $150.00 each
1390 1 setup fee at $200.00
1391 Total: $500.00
1392 """;
13311393
13321394 var parameters = new MessageCreateParams
13331395 {
from line 1413
13511413 items = new
13521414 {
13531415 type = "object",
1416 properties = new
1417 {
1418 description = new { type = "string" },
1419 quantity = new { type = "number" },
1420 unit_price = new { type = "number" },
1421 },
1422 required = new[] { "description", "quantity", "unit_price" },
13541423 additionalProperties = false,
13551424 },
13561425 },
from line 1440
13711440 ```go Go
13721441 client := anthropic.NewClient()
13731442
1374 invoiceText := "Invoice #12345, Date: 2024-01-15, Total: $500.00"
1443 invoiceText := `
1444 Invoice #12345
1445 Date: 2024-01-15
1446 Customer: Acme Corp
1447 2 widgets at $150.00 each
1448 1 setup fee at $200.00
1449 Total: $500.00
1450 `
13751451
13761452 schema := map[string]any{
13771453 "type": "object",
from line 1505
14291505 public String description;
14301506
14311507 @JsonProperty("quantity")
1432 public int quantity;
1508 public double quantity;
14331509
14341510 @JsonProperty("unit_price")
14351511 public double unitPrice;
from line 1531
14551531 void main() {
14561532 AnthropicClient client = AnthropicOkHttpClient.fromEnv();
14571533
1458 String invoiceText = "Invoice #12345, Date: 2024-01-15, Total: $500.00";
1534 String invoiceText = """
1535 Invoice #12345
1536 Date: 2024-01-15
1537 Customer: Acme Corp
1538 2 widgets at $150.00 each
1539 1 setup fee at $200.00
1540 Total: $500.00
1541 """;
14591542
14601543 StructuredMessageCreateParams<Invoice> params = MessageCreateParams.builder()
14611544 .model(Model.CLAUDE_OPUS_5_5)
from line 1551
14681551 Invoice invoice = response.content().stream()
14691552 .flatMap(block -> block.text().stream())
14701553 .findFirst().orElseThrow().text();
1471 IO.println(invoice.invoiceNumber + ": $" + invoice.totalAmount);
1554 IO.println("Invoice " + invoice.invoiceNumber + ": $" + invoice.totalAmount);
1555 for (LineItem item : invoice.lineItems) {
1556 IO.println(item.quantity + " x " + item.description);
1557 }
14721558 }
14731559 ```
14741560
14751561 ```php PHP
1562 use Anthropic\Lib\Attributes\Constrained;
14761563 use Anthropic\Lib\Concerns\StructuredOutputModelTrait;
14771564 use Anthropic\Lib\Contracts\StructuredOutputModel;
14781565
14791566 $client = new Client();
1567
1568 class LineItem implements StructuredOutputModel
1569 {
1570 use StructuredOutputModelTrait;
1571
1572 public string $description;
1573 public float $quantity;
1574 public float $unit_price;
1575 }
14801576
14811577 class Invoice implements StructuredOutputModel
14821578 {
from line 1581
14851581 public string $invoice_number;
14861582 public string $date;
14871583 public float $total_amount;
1584 #[Constrained(itemClass: LineItem::class)]
14881585 public array $line_items;
14891586 public string $customer_name;
14901587 }
14911588
1492 $invoiceText = "Invoice #12345, Date: 2024-01-15, Total: $500.00";
1589 $invoiceText = <<<'TEXT'
1590 Invoice #12345
1591 Date: 2024-01-15
1592 Customer: Acme Corp
1593 2 widgets at $150.00 each
1594 1 setup fee at $200.00
1595 Total: $500.00
1596 TEXT;
14931597
14941598 $message = $client->messages->create(
14951599 maxTokens: 4096,
from line 1607
15031607 $invoice = $message->parsedOutput();
15041608 if ($invoice instanceof Invoice) {
15051609 echo "Invoice {$invoice->invoice_number}: \${$invoice->total_amount}\n";
1610 foreach ($invoice->line_items as $item) {
1611 echo "{$item->quantity} x {$item->description}\n";
1612 }
15061613 }
15071614 ```
15081615
from line 1618
15111618
15121619 class LineItem < Anthropic::BaseModel
15131620 required :description, String
1514 required :amount, Float
1621 required :quantity, Float
1622 required :unit_price, Float
15151623 end
15161624
15171625 class Invoice < Anthropic::BaseModel
from line 1630
15221630 required :customer_name, String
15231631 end
15241632
1525 invoice_text = "Invoice #12345, Date: 2024-01-15, Total: $500.00"
1633 invoice_text = <<~TEXT
1634 Invoice #12345
1635 Date: 2024-01-15
1636 Customer: Acme Corp
1637 2 widgets at $150.00 each
1638 1 setup fee at $200.00
1639 Total: $500.00
1640 TEXT
15261641
15271642 message = client.messages.create(
15281643 model: Anthropic::Model::CLAUDE_OPUS_5_5,
15291644 max_tokens: 4096,
1530 output_config: {format: Invoice},
1645 output_config: { format: Invoice },
15311646 messages: [
1532 {role: "user", content: "Extract invoice data from: #{invoice_text}"}
1647 { role: "user", content: "Extract invoice data from: #{invoice_text}" }
15331648 ]
15341649 )
15351650
15361651 invoice = message.parsed_output
15371652 puts "Invoice #{invoice.invoice_number}: $#{invoice.total_amount}"
1653 invoice.line_items.each { |item| puts "#{item.quantity} x #{item.description}" }
15381654 ```
15391655 </CodeGroup>
15401656 </Accordion>
from line 1773
16571773 ```
16581774
16591775 ```csharp C#
1776 AnthropicClient client = new();
1777
16601778 string feedbackText = "Great product, fast shipping!";
16611779
16621780 var parameters = new MessageCreateParams
from line 1808
16901808 ```
16911809
16921810 ```go Go
1811 client := anthropic.NewClient()
1812
16931813 feedbackText := "Great product, fast shipping!"
16941814
16951815 schema := map[string]any{
from line 1934
18141934 message = client.messages.create(
18151935 model: Anthropic::Model::CLAUDE_OPUS_5_5,
18161936 max_tokens: 1024,
1817 output_config: {format: Classification},
1937 output_config: { format: Classification },
18181938 messages: [
1819 {role: "user", content: "Classify this feedback: #{feedback_text}"}
1939 { role: "user", content: "Classify this feedback: #{feedback_text}" }
18201940 ]
18211941 )
18221942 puts message.parsed_output
from line 1959
18391959 "messages": [
18401960 {
18411961 "role": "user",
1842 "content": "Process this request: ..."
1962 "content": "Write an API response: request req_2abc3def has an invalid email."
18431963 }
18441964 ],
18451965 "output_config": {
from line 1969
18491969 "type": "object",
18501970 "properties": {
18511971 "status": {"type": "string"},
1852 "data": {"type": "object", "additionalProperties": false},
1972 "data": {
1973 "type": "object",
1974 "properties": {"message": {"type": "string"}},
1975 "required": ["message"],
1976 "additionalProperties": false
1977 },
18531978 "errors": {
18541979 "type": "array",
1855 "items": {"type": "object", "additionalProperties": false}
1980 "items": {
1981 "type": "object",
1982 "properties": {
1983 "code": {"type": "string"},
1984 "detail": {"type": "string"}
1985 },
1986 "required": ["code", "detail"],
1987 "additionalProperties": false
1988 }
18561989 },
1857 "metadata": {"type": "object", "additionalProperties": false}
1990 "metadata": {
1991 "type": "object",
1992 "properties": {"request_id": {"type": "string"}},
1993 "required": ["request_id"],
1994 "additionalProperties": false
1995 }
18581996 },
18591997 "required": ["status", "data", "metadata"],
18601998 "additionalProperties": false
from line 2016
18782016 type: string
18792017 data:
18802018 type: object
2019 properties:
2020 message:
2021 type: string
2022 required:
2023 - message
18812024 additionalProperties: false
18822025 errors:
18832026 type: array
18842027 items:
18852028 type: object
2029 properties:
2030 code:
2031 type: string
2032 detail:
2033 type: string
2034 required:
2035 - code
2036 - detail
18862037 additionalProperties: false
18872038 metadata:
18882039 type: object
2040 properties:
2041 request_id:
2042 type: string
2043 required:
2044 - request_id
18892045 additionalProperties: false
18902046 required:
18912047 - status
from line 2050
18942050 additionalProperties: false
18952051 messages:
18962052 - role: user
1897 content: "Process this request: ..."
2053 content: "Write an API response: request req_2abc3def has an invalid email."
18982054 YAML
18992055 ```
19002056
from line 2060
19042060 client = Anthropic()
19052061
19062062
2063 class Payload(BaseModel):
2064 message: str
2065
2066
2067 class APIError(BaseModel):
2068 code: str
2069 detail: str
2070
2071
2072 class Metadata(BaseModel):
2073 request_id: str
2074
2075
19072076 class APIResponse(BaseModel):
19082077 status: str
1909 data: dict
1910 errors: list[dict] | None
1911 metadata: dict
2078 data: Payload
2079 errors: list[APIError] | None = None
2080 metadata: Metadata
19122081
19132082
19142083 response = client.messages.parse(
19152084 model="claude-opus-5-5",
19162085 max_tokens=1024,
19172086 output_format=APIResponse,
1918 messages=[{"role": "user", "content": "Process this request: ..."}],
2087 messages=[
2088 {
2089 "role": "user",
2090 "content": "Write an API response: request req_2abc3def has an invalid email.",
2091 }
2092 ],
19192093 )
19202094
19212095 print(response.parsed_output)
from line 2103
19292103
19302104 const APIResponseSchema = z.object({
19312105 status: z.string(),
1932 data: z.record(z.string(), z.any()),
1933 errors: z.array(z.record(z.string(), z.any())).optional(),
1934 metadata: z.record(z.string(), z.any())
2106 data: z.object({ message: z.string() }),
2107 errors: z.array(z.object({ code: z.string(), detail: z.string() })).optional(),
2108 metadata: z.object({ request_id: z.string() })
19352109 });
19362110
19372111 const response = await client.messages.parse({
19382112 model: "claude-opus-5-5",
19392113 max_tokens: 1024,
19402114 output_config: { format: zodOutputFormat(APIResponseSchema) },
1941 messages: [{ role: "user", content: "Process this request..." }]
2115 messages: [
2116 {
2117 role: "user",
2118 content: "Write an API response: request req_2abc3def has an invalid email."
2119 }
2120 ]
19422121 });
19432122
19442123 console.log(response.parsed_output);
19452124 ```
19462125
19472126 ```csharp C#
2127 AnthropicClient client = new();
2128
19482129 var parameters = new MessageCreateParams
19492130 {
19502131 Model = Model.ClaudeOpus5_5,
19512132 MaxTokens = 1024,
1952 Messages = [new UserMessageParam { Content = "Process this request: ..." }],
2133 Messages =
2134 [
2135 new UserMessageParam
2136 {
2137 Content = "Write an API response: request req_2abc3def has an invalid email.",
2138 },
2139 ],
19532140 OutputConfig = new OutputConfig
19542141 {
19552142 Format = new JsonOutputFormat
from line 2147
19602147 ["properties"] = JsonSerializer.SerializeToElement(new
19612148 {
19622149 status = new { type = "string" },
1963 data = new { type = "object", additionalProperties = false },
2150 data = new
2151 {
2152 type = "object",
2153 properties = new { message = new { type = "string" } },
2154 required = new[] { "message" },
2155 additionalProperties = false,
2156 },
19642157 errors = new
19652158 {
19662159 type = "array",
1967 items = new { type = "object", additionalProperties = false },
2160 items = new
2161 {
2162 type = "object",
2163 properties = new
2164 {
2165 code = new { type = "string" },
2166 detail = new { type = "string" },
2167 },
2168 required = new[] { "code", "detail" },
2169 additionalProperties = false,
2170 },
19682171 },
1969 metadata = new { type = "object", additionalProperties = false },
2172 metadata = new
2173 {
2174 type = "object",
2175 properties = new { request_id = new { type = "string" } },
2176 required = new[] { "request_id" },
2177 additionalProperties = false,
2178 },
19702179 }),
19712180 ["required"] = JsonSerializer.SerializeToElement(new[] { "status", "data", "metadata" }),
19722181 ["additionalProperties"] = JsonSerializer.SerializeToElement(false),
from line 2206
19972206 "data": map[string]any{
19982207 "type": "object",
19992208 "additionalProperties": false,
2209 "properties": map[string]any{
2210 "message": map[string]any{"type": "string"},
2211 },
2212 "required": []string{"message"},
20002213 },
20012214 "errors": map[string]any{
20022215 "type": "array",
20032216 "items": map[string]any{
20042217 "type": "object",
20052218 "additionalProperties": false,
2219 "properties": map[string]any{
2220 "code": map[string]any{"type": "string"},
2221 "detail": map[string]any{"type": "string"},
2222 },
2223 "required": []string{"code", "detail"},
20062224 },
20072225 },
20082226 "metadata": map[string]any{
20092227 "type": "object",
20102228 "additionalProperties": false,
2229 "properties": map[string]any{
2230 "request_id": map[string]any{"type": "string"},
2231 },
2232 "required": []string{"request_id"},
20112233 },
20122234 },
20132235 "required": []string{"status", "data", "metadata"},
from line 2237
20152237 },
20162238 },
20172239 Messages: []anthropic.MessageParam{
2018 anthropic.NewUserMessage(anthropic.NewTextBlock("Process this request: ...")),
2240 anthropic.NewUserMessage(anthropic.NewTextBlock(
2241 "Write an API response: request req_2abc3def has an invalid email.",
2242 )),
20192243 },
20202244 })
20212245 if err != nil {
from line 2256
20322256 ```java Java
20332257 import com.fasterxml.jackson.annotation.JsonProperty;
20342258
2035 static class APIData {
2259 static class Payload {
20362260 @JsonProperty("message")
20372261 public String message;
2038
2039 @JsonProperty("resource_id")
2040 public String resourceId;
20412262 }
20422263
20432264 static class APIError {
20442265 @JsonProperty("code")
20452266 public String code;
20462267
2047 @JsonProperty("message")
2048 public String message;
2049 }
2050
2051 static class APIMetadata {
2268 @JsonProperty("detail")
2269 public String detail;
2270 }
2271
2272 static class Metadata {
20522273 @JsonProperty("request_id")
20532274 public String requestId;
2054
2055 @JsonProperty("timestamp")
2056 public String timestamp;
20572275 }
20582276
20592277 static class APIResponse {
from line 2279
20612279 public String status;
20622280
20632281 @JsonProperty("data")
2064 public APIData data;
2282 public Payload data;
20652283
20662284 @JsonProperty("errors")
20672285 public List<APIError> errors;
20682286
20692287 @JsonProperty("metadata")
2070 public APIMetadata metadata;
2288 public Metadata metadata;
20712289 }
20722290
20732291 void main() {
from line 2295
20772295 .model(Model.CLAUDE_OPUS_5_5)
20782296 .maxTokens(1024L)
20792297 .outputConfig(APIResponse.class)
2080 .addUserMessage("Process this request: ...")
2298 .addUserMessage("Write an API response: request req_2abc3def has an invalid email.")
20812299 .build();
20822300
20832301 StructuredMessage<APIResponse> response = client.messages().create(params);
20842302 APIResponse result = response.content().stream()
20852303 .flatMap(block -> block.text().stream())
20862304 .findFirst().orElseThrow().text();
2087 IO.println(result.status);
2305 IO.println(result.status + ": " + result.data.message);
20882306 }
20892307 ```
20902308
from line 2313
20952313
20962314 $client = new Client();
20972315
2098 class Payload implements StructuredOutputModel { use StructuredOutputModelTrait; public string $message; }
2099
2100 class APIError implements StructuredOutputModel { use StructuredOutputModelTrait; public string $code; public string $detail; }
2101
2102 class Metadata implements StructuredOutputModel { use StructuredOutputModelTrait; public string $request_id; }
2316 class Payload implements StructuredOutputModel
2317 {
2318 use StructuredOutputModelTrait;
2319
2320 public string $message;
2321 }
2322
2323 class APIError implements StructuredOutputModel
2324 {
2325 use StructuredOutputModelTrait;
2326
2327 public string $code;
2328 public string $detail;
2329 }
2330
2331 class Metadata implements StructuredOutputModel
2332 {
2333 use StructuredOutputModelTrait;
2334
2335 public string $request_id;
2336 }
21032337
21042338 class APIResponse implements StructuredOutputModel
21052339 {
from line 2349
21152349 $message = $client->messages->create(
21162350 maxTokens: 1024,
21172351 messages: [
2118 ['role' => 'user', 'content' => 'Process this request: ...']
2352 [
2353 'role' => 'user',
2354 'content' => 'Write an API response: request req_2abc3def has an invalid email.',
2355 ],
21192356 ],
21202357 model: 'claude-opus-5-5',
21212358 outputConfig: ['format' => APIResponse::class],
from line 2390
21532390 message = client.messages.create(
21542391 model: Anthropic::Model::CLAUDE_OPUS_5_5,
21552392 max_tokens: 1024,
2156 output_config: {format: APIResponse},
2393 output_config: { format: APIResponse },
21572394 messages: [
2158 {role: "user", content: "Process this request: ..."}
2395 { role: "user", content: "Write an API response: request req_2abc3def has an invalid email." }
21592396 ]
21602397 )
21612398 puts message.parsed_output
from line 2604
23672604 ```
23682605
23692606 ```csharp C#
2607 AnthropicClient client = new();
2608
23702609 var parameters = new MessageCreateParams
23712610 {
23722611 Model = Model.ClaudeOpus5_5,
from line 2802
25632802 model: Anthropic::Model::CLAUDE_OPUS_5_5,
25642803 max_tokens: 1024,
25652804 messages: [
2566 {role: "user", content: "Help me plan a trip to Paris departing May 15, 2026"}
2805 { role: "user", content: "Help me plan a trip to Paris departing May 15, 2026" }
25672806 ],
25682807 # JSON outputs: structured response format
25692808 output_config: {
from line 2811
25722811 schema: {
25732812 type: "object",
25742813 properties: {
2575 summary: {type: "string"},
2576 next_steps: {type: "array", items: {type: "string"}}
2814 summary: { type: "string" },
2815 next_steps: { type: "array", items: { type: "string" } }
25772816 },
25782817 required: ["summary", "next_steps"],
25792818 additionalProperties: false
from line 2827
25882827 input_schema: {
25892828 type: "object",
25902829 properties: {
2591 destination: {type: "string"},
2592 date: {type: "string", format: "date"}
2830 destination: { type: "string" },
2831 date: { type: "string", format: "date" }
25932832 },
25942833 required: ["destination", "date"],
25952834 additionalProperties: false
from line 2856
26172856
26182857* Your input token count is slightly higher.
26192858* The injected prompt costs you tokens like any other system prompt.
2620* Changing the `output_config.format` parameter will invalidate any [prompt cache](https://platform.claude.com/docs/en/build-with-claude/prompt-caching) for that conversation thread.
2859* Changing the `output_config.format` parameter invalidates any [prompt cache](https://platform.claude.com/docs/en/build-with-claude/prompt-caching) for that conversation thread.
26212860
26222861### JSON Schema limitations
26232862
from line 2881
26422881 * Numerical constraints (such as `minimum`, `maximum`, `multipleOf`)
26432882 * String constraints (`minLength`, `maxLength`)
26442883 * Array constraints beyond `minItems` of 0 or 1
2645 * `additionalProperties` set to anything other than `false`
2884 * `additionalProperties` set to anything other than `false` (see [Objects with arbitrary keys](https://platform.claude.com/docs/en/build-with-claude/structured-outputs#objects-with-arbitrary-keys))
26462885
26472886 If you use an unsupported feature, you’ll receive a 400 error with details.
26482887</Accordion>
from line 2907
26682907<Tip>
26692908 SDK helpers can transform schemas with [constraints not supported by the API](https://platform.claude.com/docs/en/build-with-claude/structured-outputs#json-schema-limitations). See [How SDK transformation works](https://platform.claude.com/docs/en/build-with-claude/structured-outputs#how-sdk-transformation-works).
26702909</Tip>
2910
2911#### Objects with arbitrary keys
2912
2913List every key of an object, either in `properties` or as a field of the class or schema you pass to the SDK. Because `additionalProperties` must be `false`, Claude can only return the keys you list.
2914
2915The API accepts an object with empty or missing `properties`, but Claude can only return `{}` for it. A map, dictionary, or record type lists no keys, so the Python and TypeScript SDKs send it as an object with empty `properties`. The Java and Ruby SDKs raise an error instead.
2916
2917If you don’t know the keys in advance, use an array instead. Give each item a `key` and a `value`, as in this schema:
2918
2919```json
2920{
2921 "type": "array",
2922 "items": {
2923 "type": "object",
2924 "properties": {
2925 "key": { "type": "string" },
2926 "value": { "type": "string" }
2927 },
2928 "required": ["key", "value"],
2929 "additionalProperties": false
2930 }
2931}
2932```
26712933
26722934### Property ordering
26732935
from line 2951
26892951}
26902952```
26912953
2692The output will order properties as:
2954The output orders properties as:
26932955
269429561. `name` (required, in schema order)
269529572. `email` (required, in schema order)
from line 3022
27603022| Parameters with union types | 16 | Total parameters that use `anyOf` or type arrays (for example, `"type": ["string", "null"]`) across all strict schemas. These are especially expensive because they create exponential compilation cost. |
27613023
27623024<Note>
2763 These limits apply to the combined total across all strict schemas in a single request. For example, if you have 4 strict tools with 6 optional parameters each, you’ll reach the 24-parameter limit even though no single tool seems complex.
3025 These limits apply to the combined total across all strict schemas in a single request. For example, if you have four strict tools with six optional parameters each, you’ll reach the 24-parameter limit even though no single tool seems complex.
27643026</Note>
27653027
27663028#### Additional internal limits
from line 3049
27873049
27883050The `output_format` parameter has moved to `output_config.format`, and beta headers are no longer required. The `output_format` parameter is deprecated. To use it anyway, add the `structured-outputs-2025-11-13` beta header. Without it, the API returns a 400 error.
27893051
2790The Python SDK (v1.0 and later) does not accept `output_format={...}` on `client.beta.messages.create()` or `count_tokens()` and raises a `TypeError`. Use `output_config` instead. See [Using a raw JSON schema](https://platform.claude.com/docs/en/build-with-claude/structured-outputs#using-a-raw-json-schema) for the updated API shape.
3052In the Python SDK (v1.0 and later), a schema dictionary passed as `output_format={...}` raises a `TypeError`. Use `output_config` instead. A Pydantic model passed as `output_format=Model` to `parse()` or `stream()` works with no change and no beta header, because the SDK sends it as `output_config`. See [Using a raw JSON schema](https://platform.claude.com/docs/en/build-with-claude/structured-outputs#using-a-raw-json-schema) for the updated API shape.
27913053
27923054## Feature compatibility
27933055
27943056