Submit a query to one or more AI search surfaces.
  • One surface, no webhook (the hello-world case) runs synchronously by default: the call returns the terminal Envelope in one 200.
  • Multiple surfaces, a webhook, or ?mode=async use the durable path: 202 immediately with a parent job and one child per surface × region. Poll GET /v1/jobs/:id or register a webhook.
Every request needs Authorization: Bearer <API_KEY> and Content-Type: application/json.

Query parameters

mode
string
sync forces the bounded inline path; async forces the durable 202 + poll path. Omitted: a single-surface no-webhook request runs sync, everything else async. The header Prefer: wait=30 is equivalent to ?mode=sync.
view
string
flat projects each Envelope of a sync response to the compact flat shape (surface, status, text, markdown, sources). One child returns the flat object directly; several children return { "results": [...] }.

Body

query
string
required
The prompt to run. This is the exact text sent to each surface. prompt is accepted as an alias. Non-empty, up to 2000 characters — a longer value is rejected with 422 QUERY_TOO_LONG.
surfaces
string[]
required
One or more surfaces to capture. Each surface produces one child job per region.Allowed values: chatgpt, claude, perplexity, gemini, copilot, google_ai_overview, google_ai_mode, google_search, google_news.
regions
object[]
Where to run each surface — at most 10 per request. One child is created per surface × region. Omitted: one untargeted (GLOBAL) child per surface. A bare string like "US" is accepted as sugar for { "country": "US" }.
webhook
object
Receive a signed POST on each child’s terminal state instead of polling. Setting a webhook forces the async path. Recommended for fan-out.
idempotencyKey
string
Safe-retry key. This is a body field, not a header. Reusing the same key with the same body replays the original job (202 + Idempotent-Replayed: true); reusing it with a different body returns 409 IDEMPOTENCY_CONFLICT.
extract
boolean | object
Opt in to Auto Extract. true is identical to {}: extract brands the answer mentions without pinning targets. false, or omitting the field, disables extraction and leaves evidence.mentions as null. Auto Extract is BETA and adds 0 credits today; pricing will change at GA.
Unknown top-level fields are rejected, not silently dropped. Sending a field this endpoint doesn’t accept (a typo, or a control it doesn’t support) returns 400 VALIDATION_FAILED naming the offender. Send only the fields above — the API fails loud so a field that looks like a control never no-ops in silence.

Request

Response 202 Accepted (async)

The parent job id has no dots. Each entry in children is a dotted 3-segment child id — <jobId>.<surface>.<regionKey> — where the region key is the lowercased country[:city][:language] (or GLOBAL when untargeted).
jobId
string
The parent job id (dotless). Read it with GET /v1/jobs/job_8t2q to see the roll-up status and per-child state.
status
string
Always processing on submit. Terminal states are completed, partial, failed, canceled, expired.
children
string[]
One dotted child id per surface × region. Reading a child id returns its Envelope.
A poll loop should stop on any terminal state — prefer webhooks over polling for fan-out.

Response 200 OK (sync)

A sync call returns the parent id, its rollup status, and the full Envelope per child:
evidence.mentions populates only when the request sets extract. See Auto Extract for the full shape, pinned-target absence behavior, and examples.
With ?view=flat the same call returns just { surface, status, text, markdown, sources }.
Sync mode holds the connection open until the capture finishes and is subject to 429 CONCURRENCY_LIMIT_EXCEEDED. For more than one surface, prefer the async default.
If a surface returns nothing, the job still completes: provenance.surfacePresent is false, job.warnings carries a surface_absent warning, and answer is empty. An empty capture costs no credits.

Per-surface alias

POST /v1/search/:surface targets one surface — sync by default like any single-surface call. It accepts two convenience fields:
  • prompt — alias of query.
  • country — flat sugar for regions: [{ "country": "..." }].

Idempotency

Include idempotencyKey in the body to make retries safe.

Errors

Every error uses the flat shape { "code", "error", "request_id", "docs_url", "details"? }. Validation messages name the offending field and the allowed values.
400
429 responses carry Retry-After alongside X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset. See Errors for the full catalog.

Response headers

Read a job

Poll a parent or fetch a single child’s Envelope.

The Envelope

Every field in the canonical per-surface result.

Auto Extract

Extract brand mentions and pin targets for present-or-absent reporting.