In Claude /v1/messages, output_config.format constrains the final response text to a JSON Schema. Find the type: "text" block in content and parse its text as JSON: the first block may contain thinking.
json
{
"model": "claude-opus-5",
"max_tokens": 1024,
"messages": [{"role": "user", "content": "Extract the name and age: Anna, 29"}],
"output_config": {
"format": {
"type": "json_schema",
"schema": {
"type": "object",
"properties": {
"name": {"type": "string"},
"age": {"type": "integer"}
},
"required": ["name", "age"],
"additionalProperties": false
}
}
}
}json
{"name":"Anna","age":29}json
{
"model": "claude-opus-5",
"messages": [{"role": "user", "content": "Extract the name and age: Anna, age 29"}],
"response_format": {
"type": "json_schema",
"json_schema": {
"name": "person",
"strict": true,
"schema": {
"type": "object",
"properties": {
"name": {"type": "string"},
"age": {"type": "integer"}
},
"required": ["name", "age"],
"additionalProperties": false
}
}
}
}- Kimi. The
response_formatfield is accepted on/v1/chat/completionsand passed to the model as it is. Guard does not inject a schema of its own and does not validate the answer against yours, so parse the result on your side and handle the case where no JSON came back. - Composer and Grok. They have no
response_formatfield: a request carrying it gets400 cursor_parameter_unavailablebefore any charge. Ask for the format in the request text and check the answer on your side.