Skip to main content
Version: 2026-06-30

Structured Outputs

Structured Outputs with responseSchema

responseSchema lets you define the exact shape of AIE's response using a JSON Schema. Instead of receiving a free-form text answer, the model is constrained to produce a JSON object that matches the structure you describe — every field name, data type, and nesting level.

Why use it

Without responseSchema, AIE returns a natural-language string in the answer field. That works well for summaries and single-question answers, but becomes fragile when you need to:

  • Extract multiple structured fields from a document in one call
  • Feed the output directly into a downstream system without parsing
  • Guarantee that optional fields are always present (even if empty or null)
  • Enforce data types — numbers as numbers, dates as strings in a specific format, booleans rather than "yes"/"no"

With responseSchema, the response answer field becomes a JSON object whose shape is dictated by your schema. The model is retried automatically until its output validates against the schema, so you can rely on the structure programmatically.


JSON Schema — A Brief Overview

JSON Schema is a standard vocabulary for describing the structure of JSON data. A schema is itself a JSON object. The most important keywords for AIE use cases are:

KeywordPurpose
typeThe JSON type: "object", "array", "string", "number", "integer", "boolean", "null"
propertiesThe named fields of an object and their schemas
requiredWhich property names must be present
descriptionHuman-readable text describing the field — read by the model
enumA fixed list of allowed values
patternA regex the string value must match
itemsThe schema for elements in an array
anyOfThe value must match at least one of the listed sub-schemas
$defs / definitionsReusable schema fragments referenced with $ref

A minimal example that extracts two fields from a document:

{
"type": "object",
"properties": {
"invoice_number": {
"type": "string",
"description": "The invoice number as printed on the document."
},
"total_amount": {
"type": "number",
"description": "The total invoice amount as a decimal number, without currency symbols."
}
},
"required": ["invoice_number", "total_amount"]
}

Adding responseSchema to a Request

Pass your schema as the responseSchema field in the request body alongside your question:

{
"input": {
"prompt": "Extract the invoice details.",
"file": {
"url": "https://example.com/invoice.pdf"
}
},
"responseSchema": {
"type": "object",
"properties": {
"invoice_number": {
"type": "string",
"description": "The invoice number printed at the top of the document."
},
"vendor_name": {
"type": "string",
"description": "The name of the vendor or supplier issuing the invoice."
},
"total_amount": {
"type": "number",
"description": "The grand total amount due, as a decimal number."
},
"due_date": {
"type": "string",
"description": "Payment due date in YYYY-MM-DD format."
}
},
"required": ["invoice_number", "vendor_name", "total_amount", "due_date"]
},
"settings": {
"modelSettings": {
"capability": "consistent-output-structure"
}
}
}

The answer field in the response will be a JSON object:

{
"answer": {
"invoice_number": "INV-2024-0042",
"vendor_name": "Acme Supplies Inc.",
"total_amount": 1475.00,
"due_date": "2024-02-15"
}
}

The consistent-output-structure Capability

When using responseSchema, we recommend that you set settings.modelSettings.capability to "consistent-output-structure". This routes your request to a model specifically optimized and validated for structured output — a model that is reliably constrained to produce JSON conforming to a given schema.

"settings": {
"modelSettings": {
"capability": "consistent-output-structure"
}
}

What it does: Unlike the default "standard" capability, consistent-output-structure routes to a model whose inference pipeline validates the output against your schema and automatically retries with correction feedback if the output fails validation. You receive a response only when the output is schema-conformant.


Required Properties: How AIE Enforces Them

With the "consistent-output-structure" capability, AIE treats every property defined in your schema as required, regardless of whether you include it in the required array.

Standard JSON Schema allows properties to be omitted when they are not listed in required. AIE does not honor this distinction — if a field appears in properties, the model is expected to produce a value for it. This ensures every field in your schema is always present in the response, making the output predictable for downstream processing.

Because of this behavior, you should handle fields that may genuinely have no value in the document using anyOf with null (see the section below), rather than omitting them from required.

Example — both schemas produce the same runtime behavior:

// This...
{
"type": "object",
"properties": {
"name": { "type": "string" },
"age": { "type": "integer" }
}
}

// ...behaves the same as this:
{
"type": "object",
"properties": {
"name": { "type": "string" },
"age": { "type": "integer" }
},
"required": ["name", "age"]
}

Both will produce a response containing both name and age.


Using anyOf and null for Fields That May Be Absent

If a field may not exist in a given document, use anyOf with null as one of the options. This tells the model that an empty/missing value is a valid outcome, so it returns null rather than hallucinating a value.

{
"type": "object",
"properties": {
"invoice_number": {
"type": "string",
"description": "The invoice number as printed on the document."
},
"purchase_order": {
"anyOf": [
{ "type": "string" },
{ "type": "null" }
],
"description": "The purchase order reference number, or null if not referenced."
},
"discount_amount": {
"anyOf": [
{ "type": "number" },
{ "type": "null" }
],
"description": "The discount amount applied, or null if no discount was given."
}
},
"required": ["invoice_number", "purchase_order", "discount_amount"]
}

With this schema, a document that has no purchase order will produce:

{
"invoice_number": "INV-2024-0042",
"purchase_order": null,
"discount_amount": null
}

Use anyOf with null anywhere the underlying document may not contain the information. Without it, the model will attempt to produce a value for every field and may fabricate data for fields it cannot find.


Guiding the Model with description and pattern

The model reads description fields. A well-written description is one of the most effective tools for improving extraction accuracy.

description

Use the description field to:

  • Tell the model exactly where to look in the document
  • Clarify ambiguous field names
  • Instruct the model what to return when the value is absent

Avoid using description to specify output format. Putting a format instruction in description (e.g. "Format as YYYY-MM-DD") tells the model to look for a value that matches that format rather than return the value in that format. When you need to enforce a specific format, use pattern instead. If the pattern already enforces the format, keep the description focused on what the value is and where to find or infer it — not how it should look.

{
"type": "object",
"properties": {
"effective_date": {
"anyOf": [
{ "type": "string", "pattern": "^\\d{4}-\\d{2}-\\d{2}$" },
{ "type": "null" }
],
"description": "The policy effective date found in the header section"
},
"insured_name": {
"type": "string",
"description": "The full legal name of the insured party as shown on the declarations page."
},
"premium_amount": {
"type": "number",
"description": "The annual premium amount as a decimal number, excluding taxes and fees."
},
"policy_type": {
"type": "string",
"enum": ["homeowners", "renters", "auto", "umbrella", "other"],
"description": "The type of insurance policy. Choose 'other' if the type does not match any listed option."
}
},
"required": ["effective_date", "insured_name", "premium_amount", "policy_type"]
}

pattern

Use pattern to enforce a specific string format using a regular expression. This is useful for values like dates, phone numbers, codes, and identifiers where you need a guaranteed format.

When pattern is used, do not repeat the format in description. The regex itself enforces the format; the description should describe what the value is and where to find or infer it.

{
"type": "object",
"properties": {
"tax_id": {
"type": "string",
"pattern": "^\\d{2}-\\d{7}$",
"description": "The employer tax identification number."
},
"invoice_date": {
"type": "string",
"pattern": "^\\d{4}-\\d{2}-\\d{2}$",
"description": "The date the invoice was issued."
}
},
"required": ["tax_id", "invoice_date"]
}

Nested Objects and Arrays

With the consistent-output-structure capability, responseSchema supports arbitrarily nested objects and arrays (up to 10 levels deep). Use these to model multi-part data, tables, or repeated items.

Nested object example

{
"type": "object",
"properties": {
"vendor": {
"type": "object",
"description": "Information about the vendor issuing the invoice.",
"properties": {
"name": {
"type": "string",
"description": "The vendor's legal business name."
},
"address": {
"anyOf": [{ "type": "string" }, { "type": "null" }],
"description": "The vendor's mailing address as a single string, or null if not shown."
}
},
"required": ["name", "address"]
},
"total": {
"type": "number",
"description": "The invoice grand total as a decimal number."
}
},
"required": ["vendor", "total"]
}

Array example

{
"type": "object",
"properties": {
"line_items": {
"type": "array",
"description": "Each line item on the invoice.",
"items": {
"type": "object",
"properties": {
"description": {
"type": "string",
"description": "A short description of the product or service."
},
"quantity": {
"anyOf": [{ "type": "number" }, { "type": "null" }],
"description": "The quantity ordered, or null if not specified."
},
"unit_price": {
"anyOf": [{ "type": "number" }, { "type": "null" }],
"description": "The unit price as a decimal number, or null if not shown."
},
"amount": {
"type": "number",
"description": "The line total as a decimal number."
}
},
"required": ["description", "quantity", "unit_price", "amount"]
}
}
},
"required": ["line_items"]
}

Schema Limits

AIE validates your schema before sending it to the model. Requests exceeding these limits will be rejected with a 400 error:

LimitValue
Maximum total object properties (across all objects)5,000
Maximum nesting depth10 levels
Maximum total string length (property names, enum values, const values)120,000 characters
Maximum total enum values (across all properties)1,000
Maximum string length for a single enum (when > 250 values)15,000 characters

Tips for Accurate Extraction

  • Be explicit in descriptions. Vague descriptions like "The date" are less accurate than "The contract start date in the header." The model uses your description to locate and interpret the value. When a pattern is enforcing the output format, keep format instructions out of description — it should say what the value is and where to find it, not how it should look.

  • Use null to avoid hallucination. For any field that may not appear in every document, use anyOf with null and instruct the model to return null when not found. Without this, the model may fabricate a value.

  • Use enum for categorical fields. When a field has a known set of values (status codes, document types, classifications), enumerate them. The model will select from your list rather than generating an arbitrary string.

  • Mark all properties in required. AIE enforces all defined properties regardless of required, but explicitly listing them communicates intent clearly and avoids confusion when sharing schemas with others.

  • Keep your question focused. The question field still guides the model's attention within the document. For extraction tasks, a directive like "Extract all invoice details." or "Extract the parties, dates, and amounts from this contract." focuses the model before the schema shapes the output.

  • Use $defs for shared sub-schemas. If the same sub-schema appears in multiple places (e.g., an address block), define it once in $defs and reference it with $ref to keep the schema concise and within character limits.

{
"type": "object",
"$defs": {
"Address": {
"type": "object",
"properties": {
"street": { "anyOf": [{ "type": "string" }, { "type": "null" }], "description": "Street address." },
"city": { "anyOf": [{ "type": "string" }, { "type": "null" }], "description": "City." },
"state": { "anyOf": [{ "type": "string" }, { "type": "null" }], "description": "State or province." },
"zip": { "anyOf": [{ "type": "string" }, { "type": "null" }], "description": "Postal code." }
},
"required": ["street", "city", "state", "zip"]
}
},
"properties": {
"billing_address": { "$ref": "#/$defs/Address", "description": "The billing address." },
"shipping_address": { "$ref": "#/$defs/Address", "description": "The shipping address." }
},
"required": ["billing_address", "shipping_address"]
}