> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.twelvelabs.io/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.twelvelabs.io/_mcp/server.

# Structured output

Retrieve predictable, typed JSON responses by providing a JSON Schema with your request. This guide shows you how to define the schema and read the typed response.

# Key concepts

* **JSON Schema**: A standard for describing the structure of JSON data. You define the expected shape (properties, types, arrays), and the platform constrains its output to match.

# Prerequisites

* You've already uploaded your videos and images, and the assets have reached the `ready` status. See the [Upload content](/v1.3/agents/guides/upload-content) page for details.
* You've already created a knowledge store. See the [Create a knowledge store](/v1.3/agents/guides/create-a-knowledge-store) page for details.
* You've already added at least one asset to the knowledge store, and the item has reached the `ready` status. See the [Add assets to a knowledge store](/v1.3/agents/guides/add-assets) page for details.
* You've already read the [Create a response](/v1.3/agents/guides/create-a-response) page and understand the basic request and response format.

# Example

Define a JSON Schema describing the output you want, then pass it in the `text` parameter. This example extracts themes and entities from your videos and images. Replace the placeholders surrounded by `<>` with your values.

**`Python`**

```python Python maxlines=30
import json
from twelvelabs import TwelveLabs, TextParam
from twelvelabs.types.text_param_format import TextParamFormat_JsonSchema

client = TwelveLabs(api_key="<YOUR_API_KEY>")

response = client.responses.create(
    knowledge_store_id="<YOUR_KNOWLEDGE_STORE_ID>",
    input=[{"type": "message", "role": "user", "content": "List the main themes and key entities in these videos and images"}],
    text=TextParam(
        format=TextParamFormat_JsonSchema(
            name="themes_and_entities",
            schema_={
                "type": "object",
                "properties": {
                    "themes": {"type": "array", "items": {"type": "string"}},
                    "entities": {
                        "type": "array",
                        "items": {
                            "type": "object",
                            "properties": {
                                "name": {"type": "string"},
                                "type": {"type": "string"},
                                "frequency": {"type": "string"},
                            },
                        },
                    },
                },
            },
        )
    ),
)

for output in response.output:
    if output.type == "message":
        for content in output.content:
            structured = json.loads(content.text)
            print(f"Themes: {structured['themes']}")
            for entity in structured["entities"]:
                print(f"  {entity['name']} ({entity['type']})")
```

**`Node.js`**

```javascript Node.js maxlines=30
import { TwelveLabs } from "twelvelabs-js";

const client = new TwelveLabs({ apiKey: "<YOUR_API_KEY>" });

const response = await client.responses.create({
  knowledgeStoreId: "<YOUR_KNOWLEDGE_STORE_ID>",
  input: [{ type: "message", role: "user", content: "List the main themes and key entities in these videos and images" }],
  text: {
    format: {
      type: "json_schema",
      name: "themes_and_entities",
      schema: {
        type: "object",
        properties: {
          themes: { type: "array", items: { type: "string" } },
          entities: {
            type: "array",
            items: {
              type: "object",
              properties: {
                name: { type: "string" },
                type: { type: "string" },
                frequency: { type: "string" },
              },
            },
          },
        },
      },
    },
  },
});

for (const output of response.output ?? []) {
  if (output.type === "message") {
    for (const content of output.content ?? []) {
      const structured = JSON.parse(content.text);
      console.log(`Themes: ${structured.themes}`);
      for (const entity of structured.entities) {
        console.log(`  ${entity.name} (${entity.type})`);
      }
    }
  }
}
```

# Code explanation

#### Python

To receive typed JSON output, call the [`responses.create`](/v1.3/sdk-reference/python/responses#create-a-response) method with a `text` parameter that describes your JSON Schema. This example parses the returned JSON string and prints the extracted themes and entities to the standard output.\

**Parameters**:

* `knowledge_store_id`: The unique identifier of the knowledge store to reason over. Every request requires exactly one.
* `input`: An array of input items. Each item is a message you send to [Jockey](/v1.3/agents/concepts/jockey).
* `text`: An object that specifies the response format. To return structured JSON, set the `format` field. Within it, the `schema_` field defines the structure the output must match, and the `name` field identifies the schema. See the [JSON schema requirements](#json-schema-requirements) section for the schema rules.\


**Return value**: An object of type `ResponseObject`. Iterate the `output` array and read the `text` field of each content part in a `message` item to obtain a JSON string that matches your schema. Parse it with the `json.loads()` method into a native object.

#### Node.js

To receive typed JSON output, call the [`responses.create`](/v1.3/sdk-reference/node-js/responses#create-a-response) method with a `text` parameter that describes your JSON Schema. You pass all parameters as properties of a single object. This example parses the returned JSON string and prints the extracted themes and entities to the standard output.\

**Parameters**:

* `knowledgeStoreId`: The unique identifier of the knowledge store to reason over. Every request requires exactly one.
* `input`: An array of input items. Each item is a message you send to Jockey.
* `text`: An object that specifies the response format. To return structured JSON, set the `format` field. Within it, the `type` field must be `"json_schema"`, the `schema` field defines the structure the output must match, and the `name` field identifies the schema. See the [JSON schema requirements](#json-schema-requirements) section for the schema rules.\


**Return value**: An `HttpResponsePromise` that resolves to an object of type `ResponseObject`. Iterate the `output` array and read the `text` field of each content part in a `message` item to obtain a JSON string that matches your schema. Parse it with the `JSON.parse()` method into a native object.

# Example response

The response text is a JSON string that matches your schema:

```json
{
  "themes": ["outdoor recreation", "team building", "nature conservation"],
  "entities": [
    {"name": "John Rivera", "type": "person", "frequency": "3 items"},
    {"name": "Yellowstone", "type": "location", "frequency": "2 items"}
  ]
}
```

# Combine with instructions

Use the `instructions` field to apply a domain-specific lens, and a schema to capture the results in a structured format. This example enriches videos and images through a brand strategy perspective.

**`Python`**

```python Python maxlines=30
enrichment_schema = {
    "type": "object",
    "properties": {
        "enrichments": {
            "type": "array",
            "items": {
                "type": "object",
                "properties": {
                    "item_reference": {"type": "string"},
                    "original_summary": {"type": "string"},
                    "enriched_analysis": {"type": "string"},
                    "new_insights": {"type": "array", "items": {"type": "string"}},
                    "tags": {"type": "array", "items": {"type": "string"}},
                },
            },
        }
    },
}

response = client.responses.create(
    knowledge_store_id="<YOUR_KNOWLEDGE_STORE_ID>",
    instructions="You are a brand strategist. Analyze videos and images through the lens of brand perception and marketing effectiveness.",
    input=[{"type": "message", "role": "user", "content": "For each item, provide enriched analysis focusing on brand messaging effectiveness, audience engagement signals, and production quality."}],
    text=TextParam(format=TextParamFormat_JsonSchema(name="enrichment", schema_=enrichment_schema)),
)
```

**`Node.js`**

```javascript Node.js maxlines=30
const enrichmentSchema = {
  type: "object",
  properties: {
    enrichments: {
      type: "array",
      items: {
        type: "object",
        properties: {
          item_reference: { type: "string" },
          original_summary: { type: "string" },
          enriched_analysis: { type: "string" },
          new_insights: { type: "array", items: { type: "string" } },
          tags: { type: "array", items: { type: "string" } },
        },
      },
    },
  },
};

const response = await client.responses.create({
  knowledgeStoreId: "<YOUR_KNOWLEDGE_STORE_ID>",
  instructions: "You are a brand strategist. Analyze videos and images through the lens of brand perception and marketing effectiveness.",
  input: [{ type: "message", role: "user", content: "For each item, provide enriched analysis focusing on brand messaging effectiveness, audience engagement signals, and production quality." }],
  text: { format: { type: "json_schema", name: "enrichment", schema: enrichmentSchema } },
});
```

Swap the `instructions` field to apply a different analysis lens. The schema stays the same:

| Context       | Instructions                                                                                                                |
| ------------- | --------------------------------------------------------------------------------------------------------------------------- |
| Accessibility | "Analyze for accessibility: describe visual elements for screen readers, note caption quality, identify audio-only content" |
| Compliance    | "Review for regulatory compliance: identify claims, disclaimers, required disclosures"                                      |
| Education     | "Analyze pedagogical effectiveness: identify learning objectives, teaching methods, assessment opportunities"               |
| SEO           | "Extract SEO metadata: keywords, descriptions, suggested titles, topic clusters"                                            |

# JSON schema requirements

> **Note**
>
> The constraints in this section apply to the Responses API. The schema the platform uses during [ingestion](/v1.3/agents/guides/create-a-knowledge-store/configure-ingestion#json-schema) supports different keywords and rejects unknown keywords with a `422` error.

Your schema must adhere to the [JSON Schema Draft 2020-12 specification](https://json-schema.org/draft/2020-12) and must meet the requirements below:

* **Supported data types**: `array`, `boolean`, `integer`, `null`, `number`, `object`, and `string`.
* **Automatic schema changes**: The platform adds all object properties to `required` and sets `additionalProperties` to `false` on every object. You do not need to include `required` or `additionalProperties` in your schema.
* **Unsupported keywords**: Do not use `oneOf`, `default`, `if`/`then`/`else`, `not`, `patternProperties`, `contains`, or `prefixItems`. They may produce incomplete or malformed output without returning an error. Use `anyOf` instead of `oneOf`, and `properties` instead of `patternProperties`. Omit the others.
* **Subschema references**: You can reference subschemas using `$ref`. Define subschemas within `$defs` at the root of the schema. External URIs and relative-path references are not supported. For details, see the [JSON Schema documentation on \$defs](https://json-schema.org/understanding-json-schema/structuring#defs).

For complete specifications, see the [`schema`](/v1.3/api-reference/responses/create#request.body.text.format.json_schema.schema) field in the API Reference section.

# Common pitfalls

* **Large schemas can reduce output quality.** Keep nesting to 5 levels of objects or fewer. Keep the total number of properties across all objects to 100 or fewer. These are best-practice guidelines, not enforced limits.
* **Response text is a JSON string.** You still need to parse the text content with the `json.loads()` method (Python) or the `JSON.parse()` method (Node.js) into a native object.
* **Structured responses contain no citations.** The generated JSON has no citation markers, and the annotations array is empty. To display cited answers, send the request without a response format.
* **Truncated responses may fail to parse.** Even with a valid schema, the platform may truncate the response at the token limit. If the `status` field is `incomplete`, simplify your schema or break the request into smaller queries.

# Next steps

* [Recipes](/v1.3/agents/recipes) - complete examples that combine structured output with real tasks like entity extraction, content organization, and enrichment
* [Streaming](/v1.3/agents/guides/create-a-response/streaming) - combine streaming with structured output for real-time typed responses
* [Multi-turn sessions](/v1.3/agents/guides/create-a-response/multi-turn-sessions) - use structured output across a multi-turn conversation
* [Create a response](/v1.3/agents/guides/create-a-response) - review the basic request and response format

# Jupyter notebook

[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/twelvelabs-io/twelvelabs-developer-experience/blob/main/quickstarts/jockey/guides/structured_output.ipynb)