response_format is an ordinary field in the request body, so asking a model for
JSON works here the way it works when you call the provider directly. The two
forms are the ones you already know: {"type": "json_object"} for “answer in
JSON”, and {"type": "json_schema", ...} for “answer in this shape”.
Which models take it
Every catalog entry carries ajson_mode word in its capabilities block,
answering yes, no or unknown. See
Model capabilities.
The word covers both forms together. It does not tell you whether a model that
takes json_object also takes a json_schema with strict set, and that
distinction is real on some model lines. Where it matters, the reliable test is a
request, not the catalog.
What this platform checks
Nothing about your schema or the reply, and the sentence is worth stating flatly rather than leaving you to infer it. The one exception is the shape of the field itself when Anthropic serves the request, below.- Your schema is not validated here. It is forwarded as written to every
provider that reads
response_format. A schema a provider will not accept is refused by the provider, in the provider’s own words and on its own status. - The reply is not validated against your schema either. What arrives is what the model produced. If it is not the shape you asked for, that is what you get.
- Nothing is repaired. There is no retry on a malformed body, no second call to fix the JSON, and no post-processing of the reply. A model that returns prose where you asked for an object returns prose to you.
response_format,
so when Anthropic serves the request the field is rewritten into Anthropic’s own
structured output setting:
- A
json_schemais sent with itsschemaalone. Thenameandstrictfields are not forwarded. - A
json_schemawith no usableschemainside it is refused here with a400,param: response_format,code: invalid_value, before anything is sent. json_objectis refused here with a400,param: response_format,code: unsupported_value, because Anthropic has no equivalent. Send ajson_schemawith a schema instead.{"type": "text"}sends nothing.
Parse defensively anyway
Whatever the provider guarantees, the content is a string inchoices[0].message.content and your code has to parse it. Two failure modes are
worth handling by name:
A truncated reply is not valid JSON. A response cut short by max_tokens
ends mid-object, and finish_reason says length rather than stop. Check it
before you parse: a JSON parse error whose real cause is a token ceiling is a
confusing thing to debug. It is also a real risk here specifically, because a
request that names no ceiling is held against the model’s published maximum
output and a schema-shaped answer can be longer than you expect. See
Request parameters.
A refusal is not your schema. A model that declines to answer answers in
prose or in its own refusal field, not in the shape you asked for.
Streaming a structured output
stream: true and response_format compose the way they do upstream: the
content arrives in fragments, and a fragment is not parseable JSON on its own.
Accumulate the deltas and parse once at the end, unless you have a streaming
parser that is built for partial documents.
The stream itself is unchanged by any of this. See
Streaming.
What it costs
Ajson_schema is part of the body, so it is prompt tokens on every request that
carries it. A large schema sent on every turn of a long conversation is paid for
on every turn. The counts you read back are the provider’s own and already
include it.