Batch search
POST /v1/batch — up to 5 searches in one request. Each one is billed like a single search, and one failure does not block the others.
POST https://api.serphubapi.com/v1/batch
Run up to 5 searches in one round trip — the same query across several sources, or several queries on one source. Each item is a normal search request and follows the same rules: routing and failover, cache, and billing (failed, empty and cache-hit items cost nothing). One item failing does not stop the others.
Request
| Parameter | Type | Description |
|---|---|---|
queries | array | Required. 1–5 items. Each item takes the same fields as POST /v1/search: q, engine, type, gl, hl, num, page, time_range, mode, include_content. |
The response is always JSON; an item's format is ignored.
curl https://api.serphubapi.com/v1/batch \
-H "X-API-Key: shapi_xxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"queries": [
{"q": "wireless earbuds", "engine": "google", "gl": "us"},
{"q": "wireless earbuds", "engine": "amazon", "type": "products"},
{"q": "无线耳机", "engine": "xiaohongshu", "type": "notes"}
]}'
Response
200 whenever the request itself is valid — check each item for its own outcome. Items come back in request order.
{
"results": [
{
"query": { "q": "wireless earbuds", "engine": "google", "type": "web" },
"results": { "organic": [ { "position": 1, "title": "...", "link": "https://..." } ] },
"meta": { "id": "sch_01J9Z3KQ8W", "status": "success", "service": "google/web", "credits_charged": 10, "cached": false, "time_ms": 812 }
},
{
"query": { "q": "wireless earbuds", "engine": "amazon", "type": "products" },
"results": { "products": [ { "position": 1, "title": "...", "price": "$29.99" } ] },
"meta": { "id": "sch_01J9Z3KR2A", "status": "success", "service": "amazon/products", "credits_charged": 10, "cached": false, "time_ms": 1530 }
},
{
"query": { "q": "无线耳机", "engine": "xiaohongshu", "type": "notes" },
"error": { "code": "insufficient_balance", "message": "..." },
"meta": { "status": "failed", "credits_charged": 0 }
}
],
"meta": { "calls": 3, "total_credits_charged": 20 }
}
| Field | Description |
|---|---|
results[].query | The item's q, engine and type, so you can match results to requests. |
results[].results | Same as results in a search response. Present on success. |
results[].content | Page content, when the item set include_content. |
results[].meta | The item's own meta, as in a search response. Each successful item has its own id, usable with GET /v1/searches/{id}. |
results[].error | On failure: code and message, same codes as Errors. The item costs 0. |
meta.total_credits_charged | Sum of what all items were charged. |
Good to know
- Items run one after another, so a batch takes about as long as its items combined. For large volumes, send several batches in parallel within your rate limit.
- Each item is checked against your balance and key limits as it runs. If credits run out mid-batch, the remaining items fail with
insufficient_balanceand cost nothing. - AI sources can be used in a batch through
engine(for example"engine": "deepseek"), but each item waits synchronously. Sources that take minutes, such as ChatGPT, may time out; send those throughPOST /v1/ai-search, which returns an async job.
Errors
The whole request fails only when it is malformed:
| HTTP | Code | When |
|---|---|---|
| 400 | validation_error | queries missing, empty or longer than 5, or an item is invalid |
| 401 | invalid_api_key | Missing, invalid or disabled key |
| 429 | rate_limited | Rate limit reached |