This page is written for machine consumption. It contains everything an autonomous coding agent needs to integrate the AI Search API end to end: authentication, submitting a search, polling for results, parsing the response, handling errors, and staying within budgets, with explicit URLs and complete JSON shapes. Everything here is plain HTTP. For the entire documentation set as one file, fetch /llms-full.txt. The machine-readable contract is /openapi.json (OpenAPI 3.1).

Base URL and authentication

  • Base URL: https://api.aisearchapi.dev
  • Every request except the discovery and health endpoints requires: Authorization: Bearer <API_KEY>
  • Requests with a JSON body require: Content-Type: application/json
  • Keys look like sk_live_... or sk_test_.... Keep them server-side. New accounts start with 500 free credits.
  • A metered (restricted) key adds live credit headers to its submits — see Step 6.
Two endpoints are deliberately unauthenticated so you can discover capabilities before you hold a key: GET /v1/surfaces and GET /v1/regions. GET /v1/health is also public.

Step 0 — Discover what is live (no key needed)

Response:
Only request surfaces where live is true. A surface with live: false (currently gemini, phase 2) returns 422 UNSUPPORTED_METHOD_FOR_SURFACE.

Step 1 — Decide sync or async

There is one endpoint, POST /v1/search, with two response modes: Force sync with ?mode=sync (or header Prefer: wait=30). Force async with ?mode=async. Add ?view=flat to reduce a sync result to { surface, status, text, markdown, sources }. POST https://api.aisearchapi.dev/v1/search Request body fields (unknown top-level fields are rejected with 400 VALIDATION_FAILED — send only these): Minimal single-surface (sync) submit:
Sync 200 with ?view=flat:
On a metered (restricted) key, the sync 200 also carries X-Credits-Charged and X-Credits-Remaining headers, and the full (non-flat) result includes a credits object — see Steps 4 and 6. Multi-surface (async) submit returns 202:
On the 202, credits.creditsCharged is 0 until settlement; the parent rollup carries creditsToCharge only. The X-Credits-Charged / X-Credits-Remaining headers are present here too. Child id format: exactly three dot-separated segments — <jobId>.<surface>.<regionKey> — where regionKey is the lowercased country[:city][:language] or GLOBAL. Never construct child ids yourself; use the ones returned.

Step 3 — Poll for results (async)

GET https://api.aisearchapi.dev/v1/jobs/<id>
  • A parent id (no dots) returns a rollup: { job: { id, status, children: [...] }, children: [{ id, surface, region, status }], credits: { creditsToCharge } }.
  • A child id (dotted) returns the full Envelope for one surface × region (including its credits object).
Poll the parent until job.status is terminal, then read each child. Terminal states — stop on any of these, not just completed:
Active (keep polling): queued, running, processing. A claimed-but-not-yet-persisted child returns { "job": { "id": ..., "status": "running" }, "children": [] }. Parent rollup rules: completed iff every child completed; failed iff every child failed; otherwise partial; processing while any child is still active. Poll one parent to completion, then fetch children:

Step 4 — Parse the Envelope

A child resolves to the public Envelope: job, provenance, answer, evidence, plus optional html and credits. Full shape:
Field reference: When html is present the Envelope gains one field, e.g. "html": "https://api.aisearchapi.dev/v1/artifacts/<key>". Absence is data. If a surface returns nothing, the child still reaches completed with provenance.surfacePresent: false, an empty answer, and a surface_absent entry in job.warnings. This is a valid result, not an error, and it costs no credits. Do not treat it as a failure.

Step 5 — Handle errors

Every error, on every endpoint, is this flat shape (HTTP status carries the status; it is not duplicated in the body):
Branch on code (stable), never on error (human text, may change). request_id matches the X-Request-Id response header. Full catalog:

Step 6 — Budgets, rate limits, and idempotency

Credits. Per-surface, charged only on a successful capture (empty/failed captures are free). Costs by surface: Total spend for a search = Σ(surface cost) × regions. An insufficient balance is 402 and nothing runs. Read your ledger at GET /v1/usage. Credit visibility. On a metered (restricted) key, every submit returns X-Credits-Charged (debited by this submit) and X-Credits-Remaining (balance after) on both the sync 200 and the async 202. A credits object { creditsToCharge, creditsCharged } appears on the sync result, the async 202 accept (creditsCharged 0 until settlement), each accepted batch item, the parent rollup (creditsToCharge only), each child job GET, and the webhook payload. Rate limits. Three independent 429 gates: RATE_LIMIT_EXCEEDED (request rate), CONCURRENCY_LIMIT_EXCEEDED (sync captures in flight), QUEUE_CAPACITY_EXCEEDED (async queue full). Every 429 carries Retry-After (seconds) plus X-RateLimit-Limit/-Remaining/-Reset. Always honor Retry-After. Read GET /v1/async/status to pace against live headroom before a burst. Response headers to read: X-Request-Id (correlation), X-AISearch-Version (schema version), X-Credits-Charged / X-Credits-Remaining (metered submits, sync + async), X-RateLimit-* (on submits + 429s), X-Concurrency-* (on submits), Retry-After (on 429), Idempotent-Replayed: true (on a replay). Idempotency. Set idempotencyKey in the body. The same key + same body replays the original job (202 + Idempotent-Replayed: true, no new work, no double billing). The same key + a different body is 409 IDEMPOTENCY_CONFLICT. Use a stable derived key so a retry after an ambiguous failure is safe.

Step 7 — Webhooks (optional, avoids polling)

Attach webhook: { url, secret } to a search (forces async). You receive one HTTP POST per child on its terminal state:
result is the same Envelope as GET /v1/jobs/<childId>. Deliveries are at-least-once — dedupe on the event id. Signature (verify BEFORE JSON-parsing). Every signed delivery carries two headers: X-AISearch-Timestamp (unix seconds) and X-AISearch-Signature. The signature is HMAC-SHA256(secret, "${timestamp}.${body}"), lowercase hex — the signed string is the timestamp, a literal ., then the raw request body. To verify: (1) capture the raw body bytes before parsing, (2) bound the timestamp skew — reject anything older than ~5 minutes, (3) recompute HMAC-SHA256 over "${timestamp}.${rawBody}", (4) compare with a timing-safe equality.
Always keep polling (GET /v1/jobs/:id) as the fallback path — the result is persisted regardless of delivery.

Step 8 — Use MCP instead of raw HTTP (optional)

If your agent prefers tool calling, connect it to the MCP server. It exposes the same search, job, usage, surface, and watch operations with the same authentication, credits, tenancy, and error semantics.

Endpoint index

Complete parameter and schema detail: /openapi.json. Whole corpus as one file: /llms-full.txt. For tool-calling clients, the authenticated MCP endpoint is /mcp.