Integrating AI surfaces one at a time is a losing game. ChatGPT streams one shape, Perplexity cites another way, Google's AI Overview buries sources in rendered HTML, Gemini and Copilot each have their own DOM, and the model APIs return something different again. Write N parsers and you now maintain N parsers — each one breaking on its own schedule when a surface ships a redesign.
The AI Search API solves this with one design decision: every capture returns the same Envelope. Same shape for every surface, every acquisition method, every region. You write one parser, once.
What's in the Envelope
Fetch any completed child job and you get four top-level sections:
{
"job": { "id, surface, method, region, status, warnings, artifacts": "..." },
"provenance": { "method, official, fidelity, model, region, loginState": "..." },
"answer": { "text, markdown, blocks": "..." },
"evidence": { "sources, fanOut, mentions, shopping, ads": "..." }
}
answer— the response astext, as renderedmarkdown(always populated), and as structuredblocksthat reference the sources they're grounded in.evidence— the structured proof behind the answer:sources(with citation roles andcharRangesback into the text),fanOutqueries,mentions,shoppingcards, andads.provenance— how the answer was obtained (more on this below).job— identity, status,warnings[], and theartifactskeys for the durable raw payload, screenshot, and proof-of-page HTML.
A ChatGPT own-fleet capture, a Google AI Overview browser render, and a Claude official-API answer all come back in exactly this shape. The provenance block tells you how they differ; the structure never does.
Provenance is a first-class citizen
The reason a single contract works across such different surfaces is that we don't flatten the differences away — we record them, in provenance:
fidelity—consumer_ui(a real browser session saw this) orapi_surrogate(a model API generated it). You never confuse the two.official— whether an official provider API served the result.model—{ providerId, observedLabel, inferred, confidence }. Was the model label read off the page or deduced? Theinferredflag says so.region—requestedversuseffective. If a surface served a US experience despite a Japanese egress, you see the drift (and aregion_overriddenwarning) instead of trusting it blindly.loginState,captchaEncountered,stopReason,proxyGeo— the operational truth of the capture.
This is what "evidence-grade" means in practice: not just the answer, but a machine-readable account of exactly how it was obtained and which fields are ground truth versus inference.
Observed vs inferred, and absence as data
Two honesty guarantees ride inside the Envelope and matter regardless of surface:
Observed vs inferred. evidence.fanOut.provenance is "observed" when we read the fan-out queries off the page, "inferred" when we deduced them. provenance.model.inferred does the same for the model label. You always know which fields are ground truth.
Absence is data. If a surface returns no answer, the child still reaches a terminal completed status, provenance.surfacePresent is false, and warnings includes surface_absent — with the screenshot and proof-of-page still captured. A blank answer is a measurement, not a failure, and we make it provable. A lane that's genuinely unbacked (no credentials or engine) fails loud with DRIVER_UNAVAILABLE — never a fake mock.
One contract, one integration, N surfaces
Because the shape is stable and versioned (GET /v1/health reports the current schemaVersion), you can:
- Diff surfaces — compare how ChatGPT and Perplexity answer the same prompt, keyed on the same fields.
- Run shadow benchmarks — pin
own-fleetandmanaged-vendorfor one query and diff the two Envelopes side by side, same schema. - Fan out across regions — one request, one child per market, every child in the same shape.
- Add a surface without touching your parser — when a new surface (or the authenticated Claude browser lane) ships, it arrives in the Envelope you already read.
That's the point of a contract. The surfaces will keep changing shape — they always do. The Envelope is the stable thing you build on, so that when a surface redesigns overnight, your integration doesn't.
→ See the Canonical Envelope reference for every field and the full warnings[] catalog.