Structured Outputs vs JSON Mode: Validate Real Data

Choose JSON mode or schema-constrained output, validate business rules beyond syntax, and compare extraction models using missing and ambiguous fields.

Published 2026-09-29 · Updated 2026-09-29 · KeepRouter Editorial · 4 minute read

Protocol decision matrix for Responses API and Chat Completions integrations
Request format, response structure and application validation are separate parts of the contract. Conceptual illustration.

JSON mode targets valid JSON syntax; schema-constrained output adds structural requirements such as required keys and allowed types when the model and API support them. Neither guarantees that the values are true. For production extraction, validate syntax, schema and business meaning as three separate layers.

This guide is for teams extracting records from documents, tickets or model-generated drafts. The useful output is a record your application can safely use, not merely a response that a JSON parser accepts.

Choose the contract before the prompt

The OpenAI structured-output guide distinguishes JSON mode from schema adherence and documents refusal handling. Gemini's structured-output documentation describes its supported schema subset. These are model and endpoint features, not universal guarantees attached to every compatible API.

ContractHelps withStill requires application checks
Prompt says “return JSON”Communicating intentParsing, structure and values
JSON modeJSON syntax on supporting routesRequired fields and business rules
Schema-constrained outputSupported structural rulesSource fidelity, permissions and cross-field logic
Tool callSelecting an application operation and argumentsAuthorization and safe execution

Use a tool call when the model needs to request an application action. Use an output schema when the application needs a record. Combining the two without a clear boundary can turn extracted text into an unintended action.

Design unknown values deliberately

Consider an invoice fixture. You need an invoice ID, currency, amount and due date. The source may omit the due date. Requiring a date-shaped string without permitting a missing value encourages a syntactically valid invention.

{
  "invoice_id": "INV-DEMO-17",
  "currency": "USD",
  "amount": "125.40",
  "due_date": null,
  "evidence": "Total due: USD 125.40"
}

This is an authored example, not a real invoice or model result. Use a decimal string or integer minor units for money when your application needs exact arithmetic. Keep the original evidence text long enough to verify the amount, but avoid retaining unrelated personal information.

Define how missing, unreadable and contradictory values differ. A missing date can be null; contradictory totals may require a review state. Do not collapse both into an empty string if downstream automation treats an empty string as a valid default.

Validate meaning after parsing

A schema can enforce that currency is a string, but your application may support only a defined set of currencies. It can require amount, but cannot by itself prove that the number matches the document. Put those rules in code that remains independent of the model.

from decimal import Decimal

record = {
    "currency": "USD",
    "amount": "125.40",
    "due_date": None,
}
allowed_currencies = {"USD", "EUR"}
if record["currency"] not in allowed_currencies:
    raise ValueError("Unsupported currency")
amount = Decimal(record["amount"])
if not amount.is_finite() or amount < 0:
    raise ValueError("Invalid amount")
if amount != amount.quantize(Decimal("0.01")):
    raise ValueError("Unexpected precision")
print(amount)

This local validator demonstrates business checks; it is not a complete invoice system. It still needs source comparison, schema validation and an explicit policy for refunds, negative invoices or other valid exceptions in your business. Do not transfer funds or create an irreversible record solely because the output passes this small example.

Test the cases that make extraction fail

Build a fixture with a normal record, a missing date, two conflicting totals, an unreadable amount, an unsupported currency and a document containing instructions to ignore the schema. The last case checks whether untrusted source text gets mistaken for application instructions.

Score field correctness separately from schema validity. If 100 hypothetical documents yield 98 parseable records but only 84 records with all required facts correct, the usable result is 84, not 98. These numbers illustrate the measurement distinction and are not model performance data.

Keep refusals and truncated outputs outside the success path. A stream ending halfway through an object should remain incomplete even if a permissive parser can recover a few fields. A refusal should be shown as a refusal, not converted into a record with missing values and passed downstream.

Compare models using the cost of accepted records

Measure total charges across first attempts, repair prompts and rejected results, then divide by accepted records. A lower-priced model may need additional repair turns; a more expensive model may still invent unsupported values. Both need the same fixture and validation rules.

Do not silently weaken a schema to make one candidate pass. If a simpler schema fits your application, apply it consistently and rerun every candidate. Keep the schema version with the model configuration so later changes can be evaluated against a known contract.

For KeepRouter, check the model catalog and API reference for the exact route before using a schema-specific parameter. Compatibility with ordinary chat is not evidence of strict schema support. The migration checker helps inspect the request configuration, while the extraction evaluation guide provides a source-grounded trial design for choosing a model.

Frequently asked questions

Does strict JSON guarantee correct facts?

No. Structural compliance does not prove the values match the source. Validate evidence, business rules and missing-data handling separately.

Should missing fields be guessed?

No. Design an explicit unknown state, such as null or review_required, and make downstream behavior depend on that state rather than a fabricated value.

Is JSON mode identical across gateways?

No. Verify the selected model, endpoint and supported schema subset. A parameter accepted by one route may be rejected or behave differently on another.

Sources reviewed

Article last reviewed 2026-09-29

  1. [1] OpenAI structured outputs
  2. [2] Gemini structured outputs

Related guides

← All posts · Models & pricing · Get an API key