SerpResult support
Overview
Search engine results as JSON.
SerpResult 1.0.0
Section titled “SerpResult 1.0.0”SerpResult returns the organic results of a web search as JSON. Two search
endpoints, both synchronous: GET /v1/query runs one search and
POST /v1/bulk runs up to 50 in one request. Everything else on this
surface is the dashboard’s reporting and credential management.
Authentication
Public API calls send a secret key in the Authorization header:
Authorization: Bearer sk_live_…
Keys are minted in the dashboard (or through POST /v1/api-keys with a
session cookie). sk_live_ keys are for production traffic, sk_test_ keys
carry a lower rate limit. The dashboard’s session cookie is accepted on the
same endpoints. Routes marked session only (usage, history, key
management) refuse a bearer key: a key that could mint another key would
make revoking the first one meaningless.
Two more principals exist and are described as security schemes below:
the marketing site’s keyless demo (X-Demo-Origin) and RapidAPI’s proxy
(X-RapidAPI-Proxy-Secret + X-RapidAPI-User). Neither is something an
integrator sends by hand.
Targets and what each supports
| target | page | num | safe |
|---|---|---|---|
google_search |
1–5 | 1–20 | off, moderate, strict |
bing_search |
1 only | 1–20 | off, moderate, strict |
duckduckgo_search |
1 only | 1–10 | not supported |
yahoo_search |
1 only | 1–10 | off, moderate, strict |
brave_search |
1–5 | 1–20 | off, moderate, strict |
yandex_search |
1–5 | 1–10 | not supported |
Anything outside a target’s row answers 400 unsupported_parameter:
bing_search refuses page above 1; duckduckgo_search refuses page
above 1, num above 10 and any safe but off; yahoo_search refuses
page above 1 and num above 10; brave_search refuses page above 5;
yandex_search refuses num above 10 and any safe but off. A geo outside
the supported list answers 400 unsupported_geo with the list in details.
Credits
Every search costs one credit: one for GET /v1/query, one per row of
POST /v1/bulk. A cache hit costs the same as a fresh search. An upstream
failure (502 / 504) is still charged: the search was run and only the answer
is missing. A request refused with 400 or 402, and a failure on our side
(500), cost nothing.
Plans and quotas
Every account starts on the trial: 100 requests, granted once per email address, that never reset. The trial has no period at all — nothing rolls over, so there is no reset to wait for.
A paid plan’s quota is measured over its subscription’s billing cycle, which
renews monthly on the day the subscription started rather than on the 1st.
X-Quota-Reset and period.end carry the exact moment it rolls over; read
the reset off those rather than deriving it from a calendar. An account on a
paid plan with no subscription cycle behind it — a RapidAPI subscriber, a
plan set by hand — is measured over the calendar month in UTC instead,
resetting at 00:00:00Z on the 1st.
| plan | $ / month | requests | extra requests | concurrency |
|---|---|---|---|---|
| Trial | 0 | 100, once, for life | — | 1 concurrent request |
| Starter | 9 | 5,000 / month | credit packs at $1.50 per 1,000 | 2 concurrent requests |
| Growth | 49 | 75,000 / month | credit packs at $0.80 per 1,000 | 5 concurrent requests |
| Business | 99 | 200,000 / month | credit packs at $0.60 per 1,000 | 10 concurrent requests |
| Custom | contact us | quoted | quoted | 20 concurrent requests |
A plan costs the same bought direct as it does through RapidAPI. Plans bought direct are sold through Polar, our Merchant of Record: Polar takes the payment, handles tax and issues the invoice, and the subscription, payment methods and invoice history are managed in its customer portal.
Credit packs
Every plan is hard-limited — nothing is ever served on credit. An account that needs more requests inside the period buys a credit pack up front: 10,000, 50,000 or 100,000 credits, priced at its own plan’s rate, through a Polar one-time checkout. The credits land on the account when Polar reports the order paid.
Pack credits never expire and are not tied to the subscription: they survive a cancellation and are still spendable on an account that has gone back to the trial. They are spent only after the period’s quota is gone, so the quota is always used first.
Buying a pack needs an active subscription, because that is what prices it. Spending one never does.
/v1/query and /v1/bulk answer with X-Quota-Limit, X-Quota-Used,
X-Quota-Remaining and X-Credits-Balance on every response, plus
X-Quota-Reset on a plan whose quota rolls over. The trial’s never does, so
that header is absent on it. With both the quota and the balance spent, a
request answers 402 quota_exceeded, is not logged and is not charged; a
bulk request carrying more rows than remain between the two is refused
whole, before any row runs.
RapidAPI subscribers are metered and billed by the marketplace against the
tier they subscribed to, so the quota headers and 402 do not apply on that
path.
Rate limits
A plan’s concurrency is enforced as a request rate over a rolling 60-second
window — one concurrent request is 60 requests a minute, so the trial gets
60/min, Starter 120/min, Growth 300/min, Business 600/min and a custom plan
1200/min. Counted per credential, one hit per HTTP request however many
searches a bulk request carries. An API key (live or test) and an MCP access
token are held to the account plan’s rate; the dashboard session gets that
rate or 120/min, whichever is higher; the marketplace proxy 1200/min and the
keyless demo 5/min per client IP. /v1/query, /v1/bulk and /v1/me
answer with X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset, and a
refused request is 429 rate_limited with Retry-After.
Errors
Every error is a JSON envelope with the same three keys, plus issues
(field-level validation messages) or details (the supported geo codes)
where noted:
{ "error": "unsupported_geo", "message": "…", "request_id": "…", "details": ["us", "in", "…"] }
request_id is also sent as the X-Request-Id header on every response,
success or failure. Send a UUID as X-Request-Id on the request to have it
echoed; anything else is replaced. Any path not listed here answers
404 not_found in the same envelope.
Authentication
Section titled “Authentication”bearerAuth
Section titled “bearerAuth”A secret key from the dashboard: Authorization: Bearer sk_live_… or
Bearer sk_test_…. Both are held to the account plan’s rate — 60 a
minute on the trial, up to 1200 on a custom plan — and both spend the
same quota. Accepted on /v1/query, /v1/bulk, /v1/me and the MCP
endpoint POST /mcp only; a session-only route answers 401 to a key.
Security scheme type: http
sessionCookie
Section titled “sessionCookie”The dashboard’s session cookie (__Secure-better-auth.session_token when
served over HTTPS). Accepted everywhere a key is, and the only credential
the session-only routes take. On the search routes it gets the plan’s
per-minute limit or 120, whichever is higher.
Security scheme type: apiKey
Cookie parameter name: better-auth.session_token
demoOrigin
Section titled “demoOrigin”The marketing site’s keyless hero search. The header must equal the
deployment’s configured demo origin, and the request must carry no
Authorization header and no session cookie — a credential sent beside
it is refused rather than re-metered. The principal is the client IP,
limited to 5 requests a minute, with no account behind it. Accepted on
/v1/query and /v1/bulk.
Security scheme type: apiKey
Header parameter name: X-Demo-Origin
rapidApiProxy
Section titled “rapidApiProxy”Requests relayed by the RapidAPI marketplace. The proxy injects
X-RapidAPI-Proxy-Secret (compared in constant time against the
deployment’s secret) and X-RapidAPI-User (the marketplace account the
call is attributed to). Integrators never send these themselves. When
the marketplace secret is not configured, or the marketplace account
mapping has not landed, every request on this path answers
401 unauthorized — this branch currently answers 401.
Security scheme type: apiKey
Header parameter name: X-RapidAPI-Proxy-Secret