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

# Structured Output

> Constrain model output to a JSON schema for reliable structured data extraction.

Pass a `response_format` with `type: "json_schema"` to get a response that always matches your schema. Works with any model that supports `response_format`, including OpenAI and Google Gemini models (e.g. `google/gemini-2.5-flash`).

<Warning>
  **Not every model enforces `response_format`.** It only takes effect on models that support structured output. If a model doesn't, the request still **succeeds and returns ordinary text** — it does not error. Always parse/validate the response, and prefer a model with first-class support such as OpenAI models or Google Gemini (e.g. `google/gemini-2.5-flash`).
</Warning>

## Output modes

`response_format` is an object whose `type` selects how the output is shaped:

| `type`          | Behavior                                                                                                                            |
| --------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `"text"`        | Default. Free-form text — identical to omitting `response_format`.                                                                  |
| `"json_object"` | The model returns syntactically valid JSON. Describe the keys you want in your prompt; the structure is not otherwise enforced.     |
| `"json_schema"` | The model returns JSON that conforms to the JSON Schema you supply. Field names and types are constrained regardless of the prompt. |

In the JSON modes the content comes back as a **string** in `choices[0].message.content` — parse it client-side.

## Basic example

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    import json
    from meshapi import MeshAPI, ChatCompletionParams, ChatMessage

    client = MeshAPI(base_url="https://api.meshapi.ai", token="rsk_...")

    schema = {
        "type": "json_schema",
        "json_schema": {
            "name": "country_info",
            "schema": {
                "type": "object",
                "properties": {
                    "capital": {"type": "string"},
                    "country": {"type": "string"},
                },
                "required": ["capital", "country"],
                "additionalProperties": False,
            },
        },
    }

    resp = client.chat.completions.create(
        ChatCompletionParams(
            model="google/gemini-2.5-flash",
            messages=[ChatMessage(role="user", content="What is the capital of France? Use the provided schema.")],
            response_format=schema,
            max_tokens=1000,
            temperature=0,
        )
    )

    data = json.loads(resp.choices[0].message.content)
    print(data["capital"])  # "Paris"
    print(data["country"])  # "France"
    ```
  </Tab>

  <Tab title="Node.js">
    ```javascript theme={null}
    const schema = {
      type: "json_schema",
      json_schema: {
        name: "country_info",
        schema: {
          type: "object",
          properties: {
            capital: { type: "string" },
            country: { type: "string" },
          },
          required: ["capital", "country"],
          additionalProperties: false,
        },
      },
    };

    const resp = await client.chat.completions.create({
      model: "google/gemini-2.5-flash",
      messages: [{ role: "user", content: "What is the capital of France? Use the provided schema." }],
      response_format: schema,
      max_tokens: 1000,
      temperature: 0,
    });

    const data = JSON.parse(resp.choices[0].message?.content ?? "{}");
    console.log(data.capital); // "Paris"
    ```
  </Tab>

  <Tab title="Go">
    ```go theme={null}
    schema := map[string]interface{}{
        "type": "json_schema",
        "json_schema": map[string]interface{}{
            "name": "country_info",
            "schema": map[string]interface{}{
                "type": "object",
                "properties": map[string]interface{}{
                    "capital": map[string]interface{}{"type": "string"},
                    "country": map[string]interface{}{"type": "string"},
                },
                "required":             []string{"capital", "country"},
                "additionalProperties": false,
            },
        },
    }

    model := "google/gemini-2.5-flash"
    maxTokens := 1000
    resp, err := client.Chat.Completions.Create(ctx, meshapi.ChatCompletionParams{
        Model: &model,
        Messages: []meshapi.ChatMessage{
            {Role: "user", Content: "What is the capital of France? Use the provided schema."},
        },
        ResponseFormat: schema,
        MaxTokens:      &maxTokens,
    })
    if err != nil {
        log.Fatal(err)
    }

    var data map[string]interface{}
    json.Unmarshal([]byte(*resp.Choices[0].Message.Content), &data)
    fmt.Println(data["capital"]) // "Paris"
    ```
  </Tab>
</Tabs>

## Valid JSON without a schema

When you only need parseable JSON and don't want to define a schema, use `json_object` and describe the expected keys in the prompt:

```python theme={null}
resp = client.chat.completions.create(
    ChatCompletionParams(
        model="google/gemini-2.5-flash",
        messages=[
            ChatMessage(role="system", content="Respond only with JSON."),
            ChatMessage(role="user", content="List three fruits and their colors with keys name and color."),
        ],
        response_format={"type": "json_object"},
    )
)

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

The output is always valid JSON, but the exact keys depend on the model following your prompt. Use `json_schema` when you need that guarantee.

## How it works across providers

`response_format` follows the OpenAI convention and is forwarded to the upstream provider. For providers with a different native contract, Mesh API translates it automatically — for example, Google Gemini models on Vertex AI are converted to Gemini's native structured-output config (`responseMimeType` for `json_object`, plus `responseSchema` for `json_schema`), so enforcement runs on the provider side.

## Supported models

Structured output works with any model that supports `response_format` — this includes OpenAI and Google Gemini models (e.g. `google/gemini-2.5-flash`). Models that don't support it simply return ordinary text. Use `GET /v1/models` to see the models enabled on your account.

## Notes

* Set `additionalProperties: false` to prevent extra fields in the response.
* `finish_reason` will be `"stop"` on success.
* The response content is a JSON string — parse it with `json.loads()` / `JSON.parse()` / `json.Unmarshal`.

## Auto-retry on validation failure (Python)

Some models only best-effort the schema. Set `max_retries` on `parse()` to feed a
failed response back to the model with the validation error appended. Each retry is
a billed call; the default is `0` (no retry).

```python theme={null}
country = client.chat.completions.parse(params, Country, max_retries=3)
```

`parse()` returns the parsed object directly:

| `response_format`             | Returns                              |
| ----------------------------- | ------------------------------------ |
| Pydantic `BaseModel` subclass | An instance of that model            |
| `TypedDict` / dataclass       | The validated object                 |
| Raw JSON-schema `dict`        | A `dict` (`json.loads`, unvalidated) |

`parse()` is non-streaming — use `create()` when you need the raw string content plus
`usage` and cost metadata. The async client exposes the same `await client.chat.completions.parse(...)`.
