Batches
Queue up to 100 requests for one endpoint at half price, then poll GET /v1/batches/{id} or get a signed webhook.
POST
https://api.serpkite.com/v1/batches
Credits: Half the realtime price; polling is free
Send one endpoint and 1–100 requests (the same bodies the realtime endpoint takes). The answer is 202 Accepted with batches: one entry per request, in order, each either a batch job or an error object (for example a request that failed validation). Each job is billed at 0.5× the realtime price, and failed jobs are refunded.
Poll GET /v1/batches/{id} (free) with a job id, or follow its poll_url, until status is done or failed. Or pass webhook_url (or set an account webhook) and we POST each finished job, signed with X-SerpKite-Signature. See Batch requests and Webhooks.
Request body
| Parameter | Type | Default | Description |
|---|---|---|---|
endpoint required | string | Endpoint every request runs against. One of: search, images, videos, news, maps, places, reviews, shopping, scholar, patents, autocomplete, lens, webpage. |
|
requests required | array | 1–100 request objects with the same fields as the realtime endpoint (e.g. {"q":"…","country":"de"}). |
|
webhook_url | string | Where each finished job is POSTed (event batch.completed). Defaults to the account webhook set in the dashboard. |
Example request
Authenticate with Authorization: Bearer $SERPKITE_API_KEY (GET requests may pass
?api_key= instead). The official SDKs read
SERPKITE_API_KEY for you. See Authentication.
curl https://api.serpkite.com/v1/batches \
-H "Authorization: Bearer $SERPKITE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"endpoint":"search","requests":[{"q":"best espresso machine","country":"us"},{"q":"best espresso machine","country":"de","language":"de"}],"webhook_url":"https://example.com/hooks/serpkite"}'
# then poll a job (free)
curl https://api.serpkite.com/v1/batches/0192f7a4-6c1e-7b3a-9d2f-5e8a1c4b7d90 \
-H "Authorization: Bearer $SERPKITE_API_KEY"Response fields
| Field | Type | Description |
|---|---|---|
batches[] | array | 202 response: one entry per request, in order. Each is a job (fields below) or {"error":{"code","message"}}. |
id | string | Job ID (UUID). |
status | string | queued, running, done or failed. |
endpoint | string | The endpoint the job runs, e.g. /v1/search. |
created_at | string | ISO 8601 timestamp. |
completed_at | string | null | When the job finished. |
credits_used | number | Credits charged (0.5× the realtime price; 0 if failed). |
poll_url | string | https://api.serpkite.com/v1/batches/<id>. |
webhook_url | string | null | Where the result is POSTed. |
webhook_status | string | null | pending, delivered or failed. |
error | object | null | code and message when status is failed. |
result | object | null | The same body the realtime endpoint returns (request, results, …, meta). Present when done; kept for 24 hours. |
Example response
{
"id": "0192f7a4-6c1e-7b3a-9d2f-5e8a1c4b7d90",
"status": "done",
"endpoint": "/v1/search",
"created_at": "2026-09-29T08:00:00Z",
"completed_at": "2026-09-29T08:03:12Z",
"credits_used": 0.5,
"poll_url": "https://api.serpkite.com/v1/batches/0192f7a4-6c1e-7b3a-9d2f-5e8a1c4b7d90",
"webhook_url": null,
"webhook_status": null,
"error": null,
"result": {
"request": {
"endpoint": "search",
"engine": "google",
"q": "best espresso machine",
"country": "us",
"language": "en"
},
"results": [
"…"
],
"related_searches": [],
"meta": {
"request_id": "req_01J8ZK4M6Q2V7",
"credits_used": 0.5,
"cached": false,
"engine": "google",
"latency_ms": 1034,
"parse_quality": "ok",
"resolved_urls": true
}
}
}Errors
Errors use one shape: {"error":{"code","message","request_id"}}. Errors are never billed.
Full list in Errors.
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_request | A parameter is missing or invalid. |
| 401 | unauthorized | The API key is missing, invalid or revoked. |
| 402 | insufficient_credits | Your balance is too low. Buy a pack or wait for the monthly free grant. |
| 404 | not_found | The batch job does not exist, belongs to another account, or its result has expired. |
| 429 | rate_limited | Too many requests per second for your plan. Retry after the Retry-After header. |
| 503 | upstream_error | Google could not be fetched or parsed. Not billed; retry after Retry-After. |
Notes
GET /v1/batches/{id}is free. Poll every few seconds at most; jobs target completion within 15 minutes.- Realtime endpoints reject JSON arrays; send many queries through this endpoint instead.
- The official SDKs wrap both calls:
sk.batches.create(…)andsk.batches.wait(id).