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

# Structured outputs

> Ask Chat Completions for a JSON object or for JSON that follows a schema.

Chat Completions can return JSON as the assistant's text. You ask for a JSON object, or for an instance of a schema you name. You parse the string yourself. The API does not hand you a decoded object.

This works on every current model. The example uses `lume-3.5`. Messages does not accept `response_format`. A Messages request that needs JSON should say so in the prompt, and your application should parse the text block.

## Endpoint and auth

`POST /v1/chat/completions` needs the scope `chat:completions`.

`response_format.type` is `text`, `json_object`, or `json_schema`. For a schema, `json_schema.name` is required. `schema`, `description`, and `strict` are optional. `strict` is accepted and sent on with the schema. The whole `response_format` object can be at most 32,768 bytes.

<CodeGroup>
  ```bash cURL theme={null}
  curl https://api.overcontrolgroup.com/v1/chat/completions \
    -H "Authorization: Bearer $OVERCONTROL_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "lume-3.5",
      "max_tokens": 256,
      "messages": [
        {"role": "user", "content": "Extract the event name and city."}
      ],
      "response_format": {
        "type": "json_schema",
        "json_schema": {
          "name": "event",
          "strict": true,
          "schema": {
            "type": "object",
            "properties": {
              "name": {"type": "string"},
              "city": {"type": "string"}
            },
            "required": ["name", "city"],
            "additionalProperties": false
          }
        }
      }
    }'
  ```

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

  client = OpenAI(
      api_key=os.environ["OVERCONTROL_API_KEY"],
      base_url="https://api.overcontrolgroup.com/v1",
  )

  response = client.chat.completions.create(
      model="lume-3.5",
      max_tokens=256,
      messages=[{"role": "user", "content": "Extract the event name and city."}],
      response_format={
          "type": "json_schema",
          "json_schema": {
              "name": "event",
              "strict": True,
              "schema": {
                  "type": "object",
                  "properties": {
                      "name": {"type": "string"},
                      "city": {"type": "string"},
                  },
                  "required": ["name", "city"],
                  "additionalProperties": False,
              },
          },
      },
  )

  print(response.choices[0].message.content)
  ```

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

  const client = new OpenAI({
    apiKey: process.env.OVERCONTROL_API_KEY,
    baseURL: "https://api.overcontrolgroup.com/v1",
  });

  const response = await client.chat.completions.create({
    model: "lume-3.5",
    max_tokens: 256,
    messages: [{ role: "user", content: "Extract the event name and city." }],
    response_format: {
      type: "json_schema",
      json_schema: {
        name: "event",
        strict: true,
        schema: {
          type: "object",
          properties: {
            name: { type: "string" },
            city: { type: "string" },
          },
          required: ["name", "city"],
          additionalProperties: false,
        },
      },
    },
  });

  console.log(response.choices[0].message.content);
  ```
</CodeGroup>

For a JSON object with no schema, set `response_format` to `{"type": "json_object"}` and tell the model, in the message, to return JSON.

## What you get back

The JSON is the string in `message.content`. `finish_reason` is `stop` when the model finishes inside `max_tokens`.

```json theme={null}
{
  "id": "chatcmpl_0123456789abcdef0123456789abcdef",
  "object": "chat.completion",
  "created": 1789430400,
  "model": "lume-3.5",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "{\"name\":\"Launch\",\"city\":\"Milan\"}"
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 40,
    "completion_tokens": 12,
    "total_tokens": 52
  }
}
```

`strict: true` is forwarded with the schema. That is the contract. The page does not promise a separate guarantee that the text will satisfy the schema. Set `max_tokens` so the JSON has room to finish. `lume-3.5` allows 16,384 output tokens and a 400,000 token context window.

A `response_format.type` other than `text`, `json_object`, or `json_schema` is HTTP 400:

```json theme={null}
{
  "error": {
    "message": "Unsupported response_format type",
    "type": "invalid_request_error",
    "param": "response_format.type",
    "code": "unsupported_feature"
  }
}
```

The response includes `X-Request-Id`.

## Next

<CardGroup cols={2}>
  <Card title="Tools" icon="wrench" href="/text/tools">
    Return a function call instead of JSON text.
  </Card>

  <Card title="Generate text" icon="message" href="/text/generate">
    A normal reply, with no response format.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.