Synchronous mode returns the finished result directly in the HTTP response. You make one request, the call blocks for the capture duration, and you get a 200 with the parsed Envelope. No polling, no webhook. Sync is the default for the hello-world case: a request with one surface and no webhook runs synchronously without any flag. Multi-surface requests, requests with a webhook, or ?mode=async use the durable 202 path instead — see asynchronous requests.

Three ways to go synchronous

Just send one surface

A POST /v1/search with exactly one surface and no webhook is synchronous by default.

Force it explicitly

Add ?mode=sync or send the header Prefer: wait=30 to pin the inline path.

Use the surface alias

POST /v1/search/:surface (e.g. /v1/search/chatgpt) accepts prompt (an alias of query) and a flat country.
All paths return the same shape. The alias is just a shorter, single-surface form of the same call.

Request

The equivalent call via the alias — note prompt and flat country:
cURL

Response

You get 200 with the parent id, its rollup status, and the full Envelope for each child — the same four-section Envelope a child returns from GET /v1/jobs/:id:
jobId
string
The parent id for this submission. status is the rollup across children (completed, partial, or failed).
children
object[]
One full Envelope per child. Each has four sections: job, provenance, answer, and evidence (plus optional html and credits). When provenance.surfacePresent is false and a surface_absent warning is present, the surface returned nothing. The capture still completes with an empty answer and costs no credits.
Read answer.markdown for display. Add ?view=flat if all you want is { surface, status, text, markdown, sources }.

Built-in retry on transient failures

A sync call blocks on a single live capture, so a transient upstream hiccup — a timeout or a 5xx from the surface — would otherwise surface immediately as an error. To keep the default single-surface path reliable, the capture step gets a small bounded server-side retry on transient failures before the response returns, within the request’s wait budget. Only genuinely transient failures are retried; a deliberate stop (a captcha or login wall) or a validation error is returned right away, never retried.
This is a small budget scoped to the sync wait. Asynchronous jobs get the full durable retry budget of the background Workflow instead — up to 8 bounded steps — so for large fan-outs or flaky surfaces, prefer async. Retries never double-bill: a capture is charged only once, on success.

Errors specific to sync

Because the call blocks on a live capture, two error paths matter more here than in async.
Your key has a sync concurrency budget — the number of blocking captures allowed at once. When too many sync calls are already inflight, new ones get 429 CONCURRENCY_LIMIT_EXCEEDED. Wait for the Retry-After window, then retry — or switch to ?mode=async. The response also carries X-Concurrency-Limit, X-Concurrency-Running, and X-Concurrency-Queued so you can back off precisely. See concurrency & rate limits.
If the surface doesn’t respond within the capture window, you get 504 SURFACE_TIMEOUT. This is a transient upstream timeout — retry the request. No credits are charged for the failed capture, since captures are billed only on success.
All 429s also carry Retry-After plus X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset. Honor Retry-After before retrying.

When not to use sync

Do not use synchronous mode for fan-out. A sync call captures one surface × region and holds the connection for its entire duration — issuing many in parallel will exhaust your sync concurrency budget and stall behind slow captures. For multiple surfaces or regions, submit one async POST /v1/search and receive results via webhooks or by polling children. See asynchronous requests.

Next steps

Asynchronous requests

Fan out across surfaces and regions without blocking.

Concurrency & limits

Understand the sync budget, rate limits, and the headers to back off on.