For AI agents: markdown of this page — /docs-content-en/ai/chat/json.md documentation index — /llms.txt
Guaranteed JSON response
The response_format parameter forces the model to return a machine-readable response instead of free text. There are two levels of strictness: json_object guarantees valid JSON of an arbitrary shape, while json_schema enforces conformance to a given schema.
`json_object` mode
With response_format: {"type": "json_object"} the model returns valid JSON in the content field. Vibecode automatically adds an instruction to the system message to return only JSON. Describe the result structure explicitly in the system message:
curl -X POST https://vibecode.bitrix24.com/v1/chat/completions \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "bitrix/bitrixgpt-5.5",
"messages": [
{"role": "system", "content": "Classify the lead. Return JSON: {\"quality\": \"high|medium|low\", \"score\": 0-100}"},
{"role": "user", "content": "Acme LLC, budget 2 million per month"}
],
"response_format": {"type": "json_object"}
}'
Response:
{
"id": "chatcmpl-acdb112cf9cdf9f9",
"object": "chat.completion",
"model": "bitrix/bitrixgpt-5.5",
"choices": [
{
"index": 0,
"finish_reason": "stop",
"message": {
"role": "assistant",
"content": "{\"quality\":\"high\",\"score\":92}"
}
}
],
"usage": {"prompt_tokens": 56, "completion_tokens": 14, "total_tokens": 70}
}
`json_schema` mode
response_format: {"type": "json_schema", "json_schema": {...}} guarantees that the model response strictly conforms to the given JSON Schema — the model cannot return extra fields, omit required ones, or mix up types. This is stricter than json_object, which guarantees only valid JSON.
Not all models support this mode. For the current list, see the data.ai.structuredOutputs.models field in the GET /v1/me response.
`json_schema` fields
| Field | Type | Required | Description |
|---|---|---|---|
Fieldname |
Typestring | Requiredyes | DescriptionSchema name. Up to 64 characters, a-zA-Z0-9_- allowed |
Fieldschema |
Typeobject | Requiredyes | DescriptionThe JSON Schema itself |
Fieldstrict |
Typeboolean | Requiredno | Descriptiontrue — strict conformance checking against the schema. Recommended value |
Fielddescription |
Typestring | Requiredno | DescriptionSchema description for the model that helps it interpret the fields correctly |
Example with a schema
curl -X POST https://vibecode.bitrix24.com/v1/chat/completions \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "bitrix/bitrixgpt-5.5",
"messages": [
{"role": "system", "content": "Return strict JSON per the schema."},
{"role": "user", "content": "Hi"}
],
"response_format": {
"type": "json_schema",
"json_schema": {
"name": "hello_response",
"strict": true,
"schema": {
"type": "object",
"properties": {"message": {"type": "string"}},
"required": ["message"],
"additionalProperties": false
}
}
}
}'
The choices[0].message.content field contains a string that parses into an object matching the schema exactly — for example {"message":"Hi"}.
Early refusal on repeated JSON
The optional repetition_guard accepts "off" or "abort". Omitting it or sending "off" preserves existing behavior, including the terminal repetition check after finish_reason: "length". Enable "abort" explicitly when you accept a heuristic refusal on a legitimate repetitive prefix, such as an array of identical objects.
The "abort" mode requires response_format of type json_object or json_schema, no declared tools (tools omitted or empty), and a selected model that supports streaming, even with stream: false. It is unavailable for Cowork control/completion requests and quota announcements. An incompatible request is refused before reservation or inference: 400 invalid_request, type: "invalid_request_error", param: "repetition_guard". Values such as null, booleans and strings outside the enum also produce 400 invalid_request.
The guard inspects normalized answer content separately from reasoning. A complete JSON document at inspection is excluded, and actual tool or function calls disable detection. The reasoning guard retains its existing behavior. This heuristic does not detect every loop or bound the wait: it needs enough text to decide. Early detection is disabled when the inspected text exceeds 1,048,576 characters.
With stream: false, the platform reads the model stream privately and the client receives ordinary completion JSON or 422, without SSE headers or chunks. With stream: true, the HTTP status stays 200, with one error event followed by one data: [DONE]. The client must discard the partial answer already received. Detection cancels the active model request without retry, answer recovery or fallback to another model. Transport cancellation does not guarantee immediate GPU release.
The early refusal has fixed message and hint values:
{
"error": {
"message": "Repeated JSON content was detected and this request was stopped early.",
"type": "invalid_request_error",
"code": "reasoning_repetition",
"hint": "Disable repetition_guard for expected repeated content; otherwise revise the request or use another model."
}
}
It carries no fabricated finishReason: "length", no param, suggestedMaxTokens, retryable, retryAfter, or advice to disable reasoning. Raw answer text, the prompt, schema and private provider identifiers are excluded from the error. Measured usage is retained under existing failed-call rules. If the model reported no usage, it stays unknown and is not estimated from text length. Early refusal does not mean the model spent no tokens.
With the OpenAI Python SDK, pass the extension through extra_body:
from openai import OpenAI
client = OpenAI(base_url="https://vibecode.bitrix24.com/v1", api_key="YOUR_API_KEY")
response = client.chat.completions.create(
model="bitrix/bitrixgpt-5.5",
messages=[{"role": "user", "content": "Return a JSON object with a greeting."}],
response_format={"type": "json_object"},
extra_body={"repetition_guard": "abort"},
)
Use "off" or omit the option for expected repetition. Do not enable "abort" by default for all JSON requests.
Error response example
400 model_does_not_support_structured_outputs — the model does not support json_schema. The structuredOutputsModels field contains the list of suitable models:
{
"error": {
"message": "Model 'openai/o3' does not support response_format=json_schema. Use one of: bitrix/bitrixgpt-5.5, bitrix/bitrixgpt-5.5-thinking, openai/gpt-4o, openai/gpt-4o-mini.",
"type": "invalid_request_error",
"code": "model_does_not_support_structured_outputs",
"param": "response_format.type",
"structuredOutputsModels": ["bitrix/bitrixgpt-5.5", "bitrix/bitrixgpt-5.5-thinking", "openai/gpt-4o", "openai/gpt-4o-mini", "openai/o3-mini"]
}
}
422 structured_output_truncated — generation was cut off at the token limit without detected repetition:
{
"error": {
"message": "The model's response was cut off (finish_reason=length) before a complete JSON document was produced, so it does not satisfy the requested response_format. Raise max_tokens, or reduce the schema/prompt size.",
"type": "invalid_request_error",
"code": "structured_output_truncated",
"hint": "For reasoning models, max_tokens must cover the reasoning phase plus the JSON answer.",
"param": "max_tokens",
"finishReason": "length",
"suggestedMaxTokens": 2048
}
}
422 structured_output_invalid_json — the response is non-empty but does not parse as a JSON document:
{
"error": {
"message": "The model returned a non-empty response (finish_reason=stop) that is not a valid JSON document, so it does not satisfy the requested response_format. The response body was discarded rather than handed over as JSON.",
"type": "invalid_request_error",
"code": "structured_output_invalid_json",
"hint": "Retry the request, or use a model with reliable structured output; for a strict shape use response_format=json_schema. A larger token budget will not change the result.",
"finishReason": "stop"
}
}
Errors
| HTTP | Code | Description |
|---|---|---|
| HTTP400 | Codeinvalid_request |
DescriptionAn incompatible repetition_guard: "abort" request or an invalid option value. See the restrictions above |
| HTTP400 | Codemodel_does_not_support_structured_outputs |
DescriptionThe model does not support json_schema. The list of suitable models is in the structuredOutputsModels field |
| HTTP422 | Codestructured_output_truncated |
DescriptionThe model cut off generation before completing the JSON without detected repetition or returned an empty response |
| HTTP422 | Codestructured_output_invalid_json |
DescriptionThe model returned a non-empty response that does not parse as a JSON object or array |
| HTTP422 | Codereasoning_repetition |
DescriptionThe model got stuck in its reasoning — it kept repeating the same sentences and never started the answer. Send the request again with reasoning_effort: "none" |
| HTTP422 | Codereasoning_repetition |
DescriptionBy default (repetition_guard omitted or "off"), repetition was detected in non-empty incomplete JSON with json_object or json_schema after finish_reason: "length". The check is terminal; This is a heuristic diagnosis: it can also trigger on a legitimate repetitive array that exceeded the budget. Check whether repetition is expected; if so, check the token budget, otherwise revise the request or use another model. There is no advice to disable reasoning |
| HTTP422 | Codereasoning_repetition |
DescriptionExplicit repetition_guard: "abort" detected repeated JSON before completion. Disable the option for expected repetition, otherwise revise the request or use another model |
The full list of common API errors — Errors.
Known specifics
A truncated response yields 422 structured_output_truncated. If the model cut off generation before completing the JSON (finish_reason: "length"), a request with response_format without detected repetition returns 422 structured_output_truncated with the fields finishReason and suggestedMaxTokens. Reasoning models behave this way: the reasoning phase consumes the max_tokens budget before the model writes the JSON. Handle this error and retry the request with a larger max_tokens — you can take the value from suggestedMaxTokens. For strict JSON, set max_tokens with some headroom or use a model without reasoning.
The suggestedMaxTokens and param: "max_tokens" fields are present only when finish_reason: "length" in a structured_output_truncated error. Detected repetition produces reasoning_repetition without these fields. If the finish reason is anything else and valid JSON is still missing, the response is also 422, but without those two fields — raising max_tokens will not help; use a model without reasoning. The hint string and the finishReason field are present in both cases, and finishReason may be null.
If a reasoning model in json_object mode finished on its own and placed a complete valid JSON document into the internal reasoning_content channel, the platform recovers that JSON and returns 200 with it in content — no extra handling is required.
An unparseable response yields 422 structured_output_invalid_json. The platform parses the answer before handing it over: if, with response_format, the model returned non-empty text that is not a JSON object or array (prose around the object, an answer wrapped in a markdown code fence, a bare value such as 42), that answer is not served as a success. The refusal carries finishReason and hint, but no param and no suggestedMaxTokens — raising the token budget does not help here; retrying does, and json_schema with strict: true does when the shape matters. Nested JSON inside a string field is not a violation: only the outer parse is checked.
Looping reasoning yields 422 reasoning_repetition, not structured_output_truncated. If a reasoning model never started the answer because it kept repeating the same sentences in reasoning_content, the refusal carries the code reasoning_repetition. It has finishReason and hint but no param and no suggestedMaxTokens: a larger token budget only makes the repetition longer. Send the request again with reasoning turned off — reasoning_effort: "none". Cycling through different wordings does not count as repetition: such a response stays structured_output_truncated. If the reasoning_content channel starts as a JSON document (with { or [), in a stream the decision is deferred while recovery is still possible (if the document is too long to be recovered, the repetition cuts the stream off at once): a complete document is recovered as described above, even with identical objects, and if nothing can be recovered, reasoning_repetition arrives. Recovery from the reasoning is done only for json_object: without response_format an answer that arrives only in reasoning_content is cut off with a reasoning_repetition event when it loops.
A terminal attempt that ends in 422 is charged. The 422 response — whether for truncation, an unparseable answer or looping reasoning — arrives after the model has already run, so the attempt's tokens count toward the usage statistics in GET /v1/ai/usage and toward the Bitrix24 account's monthly AI quota. A retry with a raised max_tokens is another billable call.
A low max_tokens on a free reasoning model is raised automatically. If a free reasoning model is asked for a structured response and max_tokens is set explicitly below the lower bound, the platform raises it to that bound and reports it in the successful 200 response: the body carries a warnings array with an element {"code": "MAX_TOKENS_RAISED", "message": "..."}. This is not an error — read warnings as an optional field. If max_tokens is not set in the request, no adjustment is applied.
In streaming mode the error (and the recovered answer) arrives inside the stream. The service event {"error":{"code":"structured_output_truncated"}}, {"error":{"code":"structured_output_invalid_json"}} or {"error":{"code":"reasoning_repetition"}} comes before data: [DONE]. In the second case the answer chunks have already been delivered — discard them; the stream status stays 200 by protocol. JSON recovered from reasoning_content arrives as a content chunk before the terminal finish_reason chunk — read the stream to the end.
json_object does not check the structure. It guarantees only that the response parses as JSON — the set of fields and their types are left to the model. If the structure matters, use json_schema with strict: true.
Repetition in truncated JSON also produces reasoning_repetition. With repetition_guard omitted or "off", for json_object or json_schema, when generation ends with finish_reason: "length", non-empty incomplete JSON is checked for repetition. A detected repetition produces reasoning_repetition and a JSON-specific message, without advice to disable reasoning and without param or suggestedMaxTokens. This is a heuristic diagnosis: it can also trigger on a legitimate repetitive array that exceeded the budget. Check whether repetition is expected; if so, check the token budget, otherwise revise the request or use another model. The check runs after generation ends and does not shorten the wait. Short truncation without detected repetition and complete JSON at length retain structured_output_truncated; a legitimate repetitive array reaches the client in full on normal completion.