> ## Documentation Index
> Fetch the complete documentation index at: https://docs.aihubmix.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Structured Outputs

> Constrain model output format with JSON Schema (Structured Outputs). Supports response_format for OpenAI, output_config.format for Anthropic Claude, and Gemini models, with auto-degradation and cross-protocol translation.

## Overview

Structured Outputs force the model's response to strictly follow a JSON Schema you define, ensuring the return value can be parsed directly by your program without regex or post-processing.

Unlike asking the model to "please return JSON" in the prompt, Structured Outputs rely on **Constrained Decoding**: the upstream provider compiles the JSON Schema into grammar rules and constrains generation token-by-token during inference, making it **impossible** for the model to produce output that violates the schema.

Typical use cases:

* Extracting entities and fields from unstructured text
* Classification / labeling / sentiment analysis
* Standardized passing of intermediate results in multi-step reasoning
* Strongly-typed constraints on Agent tool call parameters

## Protocol Parameter Comparison

<Note>
  The parameter names differ across the three protocols, but the underlying mechanism is the same: the model output strictly matches the JSON Schema you provide.
</Note>

| Protocol                           | Parameter                                  | Supported Models                                     |
| ---------------------------------- | ------------------------------------------ | ---------------------------------------------------- |
| OpenAI Chat `/v1/chat/completions` | `response_format.type: "json_schema"`      | Claude 4.5+, GPT-4o / GPT-5 series, Gemini series    |
| Anthropic Messages `/v1/messages`  | `output_config.format.type: "json_schema"` | Claude 4.5+ (direct / Vertex); Bedrock 4.5--4.6 only |
| OpenAI Responses `/v1/responses`   | `text.format.type: "json_schema"`          | Depends on upstream model capabilities               |

### AWS Bedrock Limitations

Claude 4.7 and above on AWS Bedrock uses the Mantle inference path, which does not currently support `output_config.format`. The gateway automatically strips the `format` field for these models and marks the degradation in a response header (see [Auto-Degradation Mechanism](#auto-degradation-mechanism) below). Your request will not fail because of this.

***

## Quick Start

### OpenAI Protocol (Recommended)

Works with all models that support Structured Outputs, across providers.

<CodeGroup>
  ```python Python theme={null}
  from openai import OpenAI

  client = OpenAI(
      api_key="<AIHUBMIX_API_KEY>",
      base_url="https://aihubmix.com/v1",
  )

  response = client.chat.completions.create(
      model="claude-sonnet-5",
      messages=[
          {"role": "user", "content": "Extract the following information: John Smith, 28 years old, San Francisco"}
      ],
      response_format={
          "type": "json_schema",
          "json_schema": {
              "name": "person_info",
              "strict": True,
              "schema": {
                  "type": "object",
                  "properties": {
                      "name": {"type": "string"},
                      "age": {"type": "integer"},
                      "city": {"type": "string"}
                  },
                  "required": ["name", "age", "city"],
                  "additionalProperties": False
              }
          }
      }
  )

  import json
  data = json.loads(response.choices[0].message.content)
  print(data)
  # {"name": "John Smith", "age": 28, "city": "San Francisco"}
  ```

  ```typescript Node.js theme={null}
  import OpenAI from "openai";

  const client = new OpenAI({
    apiKey: "<AIHUBMIX_API_KEY>",
    baseURL: "https://aihubmix.com/v1",
  });

  const response = await client.chat.completions.create({
    model: "claude-sonnet-5",
    messages: [
      { role: "user", content: "Extract the following information: John Smith, 28 years old, San Francisco" },
    ],
    response_format: {
      type: "json_schema",
      json_schema: {
        name: "person_info",
        strict: true,
        schema: {
          type: "object",
          properties: {
            name: { type: "string" },
            age: { type: "integer" },
            city: { type: "string" },
          },
          required: ["name", "age", "city"],
          additionalProperties: false,
        },
      },
    },
  });

  const data = JSON.parse(response.choices[0].message.content);
  console.log(data);
  ```

  ```bash cURL theme={null}
  curl https://aihubmix.com/v1/chat/completions \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer <AIHUBMIX_API_KEY>" \
    -d '{
      "model": "claude-sonnet-5",
      "messages": [
        {"role": "user", "content": "Extract the following information: John Smith, 28 years old, San Francisco"}
      ],
      "response_format": {
        "type": "json_schema",
        "json_schema": {
          "name": "person_info",
          "strict": true,
          "schema": {
            "type": "object",
            "properties": {
              "name": {"type": "string"},
              "age": {"type": "integer"},
              "city": {"type": "string"}
            },
            "required": ["name", "age", "city"],
            "additionalProperties": false
          }
        }
      }
    }'
  ```
</CodeGroup>

### Using Other Models (GLM-5.2 Example)

The same OpenAI protocol parameters work with all models that support Structured Outputs -- just switch the `model`.

```python Python theme={null}
from openai import OpenAI

client = OpenAI(
    api_key="<AIHUBMIX_API_KEY>",
    base_url="https://aihubmix.com/v1",
)

response = client.chat.completions.create(
    model="glm-5.2",
    messages=[
        {"role": "user", "content": "Extract the following information: John Smith, 28 years old, San Francisco"}
    ],
    response_format={
        "type": "json_schema",
        "json_schema": {
            "name": "person_info",
            "strict": True,
            "schema": {
                "type": "object",
                "properties": {
                    "name": {"type": "string"},
                    "age": {"type": "integer"},
                    "city": {"type": "string"}
                },
                "required": ["name", "age", "city"],
                "additionalProperties": False
            }
        }
    }
)

import json
data = json.loads(response.choices[0].message.content)
print(data)
# {"name": "John Smith", "age": 28, "city": "San Francisco"}
```

### Claude Native Protocol

Call directly with the Anthropic SDK using the `output_config.format` parameter.

<CodeGroup>
  ```python Python theme={null}
  import anthropic

  client = anthropic.Anthropic(
      api_key="<AIHUBMIX_API_KEY>",
      base_url="https://aihubmix.com",
  )

  response = client.messages.create(
      model="claude-sonnet-5",
      max_tokens=1024,
      messages=[
          {"role": "user", "content": "Extract the following information: John Smith, 28 years old, San Francisco"}
      ],
      output_config={
          "format": {
              "type": "json_schema",
              "schema": {
                  "type": "object",
                  "properties": {
                      "name": {"type": "string"},
                      "age": {"type": "integer"},
                      "city": {"type": "string"}
                  },
                  "required": ["name", "age", "city"],
                  "additionalProperties": False
              }
          }
      }
  )

  import json
  data = json.loads(response.content[0].text)
  print(data)
  ```

  ```bash cURL theme={null}
  curl https://aihubmix.com/v1/messages \
    -H "Content-Type: application/json" \
    -H "x-api-key: <AIHUBMIX_API_KEY>" \
    -H "anthropic-version: 2023-06-01" \
    -d '{
      "model": "claude-sonnet-5",
      "max_tokens": 1024,
      "messages": [
        {"role": "user", "content": "Extract the following information: John Smith, 28 years old, San Francisco"}
      ],
      "output_config": {
        "format": {
          "type": "json_schema",
          "schema": {
            "type": "object",
            "properties": {
              "name": {"type": "string"},
              "age": {"type": "integer"},
              "city": {"type": "string"}
            },
            "required": ["name", "age", "city"],
            "additionalProperties": false
          }
        }
      }
    }'
  ```
</CodeGroup>

***

## Schema Writing Guidelines

### Required Fields

All `object` types must explicitly declare `additionalProperties: false`; otherwise some upstream providers will reject the request.

```json theme={null}
{
  "type": "object",
  "properties": {
    "name": { "type": "string" },
    "score": { "type": "number" }
  },
  "required": ["name", "score"],
  "additionalProperties": false
}
```

### Nested Objects

Nested `object` types also require `additionalProperties: false`:

```json theme={null}
{
  "type": "object",
  "properties": {
    "user": {
      "type": "object",
      "properties": {
        "name": { "type": "string" },
        "email": { "type": "string" }
      },
      "required": ["name", "email"],
      "additionalProperties": false
    }
  },
  "required": ["user"],
  "additionalProperties": false
}
```

### Cross-Protocol Schema Differences

| Feature                                          | OpenAI Protocol              | Anthropic Protocol                                                                 |
| ------------------------------------------------ | ---------------------------- | ---------------------------------------------------------------------------------- |
| `name` field                                     | Required                     | Not supported (automatically handled by the gateway during cross-protocol calls)   |
| `strict` field                                   | Optional, recommended `true` | Not supported                                                                      |
| Numeric constraints (`minimum`, `maximum`, etc.) | Supported                    | Not supported (automatically stripped by the gateway; does not affect the request) |
| String constraints (`minLength`, `maxLength`)    | Supported                    | Not supported (automatically stripped by the gateway)                              |

<Tip>
  When calling Claude models via the OpenAI protocol, the gateway automatically converts the Schema format and strips incompatible keywords -- no manual adaptation needed.
</Tip>

***

## Auto-Degradation Mechanism

The gateway enables auto-degradation protection for Structured Outputs on all requests by default. When the model or platform does not support it, the gateway **will not return an error**. Instead, it automatically strips the Schema constraint and marks the degradation reason in a response header. Your request will still receive a normal model response -- the output simply won't be strictly constrained by the Schema.

This means you can safely enable Structured Outputs uniformly on the client side without having to check compatibility for each model:

* **Seamless multi-model switching**: When switching models between Claude, GPT, Gemini, and GLM with the same codebase, requests won't fail even if the target model doesn't support Structured Outputs
* **Transparent fallback routing**: When the primary channel is unavailable and fallback routing redirects to a backup channel, even if the backup channel's model version doesn't support Structured Outputs, the request still completes normally
* **Simplified client logic**: No need to maintain a list of "which models support Structured Outputs" -- the gateway handles it automatically; the client only needs to check the response header to decide whether additional parsing is needed

### Response Header

```
X-Structured-Output-Degraded: <reason>
```

| reason                                 | Meaning                                                                              |
| -------------------------------------- | ------------------------------------------------------------------------------------ |
| `model_unsupported`                    | The model (or the model on its current platform) does not support Structured Outputs |
| `json_object_unsupported_on_anthropic` | `json_object` mode cannot be converted to the Anthropic format                       |
| `json_schema_missing_schema`           | `json_schema` type was specified but the `schema` field is missing                   |
| `schema_keywords_stripped`             | Some constraint keywords in the Schema were stripped (e.g., `minimum`, `maxLength`)  |

### Detection Example

```python Python theme={null}
import httpx

response = httpx.post(
    "https://aihubmix.com/v1/chat/completions",
    headers={
        "Authorization": "Bearer <AIHUBMIX_API_KEY>",
        "Content-Type": "application/json",
    },
    json={
        "model": "claude-sonnet-5",
        "messages": [{"role": "user", "content": "Extract info: John Smith, 28 years old"}],
        "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,
                }
            }
        }
    }
)

# Check if degradation occurred (e.g., when the request was routed to an unsupported Bedrock channel)
degraded = response.headers.get("X-Structured-Output-Degraded")
if degraded:
    print(f"Structured Output degraded: {degraded}")
    # The model response is still normal, but the output is not strictly constrained by the Schema
else:
    import json
    data = json.loads(response.json()["choices"][0]["message"]["content"])
    print(data)  # {"name": "John Smith", "age": 28}
```

***

## Difference from `json_object` Mode

|                     | `json_schema` (Structured Outputs)                          | `json_object`                    |
| ------------------- | ----------------------------------------------------------- | -------------------------------- |
| Output guarantee    | Strictly matches the specified Schema                       | Only guarantees valid JSON       |
| Field control       | Field names, types, and required status are all constrained | No constraints                   |
| Supported protocols | OpenAI / Anthropic / Responses                              | OpenAI-compatible protocols only |
| Claude support      | Via `output_config.format`                                  | Not supported                    |

<Warning>
  `json_object` mode cannot be converted to the Claude native protocol. If you send `response_format: {"type": "json_object"}` to Claude via the OpenAI protocol, the response header will mark `json_object_unsupported_on_anthropic` degradation. Use the `json_schema` type instead.
</Warning>

***

## FAQ

<AccordionGroup>
  <Accordion title="Which models support Structured Outputs?">
    **Claude series** (via Anthropic API's `output_config.format`):

    * Opus / Sonnet / Haiku 4.5 and above
    * Fable / Mythos 5 and above
    * Bedrock platform: 4.5--4.6 only; Vertex AI matches direct API support

    **OpenAI series** (via `response_format`):

    * GPT-4o and above, GPT-5 series

    **Gemini series** (via `responseSchema`):

    * Gemini 2.5 and above

    Check each model's capability tags on the [Models page](https://aihubmix.com/models).
  </Accordion>

  <Accordion title="Why don't some Claude models on Bedrock support Structured Outputs?">
    Claude 4.7+ on AWS Bedrock uses the new Mantle inference path, which does not currently accept the `output_config.format` parameter. The gateway handles this automatically: it strips the format field and returns a normal response while marking the degradation header `X-Structured-Output-Degraded: model_unsupported`. Claude 4.5--4.6 on Bedrock is fully supported.
  </Accordion>

  <Accordion title="Is the JSON Schema modified during cross-protocol calls?">
    Yes. When calling Claude models via the OpenAI protocol, the gateway automatically:

    1. Converts `response_format` to `output_config.format`
    2. Removes Schema keywords not supported by Anthropic (`minimum`, `maxLength`, etc.)
    3. Marks `schema_keywords_stripped` in the response header if any keywords were stripped

    The reverse direction (calling OpenAI models via the Claude protocol) is also automatically converted.
  </Accordion>

  <Accordion title="Can Structured Outputs be used together with Extended Thinking?">
    Yes. The `format` (Structured Outputs) in `output_config` and the `effort` (thinking intensity) in `reasoning` are independent parameters that can be set simultaneously:

    ```json theme={null}
    {
      "output_config": {
        "format": {
          "type": "json_schema",
          "schema": { ... }
        }
      },
      "reasoning": {
        "effort": "high"
      }
    }
    ```
  </Accordion>

  <Accordion title="How does the degradation mechanism compare to other aggregation platforms like OpenRouter?">
    Most API aggregation platforms return an error outright when a model does not support Structured Outputs. AIHubMix uses a **graceful degradation** strategy: it automatically strips incompatible parameters, returns the model response normally, and informs the client of the degradation reason via the `X-Structured-Output-Degraded` response header. Your application will not break because of this.
  </Accordion>
</AccordionGroup>
