Search API
A Serper-compatible Google Search API — same request bodies, same response schemas. Change the base URL and keep your code.
Quickstart
Create a key in the API console, then send it as the X-API-Key header:
curl -X POST 'https://serp.tsoden.ai/v1/search' \
-H 'X-API-Key: sk-your-key' \
-H 'Content-Type: application/json' \
-d '{"q": "coffee", "gl": "us", "hl": "en", "num": 10}'
Python:
import requests
r = requests.post("https://serp.tsoden.ai/v1/search",
headers={"X-API-Key": "sk-your-key"},
json={"q": "coffee", "gl": "us", "hl": "en"}, timeout=60)
data = r.json()
for row in data.get("organic", []):
print(row["position"], row["title"], row["link"])
JavaScript:
const r = await fetch("https://serp.tsoden.ai/v1/search", {
method: "POST",
headers: {"X-API-Key": "sk-your-key", "Content-Type": "application/json"},
body: JSON.stringify({q: "coffee", gl: "us", hl: "en"}),
});
const data = await r.json();
Endpoints
| Path | Returns |
|---|---|
POST /v1/search | Organic results with snippets, dates, sitelinks, plus extracted People-Also-Ask, related searches, answer box and knowledge graph when present on the page. |
POST /v1/images | Image results (title, imageUrl, thumbnailUrl, source, dimensions). |
POST /v1/news | News results (title, link, snippet, date, source). |
POST /v1/videos | Video results (title, link, duration, channel). |
POST /v1/places | Local places (title, address, rating, phone, website, coordinates). |
POST /v1/shopping | Shopping offers (title, price, delivery, rating, offers). |
POST /v1/scholar | Scholarly articles (title, link, publication info, year, citations). |
POST /v1/patents | Patent results from Google Patents. |
POST /v1/autocomplete | Query suggestions as {"suggestions": [{"value": ...}]}, exactly like Serper. |
GET /v1/account | Credit balance and request usage for the authenticated key. |
GET /v1/locations?text= | Locations the API can pin a search to, with ready-made geo tokens. |
Machine-readable spec: /public/api/openapi.json. Reverse-image search is not offered: Google Lens blocks automated access reliably enough that we would rather document the gap than sell an unreliable endpoint.
Request parameters
| Field | Type | Description |
|---|---|---|
q | string | Search query. Required. |
gl | string | Country code (us, pl, de, …) — the Google market to search. |
hl | string | Interface language (en, pl, uk, …). |
location | string | Canonical location for geo-pinning; pick values from /v1/locations. |
num | integer | Results 1–100 (default 10). Google paginates in steps of 10. |
page | integer | Page number for deeper results. |
tbs | string | Time filter: qdr:h, qdr:d, qdr:w, qdr:m or qdr:y (past hour, day, week, month, year). |
autocorrect | boolean | false keeps the query exactly as typed, without spelling correction. |
cache | boolean | Our extension. The same question asked again within an hour is answered from our cache (response header X-Cache: HIT) and billed as usual; false forces a fresh search. |
device | string | desktop or mobile (default desktop). |
Response example (/v1/search)
{
"searchParameters": {"q": "coffee", "type": "search", "num": 10, "gl": "us", "hl": "en", "device": "desktop"},
"organic": [
{
"position": 1,
"title": "Example Coffee Co",
"link": "https://example.com/",
"domain": "example.com",
"snippet": "Freshly roasted coffee…",
"date": "Jan 5, 2026",
"displayedLink": "example.com › coffee",
"sitelinks": [{"title": "Shop", "link": "https://example.com/shop"}]
}
],
"peopleAlsoAsk": [{"question": "Which coffee is best?", "snippet": "It depends…"}],
"relatedSearches": [{"query": "coffee near me"}],
"answerBox": {"title": "Coffee", "snippet": "A brewed drink…", "link": "https://en.wikipedia.org/wiki/Coffee"},
"knowledgeGraph": {"title": "Coffee", "type": "Drink", "description": "A brewed drink prepared from roasted coffee beans."}
}
Feature blocks appear only when the search page actually contains them; a missing key means “not on this SERP”, never “detection failed”.
Errors
| Status | Meaning |
|---|---|
| 400 | Missing or invalid parameter (the body carries a message). |
| 401 | Missing, unknown, revoked or expired API key. |
| 402 | Prepaid credit balance is empty — top up to continue. |
| 429 | Rate limit exceeded; the Retry-After header says when to retry. |
| 500 | The search itself failed; the credit is refunded automatically. |
| 504 | Queued request timed out; the credit is refunded automatically. |
Pricing
10000
requests
$8.00
50000
requests
$35.00
500000
requests
$300.00
2500000
requests
$1 125.00
One request costs one credit. Credits never expire, and every failed request (HTTP 5xx/504) is refunded automatically. Buy packs under Billing → API credits once signed in.
Operational notes
- Results come from our own Google scraping infrastructure, not from a third-party SERP API — your queries never touch another provider’s key.
- Most requests take 2–8 seconds; when Google pushes back the search is retried on another exit, which can stretch one to about 55 seconds. After that it ends with 504 and the credit is refunded. Set client timeouts to 60 seconds.
- Default limits: 60 requests/minute and 5 concurrent requests per API key.
- Beyond Serper: /v1/search also returns aiOverview (the text of Google’s Answer Overview with its sources) when Google shows one. Google streams long overviews in, so the text can be the first part of a longer answer.
- Credits never expire.
- Each search is made from an IP address in the market you ask for (gl), so results are the ones a searcher there sees.
- Credit enforcement is ON for this deployment: a request without an available credit is refused with 402.
- This deployment serves requests through a background worker queue; very slow requests can end in a refunded 504 instead of a result.