webhook runs asynchronously: you get an immediate acknowledgment, and the actual captures run durably in the background. (A single-surface request with no webhook runs synchronously by default — add ?mode=async to force the durable path for it too.)
The async model
An asyncPOST /v1/search returns 202 Accepted right away with a parent job. The parent fans out into one child per surface × region — that’s the unit of work that actually runs a capture and produces an Envelope.
202 response names the parent and lists its children — here, 2 surfaces × 2 regions = 4 children:
The response also carries
X-Request-Id, X-AISearch-Version, and the live
X-RateLimit-* / X-Concurrency-* admission headers. For a single surface
where you’d rather block and get the result inline, that’s the sync
default (or force it with ?mode=sync / Prefer: wait=30).Parent vs child ids
The shape of a job id tells you what you’ll get back when you read it.Resolves to the fan-out summary:
{ job, children[] }. Use it to see overall status and enumerate children.Shaped
job_<id>.<surface>.<regionKey>: three segments, the surface and the lowercased region key (country[:city][:language], or GLOBAL when untargeted). Resolves to the canonical Envelope, the answer and its provenance, for exactly one surface in one region.GET /v1/jobs/:id. The id you pass decides which shape comes back. Never construct child ids by hand — use the ids the API returns.
Lifecycle states
Parent rollup rules
A parent’s status is derived from its children:completed— every child completed.failed— every child failed.partial— a mix of completed and failed children.
processing.
A child can complete even when the surface returned nothing. In that case the
Envelope has
provenance.surfacePresent: false, an empty answer, and a
surface_absent warning — the job is still completed, and an empty capture
is not charged. See The Envelope.How to read results
You have two ways to collect results after the202.
1
Poll the parent for status
GET /v1/jobs/job_8t2q returns the current parent status and every child’s
status. Stop as soon as the parent reaches a terminal state.2
Read each child Envelope
For every child that reached
completed (or partial’s completed
children), GET /v1/jobs/job_8t2q.chatgpt.us to fetch its full Envelope.GET looks like this:
A minimal poll loop
Node
The Envelope
The canonical shape a child job resolves to.
Webhooks
Get pushed each child’s result instead of polling.