Every AI Search API call follows the same shape: a JSON POST to the base URL, authenticated with your API key. You describe what to ask (a query) and where to ask it (one or more surfaces), and the API captures the answer from a real browser driving the live AI apps — then normalizes every result into one consistent Envelope.

The essentials

Every request shares three constants:
  • Base URLhttps://api.aisearchapi.dev
  • Auth — an Authorization: Bearer <API_KEY> header on every call
  • Format — JSON in, JSON out (Content-Type: application/json)
Keep your API key server-side. Never ship it in client-side code or commit it to source control. The examples below read it from an AISEARCH_API_KEY environment variable.

The request body

The core endpoint is POST /v1/search. At minimum it needs a query and at least one surface.
query
string
required
What to ask, 1–10,000 characters.
surfaces
string[]
required
Which AI apps to capture from. One or more of chatgpt, claude, perplexity, gemini, copilot, google_ai_overview, google_ai_mode.
regions
object[]
default:"[{ country: 'US' }]"
Where to run each capture: { country, city?, language? }, country as an ISO-3166 alpha-2 code. See Regions.
priority
number
default:"5"
Scheduling priority, 1–10. Higher runs sooner under load.
webhook
object
{ url, secret } — get notified when captures finish instead of polling. See Webhooks.
idempotencyKey
string
A key you supply to safely retry the same request without creating duplicate work.

One request fans out

A single POST /v1/search produces one child capture per surface × region. Ask two surfaces across two regions and you get four children — each captured independently, each normalized to the same Envelope. The response you get back is a parent job whose children[] are the individual captures:
{
  "jobId": "job_8t2q",
  "status": "processing",
  "children": ["job_8t2q.chatgpt.us", "job_8t2q.claude.us"]
}
Each child id is job_<id>.<surface>.<region>. You fetch a child directly with GET /v1/jobs/:id to get its Envelope.

Two response shapes

The same request can resolve two ways, depending on how you call it.
POST /v1/search returns immediately with 202 and a parent job in the processing state. The captures run in the background; you learn the outcome by polling GET /v1/jobs/:id or by receiving a webhook. This is the right default for multi-surface requests, since each child finishes on its own schedule.

Synchronous vs. asynchronous

SynchronousAsynchronous
How to invoke?mode=sync or Prefer: waitDefault
Status code200202
ResponseEnvelope inlineParent job + children[]
SurfacesOne per callMany (fans out)
You get results byThe same HTTP responsePolling GET /v1/jobs/:id or a webhook
Best forInteractive, single-surface lookupsMulti-surface / multi-region jobs, batch work, background pipelines
The convenience alias POST /v1/search/:surface (for example /v1/search/chatgpt) is synchronous by default and accepts prompt as an alias of query plus a flat country. It’s the quickest way to hit one surface.

A minimal request

This asks ChatGPT and Claude the same question. Because it uses the default mode, it returns a 202 parent job.
curl https://api.aisearchapi.dev/v1/search \
  -H "Authorization: Bearer $AISEARCH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "best noise-cancelling headphones under $300",
    "surfaces": ["chatgpt", "claude"]
  }'
To make the same call synchronous for a single surface, append ?mode=sync to the URL and pass exactly one surface — the response becomes a 200 with the Envelope inline.

Next steps

Synchronous requests

Get one surface’s Envelope back in the same call.

Asynchronous requests

Fan out, then poll the parent job for results.

Webhooks

Skip polling — get notified when captures finish.