Structured Output

Return JSON that follows a schema instead of free-form Markdown.

View as MarkdownOpen in Claude

Use output_schema when you want output.content returned as a JSON object instead of free-form text. This is useful for pulling reported figures into fixed fields, comparing companies on the same metrics, or feeding Finance Research API output into a model, dashboard, or other typed system.

output_schema is supported with every research_effort value.

curl -X POST https://api.you.com/v1/finance_research \
-H "X-API-Key: $YDC_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"input": "What were Apple'\''s revenue and diluted EPS in its most recent fiscal quarter, and how did EPS compare with consensus?",
"research_effort": "deep",
"output_schema": {
"type": "object",
"properties": {
"company": {
"type": "string"
},
"fiscal_quarter": {
"type": "string"
},
"revenue_usd_billions": {
"type": "number"
},
"diluted_eps_usd": {
"type": "number"
},
"eps_vs_consensus": {
"type": "string",
"enum": ["beat", "inline", "miss"]
}
},
"required": ["company", "fiscal_quarter", "revenue_usd_billions", "diluted_eps_usd", "eps_vs_consensus"],
"additionalProperties": false
}
}'

When output_schema is provided, the structured result is returned in output.content and output.content_type is object. Sources remain in output.sources. The API does not add citation fields into your schema object automatically.

{
"output": {
"content": {
"company": "Apple",
"fiscal_quarter": "Fiscal Q3 2026",
"revenue_usd_billions": 109.4,
"diluted_eps_usd": 2.02,
"eps_vs_consensus": "beat"
},
"content_type": "object",
"sources": [
{
"url": "https://www.apple.com/newsroom/pdfs/fy2026q3/FY26_Q3_Consolidated_Financial_Statements.pdf",
"title": "Apple Inc. CONDENSED CONSOLIDATED STATEMENTS OF OPERATIONS (Unaudited)"
},
{
"url": "https://www.apple.com/newsroom/2026/07/apple-reports-third-quarter-results/",
"title": "Apple reports third quarter results - Apple"
}
]
},
"warnings": []
}

Schema Rules

output_schema follows a narrow JSON Schema subset designed for reliable structured generation. The rules and limits are the same as the Research API, so one schema works on both endpoints.

Required rules:

  • The root must be an object.
  • The root must not use top-level anyOf.
  • Every object must define properties.
  • Every object must set additionalProperties: false.
  • Every property must be listed in required. To make a field optional, keep it in required and make it nullable—see Optional and Nullable Fields.
  • Recursive schemas are not supported.
  • A property’s type must not be a bare {"type": "null"}. Use a nullable union such as {"type": ["number", "null"]} instead.

Supported patterns include nested objects, arrays, enums, nested anyOf, and non-recursive $defs and $ref.

Unsupported keywords:

  • allOf
  • contains
  • not
  • dependentRequired
  • dependentSchemas
  • format
  • if / then / else
  • maxContains / minContains
  • maxItems / minItems
  • maxLength / minLength
  • maxProperties / minProperties
  • maximum / minimum
  • multipleOf
  • pattern
  • patternProperties
  • propertyNames
  • unevaluatedItems / unevaluatedProperties
  • uniqueItems

Selected limits:

LimitValue
Max nesting depth5
Max total properties100
Max total enum values500
Max large-enum string budget (>250 values)7,500
Max total schema string budget25,000

If the schema is invalid, the request fails validation before model execution. The schema string budget counts property names, $defs names, enum values, and const values. It applies to schema shape only. Request-level limits such as the 40,000-character input limit are enforced separately at the request layer.

There is no separate raw byte-size limit on the schema. What matters is the 25,000-character string budget, which counts only property names, $defs names, enum values, and const values—not structural JSON ({}, "type", whitespace). A 30 KB schema file can still pass if its counted strings stay under budget—a much smaller file can fail if it has many long enum values, such as a full list of ticker symbols.

A schema is rejected with 422 before any model execution if it exceeds any limit above (depth, property count, enum count, or string budget) or violates a Schema Rule. The error message names the specific limit or rule.

Nesting depth counts every object and array level. A per-company array whose items hold a per-segment array of objects (companies[] → segments[] → segment) reaches the depth limit quickly. Flatten one level—for example, give each company segment_names and segment_revenue_usd_billions arrays—when you hit it.

Optional and Nullable Fields

Every property you declare must appear in required. This is what makes structured generation reliable—the model always emits every field—and it matches OpenAI Structured Outputs.

To express a value that may be unknown or not applicable, keep the field in required but make its type nullable by adding "null". The model returns null when the value isn’t available instead of guessing. Financial schemas need this often: a company that pays no dividend has no dividend yield, and a pre-profit company has no meaningful P/E ratio.

Use the concise form (equivalent to number | null):

"forward_pe": { "type": ["number", "null"] }

An anyOf spelling is also valid but more verbose—prefer the concise form above:

"forward_pe": { "anyOf": [{ "type": "number" }, { "type": "null" }] }

A property’s type may not be a bare {"type": "null"} (a field that can only ever be null). Make the field nullable instead, as shown above. A null branch inside an anyOf is fine.

Omitting a field from required produces an invalid schema—the request fails validation before execution. Nullability is the only mechanism for “may be absent.”

Response behavior

  • A nullable field with no available value is returned as null.
  • A non-nullable required field with no available value forces the model to emit something anyway (typically an empty string "" for strings). Required fields are never omitted from the response, and the model does not fabricate a citation-backed value to fill them. If a field can legitimately be unknown, make it nullable so you get a clean null instead of "" or 0.

Example

{
"type": "object",
"properties": {
"ticker": { "type": "string" },
"forward_pe": { "type": ["number", "null"] }
},
"required": ["ticker", "forward_pe"],
"additionalProperties": false
}

Conditional Structure

Conditional keywords (if / then / else, dependentRequired, dependentSchemas) are not supported. To express “field Y is required only when X”—for example, annual_dividend_per_share_usd is required only when pays_dividend is true—model the object as a discriminated anyOf union: one branch per case, with a shared field pinned to a distinct value via enum.

{
"type": "object",
"properties": {
"dividend": {
"anyOf": [
{
"type": "object",
"properties": {
"pays_dividend": { "type": "boolean", "enum": [true] },
"annual_dividend_per_share_usd": { "type": "number" },
"dividend_yield_pct": { "type": ["number", "null"] }
},
"required": ["pays_dividend", "annual_dividend_per_share_usd", "dividend_yield_pct"],
"additionalProperties": false
},
{
"type": "object",
"properties": { "pays_dividend": { "type": "boolean", "enum": [false] } },
"required": ["pays_dividend"],
"additionalProperties": false
}
]
}
},
"required": ["dividend"],
"additionalProperties": false
}

When pays_dividend is true, annual_dividend_per_share_usd is required—when false, only pays_dividend is allowed. This is the same pattern OpenAI Structured Outputs uses, so one schema works across both.

anyOf may not be used at the schema root—nest the union under a property (or array items), as shown above.

Comparing Multiple Companies

Put the per-company fields in an array of objects to get one row per company in a single request. Nullable fields keep a missing figure from being filled with a guess, and an enum turns a qualitative judgment into a value you can filter on:

curl -X POST https://api.you.com/v1/finance_research \
-H "X-API-Key: $YDC_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"input": "Compare free cash flow, share buybacks, and dividends per share for Apple, Microsoft, and Alphabet in each company'\''s most recent fiscal year.",
"research_effort": "deep",
"output_schema": {
"type": "object",
"properties": {
"companies": {
"type": "array",
"items": {
"type": "object",
"properties": {
"ticker": { "type": "string" },
"fiscal_year": { "type": "string" },
"free_cash_flow_usd_billions": { "type": ["number", "null"] },
"buybacks_usd_billions": { "type": ["number", "null"] },
"dividends_per_share_usd": { "type": ["number", "null"] },
"capital_allocation_priority": {
"type": "string",
"enum": ["buybacks", "dividends", "reinvestment", "balanced"]
}
},
"required": ["ticker", "fiscal_year", "free_cash_flow_usd_billions", "buybacks_usd_billions", "dividends_per_share_usd", "capital_allocation_priority"],
"additionalProperties": false
}
},
"summary": { "type": "string" }
},
"required": ["companies", "summary"],
"additionalProperties": false
}
}'

Structured output does not change what the Finance Research API reads. Figures still come from the sources in output.sources, so check them against the primary filing before they feed an investment decision or a client report.

View full API reference

Next Steps