Search
POST /v1/search — call any catalog search service with one request format and one response format.
POST https://api.serphubapi.com/v1/search
One call returns search results in a unified structure, whichever engine answers. If a data path fails, SerpHubAPI switches to another one automatically — you are charged at most once, and nothing if every attempt fails.
Request
Send a JSON body with Content-Type: application/json. Only q is required.
| Parameter | Type | Default | Description |
|---|---|---|---|
q | string | — | Required. The search query (1–2048 characters, leading/trailing spaces trimmed). |
engine | string | auto | The search source: google, bing, yandex, baidu, xiaohongshu, wechat, taobao, deepseek, yuanbao … auto uses Google with Bing as fallback. See Services. |
type | string | web | Result type offered by that source, e.g. web, news, images, videos, shopping, maps, scholar, autocomplete, notes, articles, products. engine + type names one service. |
gl | string | — | Country code, e.g. us, gb, de. |
hl | string | — | Language code, e.g. en, zh-cn. |
num | integer | 10 | Number of results, 1–100. |
page | integer | 1 | Result page, starting at 1 (max 100). |
time_range | string | — | day, week, month or year. Restricts results to that period. |
mode | string | live | live always fetches fresh results. cache_first may return a result cached within the last hour, at half price — and free if it is a cache hit. |
include_content | integer | 0 | 0–5. Also fetch the main content of the top N results as Markdown. 3 credits per page. Not available for type=autocomplete. |
Not every service honours every optional parameter (DeepSeek search, for example, has no page, gl or hl). Sending a non-default value for a parameter the service does not support returns 400 validation_error; each service's supported parameters are listed in GET /v1/services.
| format | string | json | json, or markdown to receive the whole result as one Markdown document. |
gl and hl are case-insensitive. Unknown fields in the body are ignored.
Example
curl -X POST https://api.serphubapi.com/v1/search \
-H "X-API-Key: shapi_xxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"q": "best espresso machine 2026",
"engine": "google",
"type": "web",
"gl": "us",
"hl": "en",
"num": 10,
"time_range": "month"
}'
Services and prices
Each engine + type pair is one service with its own per-call price — for example google/web (10 credits), deepseek/web (8 credits). mode=cache_first costs half the service price. The full list, with prices, supported parameters and live status, is on the services page and in GET /v1/services.
- A type the source does not offer (e.g.
engine=bing, type=shopping) returns400 validation_error. - A service that is listed but not launched yet (e.g.
engine=baidu) returns503 engine_unavailable.
Response (JSON)
{
"meta": {
"id": "sch_01J9Z3KQ8W",
"status": "success",
"engine": "google",
"cached": false,
"credits_charged": 10,
"time_ms": 812
},
"params": {
"q": "best espresso machine 2026",
"engine": "google",
"type": "web",
"num": 10,
"page": 1,
"gl": "us",
"hl": "en",
"time_range": "month",
"mode": "live"
},
"results": {
"organic": [
{
"position": 1,
"title": "The 8 Best Espresso Machines of 2026",
"link": "https://example.com/espresso",
"snippet": "We tested 30 machines ...",
"date": "2026-09-14"
}
],
"people_also_ask": [
{ "question": "Which espresso machine is best for beginners?", "snippet": "...", "link": "https://..." }
],
"related_searches": ["best espresso machine under 500"],
"knowledge_graph": {}
}
}
meta
| Field | Type | Description |
|---|---|---|
id | string | Call ID (sch_...). Use with GET /v1/searches/{id} and when contacting support. |
status | string | Always success on a 200 response. |
service | string | The service that answered, as engine/type (e.g. google/web). |
engine | string | The source that answered. With engine=auto this tells you which one was used. |
cached | boolean | true if the result came from cache (mode=cache_first only). |
credits_charged | integer | Credits actually deducted for this call. 0 for cache hits and empty results. |
time_ms | integer | Server-side processing time for this call, in milliseconds. |
params
The parameters that actually took effect, after defaults were applied. Useful for logging and debugging.
results
Only the keys relevant to the request are present. Fields an engine does not provide are omitted rather than filled with guesses.
| Key | Present for | Item fields |
|---|---|---|
organic | web, scholar | position, title, link, snippet, date (when available) |
news | news | position, title, link, source, date, snippet |
images | images | position, title, link (page containing the image), image (original image URL), thumbnail |
videos | videos | position, title, link, thumbnail, duration |
shopping | shopping | position, title, link, price, currency, merchant, rating |
places | maps | position, name, address, rating, reviews, link |
suggestions | autocomplete | array of strings |
people_also_ask | web (when shown) | question, snippet, link |
related_searches | web (when shown) | array of strings |
knowledge_graph | web (when shown) | free-form object |
content
Present only when include_content > 0. One item per fetched result, in result order:
| Field | Type | Description |
|---|---|---|
link | string | The result URL. |
markdown | string | Cleaned main content as Markdown. Empty string if the page could not be fetched. |
error | string | fetch_failed when the page could not be fetched. Failed items are not charged. |
Content is taken from the main result list for the type (organic for web, news for news, and so on), skipping duplicate links.
Empty results
If the search succeeds but returns nothing, you get 200 with empty result arrays and meta.credits_charged: 0. Content is not fetched for empty results.
Markdown format
With "format": "markdown" the response is text/markdown instead of JSON — ready to paste into an LLM context. Since there is no JSON meta, the key values are in response headers:
| Header | Description |
|---|---|
X-Search-Id | Call ID (same as meta.id) |
X-Credits-Charged | Credits deducted |
X-Cached | true or false |
Rate limit headers are included as usual. Example output:
# Search: best espresso machine 2026
_engine: google · type: web · id: sch_01J9Z3KQ8W · credits: 10_
## Results
1. [The 8 Best Espresso Machines of 2026](https://example.com/espresso) — 2026-09-14
We tested 30 machines ...
## People also ask
- **Which espresso machine is best for beginners?** ...
## Related searches
- best espresso machine under 500
With include_content, each page follows as a ## Content: <url> section.
Credits
| What | Credits |
|---|---|
mode=live search | 10 |
mode=cache_first search | 5 (0 on a cache hit) |
include_content | +3 per page successfully fetched (cache hits under cache_first are free) |
| Empty result | 0 |
| Failed call (any error response) | 0 |
Your balance must cover the maximum possible cost of the call before it starts (for example 10 + 3 × 5 = 25 credits for a live search with include_content: 5). Anything not used is returned immediately; you are only charged meta.credits_charged. See Billing.
Errors
| HTTP | Code | When |
|---|---|---|
| 400 | validation_error | Invalid parameter, or unsupported engine/type combination |
| 401 | invalid_api_key | Missing, invalid or disabled key |
| 402 | insufficient_balance | Not enough credits |
| 429 | rate_limited | Rate limit or key daily credit limit reached |
| 502 | all_upstreams_failed | The search could not be completed. Not charged |
| 503 | engine_unavailable | Engine not launched or temporarily unavailable |
Details in Errors.