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

# Structured Outputs

> Force models to return valid JSON matching an exact schema.

Structured Outputs let you enforce that a model's response conforms to a JSON schema you define. Instead of asking the model to *try* to return JSON, the API guarantees the output matches your schema — no extra parsing, no malformed responses.

<Info>
  Structured Outputs are available on models that support `response_format` with `json_schema` (e.g. `gpt-4o`, `gpt-4o-mini`). For other models, use `json_object` mode with a system prompt.
</Info>

***

## JSON Mode vs. Structured Outputs

| Feature                   | `json_object` mode    | `json_schema` mode   |
| ------------------------- | --------------------- | -------------------- |
| Guarantees valid JSON     | ✓                     | ✓                    |
| Enforces specific keys    | ✗                     | ✓                    |
| Supports required fields  | ✗                     | ✓                    |
| Validates enums and types | ✗                     | ✓                    |
| Best for                  | Simple JSON responses | Production pipelines |

Use `json_schema` when downstream code depends on specific fields always being present.

***

## Basic Example

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    import os
    import json
    from openai import OpenAI
    from pydantic import BaseModel

    client = OpenAI(
        base_url="https://api.routeway.ai/v1",
        api_key=os.getenv("ROUTEWAY_API_KEY")
    )

    # Define your schema with Pydantic
    class CalendarEvent(BaseModel):
        name: str
        date: str
        participants: list[str]
        location: str | None = None

    response = client.beta.chat.completions.parse(
        model="gpt-4o",
        messages=[
            {
                "role": "user",
                "content": "Alice and Bob are attending a machine learning workshop in Berlin on July 15th."
            }
        ],
        response_format=CalendarEvent,
    )

    event = response.choices[0].message.parsed
    print(event.name)          # "Machine Learning Workshop"
    print(event.participants)  # ["Alice", "Bob"]
    print(event.date)          # "July 15th"
    print(event.location)      # "Berlin"
    ```
  </Tab>

  <Tab title="Node.js">
    ```javascript theme={null}
    import OpenAI from "openai";
    import { zodResponseFormat } from "openai/helpers/zod";
    import { z } from "zod";

    const client = new OpenAI({
      baseURL: "https://api.routeway.ai/v1",
      apiKey: process.env.ROUTEWAY_API_KEY,
    });

    const CalendarEvent = z.object({
      name: z.string(),
      date: z.string(),
      participants: z.array(z.string()),
      location: z.string().optional(),
    });

    async function main() {
      const response = await client.beta.chat.completions.parse({
        model: "gpt-4o",
        messages: [
          {
            role: "user",
            content: "Alice and Bob are attending a machine learning workshop in Berlin on July 15th.",
          },
        ],
        response_format: zodResponseFormat(CalendarEvent, "calendar_event"),
      });

      const event = response.choices[0].message.parsed;
      console.log(event.name);          // "Machine Learning Workshop"
      console.log(event.participants);  // ["Alice", "Bob"]
    }

    main().catch(console.error);
    ```
  </Tab>

  <Tab title="Raw JSON Schema">
    ```bash theme={null}
    curl https://api.routeway.ai/v1/chat/completions \
      -H "Authorization: Bearer $ROUTEWAY_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "model": "gpt-4o",
        "messages": [
          {
            "role": "user",
            "content": "Alice and Bob are attending a workshop in Berlin on July 15th."
          }
        ],
        "response_format": {
          "type": "json_schema",
          "json_schema": {
            "name": "calendar_event",
            "strict": true,
            "schema": {
              "type": "object",
              "properties": {
                "name": {"type": "string"},
                "date": {"type": "string"},
                "participants": {
                  "type": "array",
                  "items": {"type": "string"}
                },
                "location": {"type": ["string", "null"]}
              },
              "required": ["name", "date", "participants", "location"],
              "additionalProperties": false
            }
          }
        }
      }'
    ```
  </Tab>
</Tabs>

***

## Common Schema Patterns

### Extraction

Pull structured records out of unstructured text.

```python theme={null}
class ProductReview(BaseModel):
    sentiment: Literal["positive", "neutral", "negative"]
    score: int          # 1-5
    key_issues: list[str]
    recommended: bool

response = client.beta.chat.completions.parse(
    model="gpt-4o",
    messages=[
        {"role": "system", "content": "Extract a structured review from the customer feedback."},
        {"role": "user", "content": "I love the design but the battery only lasts 4 hours. Not worth the price."}
    ],
    response_format=ProductReview,
)
```

### Classification

Route or label inputs reliably.

```python theme={null}
class SupportTicket(BaseModel):
    category: Literal["billing", "technical", "account", "general"]
    priority: Literal["low", "medium", "high", "urgent"]
    summary: str

response = client.beta.chat.completions.parse(
    model="gpt-4o-mini",
    messages=[
        {"role": "system", "content": "Classify the support ticket."},
        {"role": "user", "content": "My card was charged twice for the same subscription last week."}
    ],
    response_format=SupportTicket,
)
```

### Nested Objects

Schemas can be deeply nested.

```python theme={null}
class Address(BaseModel):
    street: str
    city: str
    country: str

class Contact(BaseModel):
    name: str
    email: str
    address: Address
    tags: list[str]
```

***

## JSON Object Mode (Fallback)

For models that don't support `json_schema`, use `json_object` mode with a system prompt instructing the model to return JSON.

```python theme={null}
response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[
        {
            "role": "system",
            "content": 'Return a JSON object with keys: "name" (string), "score" (number 1-10), "tags" (array of strings).'
        },
        {"role": "user", "content": "Analyze this product description: ..."}
    ],
    response_format={"type": "json_object"},
)

data = json.loads(response.choices[0].message.content)
```

<Warning>
  `json_object` mode guarantees valid JSON but not schema conformance. Always validate the output against your expected shape before using it in production.
</Warning>

***

## Schema Design Tips

<AccordionGroup>
  <Accordion title="Always set additionalProperties: false" icon="shield">
    Prevents the model from including unexpected fields that could break downstream parsers.

    ```json theme={null}
    {
      "type": "object",
      "properties": {...},
      "required": ["name", "value"],
      "additionalProperties": false
    }
    ```
  </Accordion>

  <Accordion title="List all fields in required" icon="list-checks">
    With `strict: true`, every property must appear in `required`. Optional fields should use a union type like `["string", "null"]`.

    ```json theme={null}
    "nickname": {"type": ["string", "null"]}
    ```
  </Accordion>

  <Accordion title="Use enums for categorical fields" icon="tag">
    Enums are strictly enforced and reduce hallucination on fields with a known set of values.

    ```json theme={null}
    "status": {"type": "string", "enum": ["active", "inactive", "pending"]}
    ```
  </Accordion>

  <Accordion title="Keep schemas flat when possible" icon="layers">
    Deeply nested schemas increase the chance of refusal on complex inputs. Flatten where the structure allows.
  </Accordion>
</AccordionGroup>
