The migration
What is implemented
Supported
POST /v1/async/taskPOST /v1/async/task/batchGET /v1/async/task/{id}Webhook callbacksNot implemented
/v1/monitor/* synchronous endpoints/v1/async/status/v1/monitor/* family is deliberately absent. Every engine here is driven
asynchronously; a request that blocks for the minutes a browser run can take is not a shape
this service offers.
Where behaviour differs
1. Throughput varies sharply by engine
1. Throughput varies sharply by engine
The most important difference, and the only one that can bite you in production. Each
engine’s capacity here is the capacity of its backing pool of exit IPs, and we publish it
rather than hiding it behind an opaque rate limiter.
GEMINI sustains ~14 QPS. PERPLEXITY sustains ≤2. Browser-driven engines sustain much
less. Over-submitting does not produce a 429 — it produces a growing queue and, eventually,
FAILED tasks.See Rate limits and capacity.2. Credits are nominal, never billed
2. Credits are nominal, never billed
credits is present on every response as part of the envelope. Submit and poll responses
report { "creditsToCharge": 0, "creditsCharged": 0 }; webhooks report a nominal
per-engine figure.Nothing is metered. If you aggregate credits for cost reporting, the numbers will not mean
what they used to.3. Some engine × region pairs are rejected outright
3. Some engine × region pairs are rejected outright
A few combinations cannot be served at all —
CHATGPT/PERPLEXITY/GEMINI into CN,
GEMINI into DE/GB/IR. Those fail immediately with 422 REGION_UNSUPPORTED rather
than being accepted. 422 REGION_UNAVAILABLE covers the transient version of the same
thing.A client that assumes every well-formed submission is accepted needs a branch here. See
Regions.4. include flags are mostly inert
4. include flags are mostly inert
The
payload.include flags are accepted, but most engines here return a fixed-shape
response and ignore them. Only ChatGPT honours the full set; GEMINI honours markdown
and rawResponse only.Requesting html from Gemini, for instance, is silently ignored — no error, no field.
See the flag support table.5. One extra status code: 422
5. One extra status code: 422
Error handling is otherwise conventional — validation failures return
400, 401 reports
MISSING_API_KEY, 404 reports RESOURCE_NOT_FOUND, and details names the offending
field.The one addition is the 422 pair (REGION_UNSUPPORTED, REGION_UNAVAILABLE) described
above. It exists because we run our own egress and tell you up front when a region cannot
be served, so a client that has never had to handle a 422 will start seeing them.6. A failed task adds a top-level `error` string
6. A failed task adds a top-level `error` string
GET /v1/async/task/{id} on a FAILED task returns a top-level error field that the
task-status schema does not otherwise define — and it is a plain string, not the
{code, message, timestamp} object used by request-level errors.body.error as a failed request will misread a
successfully-retrieved failed task. Branch on task.status instead.These behaviours were established by calling this API, not by reading a schema. Where a
published spec and a live response ever disagree, the live response is what these pages
document.
Picking the right taskType
If your current integration calls a per-engine endpoint, the engine name maps onto a
taskType:
GOOGLE meaning “AI Overview” is a naming convention, not a Google product name. The
response is a SERP envelope with aioverview as a nullable member — see
the GOOGLE shape.Verifying the cutover
Run your existing integration and this one in parallel for a window, and diff the fields you actually consume — in practiceresponse.text, response.sources[], and
response.markdown. A shadow
comparison catches shape drift that a schema check will not, such as a source list that is
populated but ordered differently.