Skip to main content

Overview

Passing response_format to answer changes the response from Markdown prose to a JSON string matching a schema you supply. It doesn’t change citations: they come back exactly as they do without response_format, regardless of which scope grounded the search. This guide walks through building a structured response: identifying the scope your fields live in, designing the schema, writing a query that actually surfaces every field, and parsing the result safely. Each step applies directly to one running example: pulling a company snapshot out of the companies scope.

Why use a structured response

By default, answer returns Markdown prose with inline citations. That’s a fine format for a person or an agent to read, but not one code can consume directly. Asking about a company without response_format might return something like this:
Pulling a company type, a location, or a dollar figure back out of that sentence means writing a parser for prose that can rephrase itself on every call: “US” instead of “United States,” “12,500,000” instead of “12.5 million,” a different sentence order entirely. Specifying response_format replaces that parsing step: the endpoint instead returns a JSON object that matches your schema instead of prose.

What makes a structured response reliable

response_format only changes the shape of the output. It has no effect on what the grounding search looks for or finds. A schema asking for a field the grounding search never surfaces doesn’t make that field appear; it either comes back as a best guess or breaks the response’s validity. Getting a reliable structured response comes down to three things: pointing the search at the right data (this step), designing the schema correctly (Step 2), and writing a query whose answer contains what the shape asks for (Step 3).

Step 1: Identify the correct scope.

Every scope has its own native structure. The closer your schema’s fields are to a scope’s native structure, the more reliably response_format can fill them in, because the model is normalizing data that’s actually in front of it rather than inferring something absent. Example: A research tool needs a company’s legal name, industry, ownership type, headquarters country, and total funding raised. All five live in the companies scope’s native structure (Company Details and Financials, specifically), so that’s the correct scope to choose, rather than, say, news or wikipedia, which wouldn’t reliably carry all five in one place.

Step 2: Design your schema.

The schema specifies what the endpoint should return. To create the most reliable schema possible, follow these principles:
  • Include every piece of data your use case needs. If your code needs a field, name it in your schema, or it never shows up in the response. Work from what your code does with the result. Applied: the research tool needs five things, so company_snapshot has five properties: legal_name and industry to identify and categorize the company, ownership_type and hq_country for the tool’s own filtering, and total_funding_usd as the number it actually reports.
  • Use the narrowest matching type. The narrower the type, the less parsing your own code has to do afterward. Applied: the schema types total_funding_usd as number, not string. The sample data spells it $12500000, and the schema turns that into a plain 12500000 you can do arithmetic on directly.
  • Write descriptions as instructions, not documentation. A description tells the model how to derive or normalize the field, not just what it means. A description that just restates the field name gives it nothing to act on. Applied: hq_country’s description spells out the normalization from a full mailing address down to just the country. Without it, the model has no instruction to do anything but copy the address field verbatim.
  • Constrain to a fixed set with enum where one exists. If a field can only take one of a handful of known values, declare it as an enum rather than leaving it a free-form string. This applies to an entity type, a status, a category, or similar fields. Doing so rules out near-miss variants that all mean the same thing. Applied: The example schema constrains ownership_type to ["public_company", "privately_held", "nonprofit", "government_agency"]. Without the enum, one call might return "Private" and another "Privately held company", while a downstream filter matching on an exact string silently misses half of them.
  • Mark every field required. A property left out of required is optional, and the model can skip it entirely rather than returning it, even as null. If a field needs to come back on every call, it belongs in required. Applied: all five fields go in required. None of them is optional here: a snapshot missing ownership_type or total_funding_usd is exactly the kind of gap this schema exists to prevent.
  • Set additionalProperties: false on every object, including nested ones. Otherwise, the model can return fields you don’t name. JSON Schema doesn’t let a nested object inherit the setting from its parent, so you have to set it on each object yourself. See Schema validity for what happens when you omit it on a nested object under strict: true. Applied: additionalProperties: false sits on the single top-level object here.
  • Limit the schema to the fields you actually use. Every extra field is another place generation can go wrong, and a schema with unused fields makes truncation more likely on longer answers. See Step 4. Applied: The companies scope’s structure also includes headcount, web traffic, competitors, and a dozen other fields. See the full list. None of them are in this schema, because the research tool in this example doesn’t use them.
Putting the five fields together:

Step 3: Write a query whose answer contains every field.

The response_format only shapes output; for the response format to work, the query must elicit the facts that make up the response format. Two practices improve query reliability:
  • Ask for exactly the fields your schema names, in roughly the same terms. Don’t rely on the schema alone to imply what you want. Applied: The query below asks for the same five things, in the same order, as the schema’s five properties: “legal name, industry, ownership type, headquarters country, and total funding raised.”
  • Anchor the query with identifying detail. A bare name is a weak query on any scope; the more specific the query, the more likely the grounding search surfaces the one record you mean instead of a similarly named one. Applied: “Seltz” alone is ambiguous. The companies scope also has an unrelated company, Sketz.ai, and the wikipedia scope has two places that share the name “Seltz” and aren’t companies at all. The query below anchors on “the web knowledge layer company at seltz.ai” to point the search at the right entity.

Step 4: Parse defensively.

answer doesn’t validate the model’s output against your schema before returning it. A request can still succeed with a 200 and return a value that ends prematurely partway through generation, in which case it doesn’t parse as valid JSON. Always wrap the parse call in a try/catch or equivalent rather than assuming the result is well-formed. See Request a structured response for the full caveat. Putting the schema, the query, and defensive parsing together:
snapshot comes back matching the schema from Step 2, built from the same sample company profile used throughout this example:

More examples

The same four steps apply to any scope.

People

Profiles include a title and location in free-text fields, so the schema has to normalize these. This is the exact schema a customer uses to extract a name, title, and country from a LinkedIn profile. See the people scope’s field list for what else is available to extract. A bare name is too weak an anchor on this scope even with an employer attached, since common names collide with unrelated profiles. The query below anchors on Seltz’s own founder instead, whose profile is unambiguous:
extracted with:
Python

News

Articles already carry a publishedDate field, but the schema below has the model reformat it and pull an array out of the article body. See the full sample.
extracted with:
Python

Wikipedia

Articles in this scope are closer to raw prose than the other scopes, so schema fields need to point at facts the article actually states, not facts you assume. An enum keeps the entity-type field from drifting across near-duplicate values like "Village" or "town". See the full sample.
extracted with:
Python

Beyond Answer

Chat completions accepts the same response_format and scope combination. See Structured outputs if that’s your integration surface instead of answer directly. Agent takes the same JSON-schema shape too, as output_schema, but runs its own open-ended multi-step research rather than a single grounding search scoped to one of these four verticals. See Structured output for when that’s the better fit.

Next steps