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 — browser-first, from the live AI apps — then normalizes every result into one consistent Envelope.
The essentials
Every request shares three constants:- Base URL —
https://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 isPOST /v1/search. At minimum it needs a query and at least one surface in surfaces.
What to ask — a non-empty string, up to 2000 characters (longer is
422 QUERY_TOO_LONG). prompt is accepted as an alias.Which AI apps to capture from. One or more of
chatgpt, claude,
perplexity, gemini, copilot, google_ai_overview, google_ai_mode,
google_search, google_news. See Surfaces for which are
live today (gemini currently has no v1 path and returns 422).Where to run each capture:
{ country, state?, city?, language? }, with country as an ISO-3166 alpha-2 code. At most 10 per request. When omitted, each surface runs one untargeted (GLOBAL) capture. See Regions.{ url, secret? } — get a signed POST when each capture finishes instead of polling. Setting a webhook forces the async path. See Webhooks.Output-format flags:
{ markdown?: boolean = true, html?: boolean = false }.
Set markdown: false to trim answer.markdown from the result
(answer.text is always present); set html: true to add a proof-of-page
HTML URL on consumer-UI surfaces. Unknown include keys are rejected with
400 VALIDATION_FAILED. See Output formats.A key you supply to safely retry the same request without creating duplicate
work. A body field, not a header.
Send only the documented fields. Unknown top-level fields are rejected
with
400 VALIDATION_FAILED (the message names the offender) — the API fails
loud rather than silently dropping a field that looks like a control.One request fans out
A singlePOST /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.
On the async path, the response is a parent job whose children[] are the individual captures:
job_<id>.<surface>.<regionKey> — where the region key is the lowercased country[:city][:language] (or GLOBAL when untargeted). Fetch a child directly with GET /v1/jobs/:id to get its Envelope.
Every Envelope carries the normalized answer alongside structured evidence — the sources[] behind the answer, the fanOut queries the surface ran, and any brand mentions — at no extra credit cost. See Output formats for the full shape.
Two response shapes
The same endpoint can resolve two ways, depending on what you submit.- Synchronous (default for one surface)
- Asynchronous (fan-out)
A request for one surface with no webhook runs synchronously by default:
the API holds the connection while the capture runs and returns
200
with the finished result inline — the parent id, its rollup status, and the
full Envelope per child. You can force this path explicitly with
?mode=sync or the header Prefer: wait=30, and simplify the shape with
?view=flat.Both shapes report billing. Metered (restricted-key) submits return
X-Credits-Charged and X-Credits-Remaining headers on the sync 200 and
the async 202, and a credits object ({ creditsToCharge, creditsCharged })
rides along on the sync result and each child job. Billing is success-only.
See Credits.Synchronous vs. asynchronous
A minimal request
This asks ChatGPT and Claude the same question. Because it names two surfaces, it returns a202 parent job.
"claude" from surfaces and the same call becomes synchronous automatically — a 200 with the finished ChatGPT result inline.
Next steps
Synchronous requests
Get one surface’s result back in the same call.
Asynchronous requests
Fan out, then poll the parent job for results.
Webhooks
Skip polling — get notified when captures finish.