## 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:

```bash
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:

```json
{
  "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 confuse types. This is stricter than `json_object`, which guarantees only valid JSON.

The mode is not available on all models. For the current list, see the response of [`GET /v1/me`](/docs/keys-auth), field `ai.structuredOutputs.models`.

## `json_schema` fields

| Field | Type | Req. | Description |
|------|-----|:-----:|---------|
| `name` | string | yes | Schema name. Up to 64 characters, `a-zA-Z0-9_-` allowed |
| `schema` | object | yes | The JSON Schema itself |
| `strict` | boolean | no | `true` — strict conformance checking against the schema. Recommended value |
| `description` | string | no | Schema description for the model, helps it interpret the fields correctly |

## Example with a schema

```bash
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/openai/gpt-oss-120b",
    "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"}`.

## 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:

```json
{
  "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, bitrix/openai/gpt-oss-120b, 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", "bitrix/openai/gpt-oss-120b", "openai/gpt-4o-mini", "openai/o3-mini"]
  }
}
```

`422 structured_output_truncated` — generation was cut off at the token limit before a complete JSON:

```json
{
  "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
  }
}
```

## Errors

| HTTP | Code | Description |
|------|-----|---------|
| 400 | `model_does_not_support_structured_outputs` | The model does not support `json_schema`. The list of suitable models is in the `structuredOutputsModels` field |
| 422 | `structured_output_truncated` | The model cut off generation before completing the JSON or returned an empty response |

The full list of common API errors — [Errors](/docs/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` returns `422` 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"` — they indicate that raising the token budget helps. If the finish reason is any other one and no valid JSON is present, the response is still `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 on `json_object` finished on its own and placed a complete valid JSON into the service `reasoning_content` channel, the platform recovers that JSON and returns `200` with it in `content` — no extra handling is required.

**A truncated attempt is charged.** The `422` arrives after the model has already run, so the attempt's tokens count toward the usage statistics in [`GET /v1/ai/usage`](/docs/ai/consumption/usage) and toward the 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 this on the successful `200` response: the body gains a `warnings` array with the 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) arrive inside the stream.** The service event `{"error":{"code":"structured_output_truncated"}}` comes before `data: [DONE]`. 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`.

## See also

- [Create a chat completion](./completions.md)
- [Streaming](./streaming.md)
- [Function calling](./tools.md)
- [Models list](/docs/ai/models/list)