202 immediately with a parent job and one child per surface × region. Poll GET /v1/jobs/:id or register a webhook to receive each child’s Envelope on completion.
Authorization: Bearer <API_KEY> and Content-Type: application/json.
Body
The prompt to run, 1–10000 characters. This is the exact text sent to each surface.
One or more surfaces to capture. At least one is required. Each surface produces one child job per region.Allowed values:
chatgpt, claude, perplexity, gemini, copilot, google_ai_overview, google_ai_mode.Where to run each surface. One child is created per surface × region.
Queue priority, 1–10. Higher values are scheduled ahead of lower ones within your account.
Receive a signed POST on each child’s terminal state instead of polling. Recommended for fan-out.
Safe-retry key. This is a body field, not a header. Reusing the same key with the same body replays the original job; reusing it with a different body returns
409 IDEMPOTENCY_CONFLICT.Request
Response 202 Accepted
The parent job id has no dots. Each entry in children is a dotted child id you can read individually.
The parent job id (dotless). Read it with
GET /v1/jobs/job_8t2q to see the roll-up status and per-child state.Always
processing on submit. Terminal states are completed, partial, failed, canceled, expired.One dotted child id per surface × region, e.g.
job_8t2q.chatgpt.us. Reading a child id returns its Envelope.Sync variant
For a single surface you can get the Envelope inline with200 instead of polling. Add ?mode=sync to the URL or send the header Prefer: wait.
Response 200 OK
Returns the full Envelope for the single surface. See The Envelope for every field.
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 and is sync by default — no ?mode=sync needed. It accepts two convenience fields:
prompt— alias ofquery.country— flat sugar forregions: [{ "country": "..." }].
200 with the Envelope, exactly like the sync variant above.
Idempotency
IncludeidempotencyKey in the body to make retries safe.
| Scenario | Result |
|---|---|
| First request with a key | 202 — a new job is created. |
| Same key + same body | 200 with header Idempotent-Replayed: true — the original job is replayed, no new work. |
| Same key + different body | 409 IDEMPOTENCY_CONFLICT. |
Errors
Every error uses the shape{ "error": { "code", "message", "status", "details"? } }.
| Code | Status | When |
|---|---|---|
AUTH_MISSING | 401 | No Authorization header. |
AUTH_INVALID | 401 | Bad or revoked API key. |
VALIDATION_FAILED | 400 | Body failed validation; see details[]. |
UNSUPPORTED_SURFACE | 400 | A value in surfaces (or the alias :surface) is not requestable. |
IDEMPOTENCY_CONFLICT | 409 | Same idempotencyKey reused with a different body. |
RATE_LIMIT_EXCEEDED | 429 | Account request rate exceeded. |
CONCURRENCY_LIMIT_EXCEEDED | 429 | Too many in-flight sync requests. |
QUEUE_CAPACITY_EXCEEDED | 429 | Async queue is full. |
SURFACE_TIMEOUT | 504 | A sync capture did not finish in time. |
Retry-After alongside X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset. See Errors for the full catalog.
Response headers
| Header | On | Meaning |
|---|---|---|
X-AISearch-Version | every response | API version that served the request. |
Location | 202 | URL of the created parent job. |
Idempotent-Replayed | replays | true when an idempotent request replayed an existing job. |
X-RateLimit-Limit | rate-limited | Request ceiling for the current window. |
X-RateLimit-Remaining | rate-limited | Requests left in the current window. |
X-RateLimit-Reset | rate-limited | When the window resets. |
Retry-After | 429 | Seconds to wait before retrying. |
Read a job
Poll a parent or fetch a single child’s Envelope.
The Envelope
Every field in the canonical per-surface result.