# SerpWiz — full documentation Source: https://serpwiz.com/docs --- URL: https://serpwiz.com/docs # SerpWiz API documentation SerpWiz is a real-time search API. Send a `GET` request, get the live results page back as clean JSON. It costs **$0.15 per 1,000 queries** on every plan ($0.11 with a year prepaid), and **only successful requests are charged**. ```bash curl "https://api.serpwiz.com/v1/google/search?q=best+crm+for+startups" \ -H "X-API-Key: $SERPWIZ_API_KEY" ``` ## Endpoints | Endpoint | Returns | |---|---| | [`GET /v1/google/search`](/docs/google-search) | Google web results: organic results, ads, top stories, knowledge panel, People Also Ask, related searches, pagination | | [`GET /v1/google/maps`](/docs/google-maps) | Google Maps places: name, address, rating, reviews count, phone, website, coordinates, opening hours and more | | [`GET /v1/account`](/docs/account) | Your query balance, free allowance, RPS limit and plan (free to call) | More engines are on the way. Each gets its own endpoint under `/v1/{engine}/{type}`, at the same flat rate. ## How it works - **Base URL:** `https://api.serpwiz.com/v1` - **Auth:** an API key in the `X-API-Key` header. [Get one free](/signup) — 1,000 queries a month, no card. - **One query = one successful request.** No credit multipliers. Failed requests, timeouts and `429`s cost nothing. - **Rate limits are per account**, in requests per second (RPS). Every $10/mo of plan adds 1 RPS, up to 100 RPS self-serve. See [Rate limits](/docs/rate-limits). - **Credits roll over** and are valid for 12 months from purchase. See [Credits & billing](/docs/credits). ## Next steps 1. [Quickstart](/docs/quickstart) — your first call in curl, Python, JavaScript or PHP. 2. [Google Search reference](/docs/google-search) — every parameter and response field. 3. [Errors](/docs/errors) — status codes and how to retry. Building with an LLM? Point it at [`/llms.txt`](https://serpwiz.com/llms.txt), the [OpenAPI spec](https://serpwiz.com/openapi.json), or any docs page with `.md` appended — see [AI agents & LLMs](/docs/ai-agents). --- URL: https://serpwiz.com/docs/quickstart # Quickstart You'll make a live Google search from your terminal in under a minute. ## 1. Get an API key [Create a free account](https://serpwiz.com/signup), verify your email, then create a key under **Dashboard → API keys**. Keys look like `sw_live_…` and are shown once — store it somewhere safe, such as an environment variable: ```bash export SERPWIZ_API_KEY="sw_live_your_key_here" ``` The free tier gives you 1,000 queries a month at 1 request per second. No card needed. ## 2. Make a request ### curl ```bash curl "https://api.serpwiz.com/v1/google/search?q=coffee+near+seattle&gl=us&hl=en" \ -H "X-API-Key: $SERPWIZ_API_KEY" ``` ### Python ```python import os, requests r = requests.get( "https://api.serpwiz.com/v1/google/search", params={"q": "coffee near seattle", "gl": "us", "hl": "en"}, headers={"X-API-Key": os.environ["SERPWIZ_API_KEY"]}, timeout=60, ) r.raise_for_status() for item in r.json().get("results", []): print(item["position"], item["title"], item["url"]) ``` ### JavaScript (Node 18+) ```js const url = new URL("https://api.serpwiz.com/v1/google/search"); url.search = new URLSearchParams({ q: "coffee near seattle", gl: "us", hl: "en" }); const res = await fetch(url, { headers: { "X-API-Key": process.env.SERPWIZ_API_KEY } }); if (!res.ok) throw new Error((await res.json()).error.message); const data = await res.json(); console.log(data.results?.map(r => r.title)); ``` ### PHP ```php 'coffee near seattle', 'gl' => 'us', 'hl' => 'en']); $ch = curl_init("https://api.serpwiz.com/v1/google/search?$query"); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 60, CURLOPT_HTTPHEADER => ['X-API-Key: ' . getenv('SERPWIZ_API_KEY')], ]); $data = json_decode(curl_exec($ch), true); foreach ($data['results'] ?? [] as $r) echo $r['position'], ' ', $r['title'], "\n"; ``` ## 3. Read the response A successful call returns `200` with the results as JSON, plus headers telling you what it cost: ```http HTTP/1.1 200 OK Content-Type: application/json X-Credits-Charged: 1 X-Credits-Remaining: 999 X-RateLimit-Limit: 1 X-Request-Id: 9f2c1a7b3e4d5f60 ``` ```json { "search_term": "coffee near seattle", "results": [ { "position": 1, "title": "The 38 Essential Seattle Coffee Shops", "url": "https://…", "description": "…" } ], "ads": [], "top_stories": [], "knowledge_panel": { "name": "", "…": "…" }, "related_keywords": { "spelling_suggestion": null, "keywords": [ { "position": 1, "keyword": "…" } ] }, "next_page": 2, "next_start": 10 } ``` Searches take a few seconds — set your HTTP client timeout to at least 60 seconds. ## Next - [Google Search parameters](/docs/google-search) — country, language, pagination, date filters. - [Google Maps](/docs/google-maps) — places, ratings and reviews. - [Errors](/docs/errors) and [Rate limits](/docs/rate-limits) — what to do with `4xx`/`5xx` and `429`. --- URL: https://serpwiz.com/docs/authentication # Authentication Every request needs an API key. Create and revoke keys in **[Dashboard → API keys](https://serpwiz.com/dashboard/keys)**. ## Sending the key Use the `X-API-Key` header (recommended): ```bash curl "https://api.serpwiz.com/v1/google/search?q=hello" -H "X-API-Key: sw_live_…" ``` These also work, in order of precedence after `X-API-Key`: | Method | Example | Notes | |---|---|---| | Bearer token | `Authorization: Bearer sw_live_…` | Handy for HTTP clients and agent frameworks that only support bearer auth. | | Query parameter | `?api_key=sw_live_…` | Convenient for quick tests and spreadsheets. Avoid it in production: URLs end up in logs and browser history. | ## Keys and limits - Keys are shown **once**, when you create them. We store only a hash. If you lose a key, revoke it and create a new one. - You can have up to 20 active keys — one per app or environment makes revoking painless. - **All keys on an account share one rate limit and one balance.** More keys don't add throughput; a bigger plan does. See [Rate limits](/docs/rate-limits). - You must verify your email address before keys work. ## Keep keys secret API keys can spend your balance. Don't ship them in front-end JavaScript or mobile apps — call SerpWiz from your server, and pass results to the client. If a key leaks, revoke it in the dashboard; it stops working within a few minutes everywhere. ## Errors | Status | `code` | Meaning | |---|---|---| | `401` | `unauthorized` | The key is missing, malformed, invalid or revoked. | | `403` | `email_unverified` | Verify your email address first. | | `403` | `account_suspended` | Contact [support@serpwiz.com](mailto:support@serpwiz.com). | --- URL: https://serpwiz.com/docs/api # API reference The SerpWiz API is a set of read-only HTTPS `GET` endpoints that return JSON. - **Base URL:** `https://api.serpwiz.com/v1` - **Auth:** `X-API-Key: sw_live_…` ([details](/docs/authentication)) - **Format:** JSON (UTF-8), gzip if you send `Accept-Encoding: gzip` - **Machine-readable spec:** [OpenAPI 3.1](https://serpwiz.com/openapi.json) ## Endpoints | Method | Path | Description | Cost | |---|---|---|---| | `GET` | [`/v1/google/search`](/docs/google-search) | Google web search results | 1 query | | `GET` | [`/v1/google/maps`](/docs/google-maps) | Google Maps places (up to 20 per request) | 1 query | | `GET` | [`/v1/account`](/docs/account) | Balance, free allowance, RPS limit, plan | free | Paths follow `/v1/{engine}/{type}`. New engines are added as new paths; existing paths don't change within `v1`. ## Conventions - **Parameters** go in the query string, URL-encoded. Names are `snake_case`. Unknown parameters are ignored. - **Charging:** you're charged only when the response is `200`. Every other status costs nothing. - **Timeouts:** searches usually return in a few seconds. Use a client timeout of at least 60 seconds. - **Optional fields:** result groups (ads, top stories, knowledge panel…) appear only when the results page has them. Treat every field except `results` as optional. ## Response headers | Header | Description | |---|---| | `X-Request-Id` | Unique ID for the request. Include it when you contact support. | | `X-Credits-Charged` | Queries deducted for this request: `1` on success, `0` otherwise. | | `X-Credits-Remaining` | Free allowance plus balance left after this request. | | `X-RateLimit-Limit` | Your account's requests-per-second limit. | | `Retry-After` | On `429` and `503`: seconds to wait before retrying. | ## Errors Errors use one shape across every endpoint: ```json { "error": { "status": 429, "code": "rate_limited", "message": "Rate limit exceeded for your plan (1 RPS). Retry after the Retry-After header, or upgrade for more RPS.", "request_id": "9f2c1a7b3e4d5f60", "docs": "https://serpwiz.com/docs/errors" } } ``` See [Errors](/docs/errors) for every `code`. ## CORS The API sends `Access-Control-Allow-Origin: *` so you can test from a browser, but **don't put API keys in client-side code** — call the API from your server. --- URL: https://serpwiz.com/docs/google-search # Google Search `GET https://api.serpwiz.com/v1/google/search` Returns one page of live Google web results — organic results, ads, top stories, the knowledge panel, People Also Ask and related searches — as JSON. **Costs 1 query** when successful; failed requests are free. ```bash curl "https://api.serpwiz.com/v1/google/search?q=best+crm+for+startups&gl=us&hl=en" \ -H "X-API-Key: $SERPWIZ_API_KEY" ``` ## Parameters | Parameter | Required | Description | |---|---|---| | `q` | **yes** | Search terms, up to 2,048 characters, at least one letter. Alias: `query`. Supports Google operators such as `site:`, `"exact phrase"`, `-exclude`. | | `gl` | no | Country to search from, as a 2-letter code: `us`, `ca`, `gb`, `de`… Sets which country's results you get. | | `hl` | no | Interface language: `en`, `es`, `fr`, `de`… Affects result snippets and labels. | | `page` | no | Results page, starting at `1` (default). 10 results per page; max `100`. | | `lr` | no | Only return pages in a language: `lang_en`, `lang_fr`… | | `cr` | no | Only return pages from a country: `countryUS`, `countryCA`… (case-sensitive) | | `tbs` | no | Time and verbatim filters — see below. | ### Time filters (`tbs`) | Value | Meaning | |---|---| | `qdr:h` | Past hour | | `qdr:d` | Past 24 hours | | `qdr:w` | Past week | | `qdr:m` | Past month | | `qdr:y` | Past year | | `cdr:1,cd_min:1/1/2026,cd_max:10/1/2026` | Custom date range (M/D/YYYY) | | `li:1` | Verbatim — match your exact words | Remember to URL-encode: `tbs=cdr%3A1%2Ccd_min%3A1%2F1%2F2026%2Ccd_max%3A10%2F1%2F2026`. ## Response ```json { "search_term": "best crm for startups", "results": [ { "position": 1, "url": "https://www.reddit.com/r/CRM/comments/…", "title": "What's the best CRM for an early stage, bootstrapped startup", "description": "Sep 9, 2025 · …", "date": "Sep 9, 2025" }, { "position": 2, "url": "https://www.salesforce.com/crm/startup-crm/", "title": "Best CRM For Startups: The All-In-One Guide - Salesforce", "description": "Find out how the right CRM for startups can help boost revenue…" } ], "ads": [], "top_stories": [], "knowledge_panel": { "name": "", "label": "", "description": { "text": "", "url": "", "site": "" }, "image": { "url": "", "width": "", "height": "", "page_url": "" }, "info": [] }, "related_keywords": { "spelling_suggestion": null, "keywords": [ { "position": 1, "keyword": "Best crm for startups free" }, { "position": 2, "keyword": "Best crm for startups reddit" } ] }, "next_page": 2, "next_start": 10 } ``` ### Fields | Field | Type | Description | |---|---|---| | `search_term` | string | The query as Google understood it. | | `results[]` | array | Organic results in page order. | | `results[].position` | integer | 1-based rank on this page. | | `results[].title` | string | Result title. | | `results[].url` | string | Destination URL. | | `results[].description` | string | Snippet text. | | `results[].date` | string | Publication date when Google shows one. Optional. | | `ads[]` | array | Paid results, when present. | | `top_stories[]` | array | News carousel items, when present. | | `knowledge_panel` | object | Entity panel. Fields are empty strings when the page has no panel. | | `related_keywords.keywords[]` | array | "Related searches" suggestions and "People Also Ask" questions (question text only). | | `related_keywords.spelling_suggestion` | string \| null | "Did you mean" correction. | | `next_page` | integer | Value to pass as `page` for the next page. Absent on the last page. | Groups that Google didn't show come back empty (`[]` or empty strings). Don't rely on any field except `results` being non-empty, and ignore fields you don't recognise — we add new ones without a version bump. ## Paginating ```python page = 1 while page and page <= 5: data = get("/v1/google/search", q="serp api", page=page) handle(data["results"]) page = data.get("next_page") ``` Each page is a separate query and costs 1. ## Notes - Results are live. Identical requests within about an hour may be served from a short-lived cache, which is still billed as a query. - Location targeting is by country (`gl`). City-level targeting isn't available yet. - See [Errors](/docs/errors) for failure handling. Validation errors return `400 invalid_request` and are free. --- URL: https://serpwiz.com/docs/google-maps # Google Maps `GET https://api.serpwiz.com/v1/google/maps` Search Google Maps and get places back as JSON: name, category, address, coordinates, rating, review count, phone, website, opening hours and more. **Costs 1 query** per successful request, for up to 20 places. ```bash curl "https://api.serpwiz.com/v1/google/maps?q=coffee+shops+in+seattle&num=10" \ -H "X-API-Key: $SERPWIZ_API_KEY" ``` ## Parameters Provide **one of** `q`, `place_id` or `url`. | Parameter | Description | |---|---| | `q` | What to search for, e.g. `dentists in Miami`. Alias: `query`. | | `place_id` | A Google Place ID, e.g. `ChIJN1t_tDeuEmsRUsoyG83frY4`, to fetch one place. | | `url` | A Google Maps URL (`https://www.google.com/maps/…`). | | `num` | Places to return, `1`–`20`. Default `10`. | | `gl` | Country code, e.g. `us`, `ca`. Default `us`. | | `hl` | Language code, e.g. `en`. | | `location` | Free-text area to search in, e.g. `Toronto, ON`. | | `lat`, `lng` | Search centre as decimal coordinates. | | `zoom` | Map zoom level, `1`–`21`. | | `radius_km` | Search radius around `lat`/`lng`, in kilometres (max 100). | ### Extra detail (slower) These fetch more data per place, so requests take longer. Turn on only what you need. | Parameter | Description | |---|---| | `place_details=1` | Full place details. | | `reviews=1` | Include reviews. Use `max_reviews` (`1`–`50`) to limit them. | | `images=1` | Include photos. Use `max_images` (`1`–`20`) to limit them. | | `popular_times=1` | Include "popular times" histograms where Google has them. | ## Response ```json { "results": [ { "position": 1, "title": "Storyville Coffee Pike Place", "categoryName": "Coffee shop", "categories": ["Coffee shop", "Bakery", "Cafe"], "address": "94 Pike St Top floor Suite 34, Seattle, WA 98101, United States", "city": "Seattle", "state": "Washington", "postalCode": "98101", "countryCode": "US", "location": { "lat": 47.6087916, "lng": -122.3400457 }, "rating": 4.6, "reviewsCount": 3231, "phone": "+1 206-780-5777", "website": "https://storyville.com/pages/pike-place-market", "placeId": "ChIJBR3G8LJqkFQRWD2Wzn0qG3c", "googleMapsUrl": "https://www.google.com/maps/place/?q=place_id:ChIJBR3G8LJqkFQRWD2Wzn0qG3c", "openingHours": { "Monday": "6:59 AM–5 PM", "…": "…" }, "openingHoursState": "Closed · Opens 6:59 AM Mon", "priceLevel": null, "permanentlyClosed": null } ] } ``` ### Common fields | Field | Description | |---|---| | `position` | Rank in the results. | | `title` | Place name. | | `categoryName`, `categories[]` | Primary and all Google categories. | | `address`, `street`, `city`, `state`, `postalCode`, `countryCode`, `neighborhood` | Address parts. | | `location.lat`, `location.lng` | Coordinates. | | `rating`, `reviewsCount` | Star rating and number of reviews. | | `phone`, `website`, `domain` | Contact details. | | `placeId`, `cid`, `googleMapsUrl` | Identifiers and a link to the place. | | `openingHours`, `openingHoursDetailed[]`, `openingHoursState` | Hours by day and current state. | | `priceLevel`, `temporarilyClosed`, `permanentlyClosed` | Status fields; `null` when unknown. | | `imageUrl`, `thumbnailUrl`, `images[]` | Photos. | | `amenities` | Grouped attributes (accessibility, service options…). | Places carry many more fields; fields with no data are `null`. Responses always wrap places in `results`. --- URL: https://serpwiz.com/docs/account # Account `GET https://api.serpwiz.com/v1/account` Returns your remaining query balance, free allowance, rate limit and plan. **Free to call** — it never uses credits. ```bash curl "https://api.serpwiz.com/v1/account" -H "X-API-Key: $SERPWIZ_API_KEY" ``` ```json { "account": { "email": "you@example.com", "rps_limit": 5 }, "credits": { "balance": 3998120, "free_remaining": 1000, "free_resets_at": "2026-11-19T02:41:00+00:00", "next_expiry": { "queries": 120000, "date": "2027-03-02" } }, "plan": { "monthly_usd": 50, "interval": "year", "rps": 5, "renews_at": "2027-10-19T02:41:00+00:00" } } ``` | Field | Description | |---|---| | `account.rps_limit` | Requests per second allowed across all your keys. | | `credits.balance` | Paid queries left. Used after the free allowance. | | `credits.free_remaining` | Free queries left this month. | | `credits.free_resets_at` | When the free allowance refills. Unused free queries don't roll over. | | `credits.next_expiry` | The next batch of queries to expire and when, or `null`. Purchased queries are valid for 12 months; the oldest are used first. | | `plan` | Your active plan, or `null` if you don't have one (1 RPS). `monthly_usd` is the plan size; `interval` is `month` or `year`. | --- URL: https://serpwiz.com/docs/errors # Errors **You are never charged for an error.** Only `200` responses use credits — every status below costs nothing, so retrying is safe. ## Format ```json { "error": { "status": 402, "code": "insufficient_credits", "message": "Your query balance is empty. Top up or choose a plan at https://serpwiz.com/dashboard/billing", "request_id": "9f2c1a7b3e4d5f60", "docs": "https://serpwiz.com/docs/errors" } } ``` Match on `code`, not on `message` — messages may be reworded. ## Codes | Status | `code` | What happened | What to do | |---|---|---|---| | `400` | `invalid_request` | A parameter is missing or invalid. The message names it. | Fix the request. Don't retry unchanged. | | `401` | `unauthorized` | API key missing, malformed, invalid or revoked. | Check the `X-API-Key` header. | | `402` | `insufficient_credits` | Free allowance and balance are both used up. | [Top up or upgrade](https://serpwiz.com/dashboard/billing). | | `403` | `email_unverified` | The account's email isn't verified yet. | Click the link in your verification email. | | `403` | `account_suspended` | The account is suspended. | Contact [support@serpwiz.com](mailto:support@serpwiz.com). | | `404` | `not_found` | Unknown endpoint. | Check the path against the [API reference](/docs/api). | | `405` | `method_not_allowed` | Not a `GET`. | Use `GET`. | | `429` | `rate_limited` | Over your requests-per-second limit, or the service is busy. | Wait `Retry-After` seconds, then retry. | | `500` | `internal_error` | Something broke on our side. | Retry with backoff. | | `502` | `upstream_error` | The search couldn't be completed. | Retry with backoff. | | `503` | `capacity` | Temporarily over capacity. | Wait `Retry-After` seconds, then retry. | | `504` | `upstream_timeout` | The search took too long. | Retry. | ## Retrying Retry `429`, `5xx` and network errors with exponential backoff and jitter, honouring `Retry-After` when present. Don't retry `400`–`404`. ```python import random, time, requests def search(params, key, attempts=5): for i in range(attempts): r = requests.get("https://api.serpwiz.com/v1/google/search", params=params, headers={"X-API-Key": key}, timeout=60) if r.status_code == 200: return r.json() if r.status_code in (429, 500, 502, 503, 504): wait = float(r.headers.get("Retry-After", 0)) or min(30, 2 ** i) time.sleep(wait + random.random()) continue r.raise_for_status() raise RuntimeError("gave up after retries") ``` Quote the `request_id` when you contact support. --- URL: https://serpwiz.com/docs/rate-limits # Rate limits SerpWiz limits **requests per second (RPS) per account**. Every $10/mo of plan buys 1 RPS, so throughput scales linearly with your plan: | Plan | RPS | |---|---| | Free | 1 | | $10/mo | 1 | | $50/mo | 5 | | $100/mo | 10 | | $250/mo | 25 | | $500/mo | 50 | | $1,000/mo | 100 | Monthly and annual plans get the same RPS. Need more than 100 RPS? [Talk to us](mailto:sales@serpwiz.com). ## How it's enforced - **Per account, not per key.** All your API keys share one limit. - **Token bucket.** You can burst up to your RPS in any one second, refilling continuously. - **Over the limit** you get `429 rate_limited` with a `Retry-After` header. It's free — retry after the wait. - Your RPS comes from your active plan plus any RPS add-ons. Your credit balance doesn't change it, and an account without an active plan runs at 1 RPS. ## Concurrency A search takes a few seconds, so to use your full RPS you need several requests in flight at once. Roughly: ```text concurrent requests ≈ RPS × average latency (seconds) ``` At 10 RPS and ~4 s per search, keep about 40 requests in flight. Watch for `429`s and back off — see [Errors](/docs/errors#retrying). ## Checking your limit Every response includes `X-RateLimit-Limit`, and [`GET /v1/account`](/docs/account) returns `rps_limit`. Usage, success rate and 429s are charted in your [dashboard](https://serpwiz.com/dashboard/usage). --- URL: https://serpwiz.com/docs/credits # Credits & billing One rate — **$0.15 per 1,000 queries** — on every plan. Prepay a year and it's **$0.1125**, 25% less. ## Your balance - Each account has **one query balance**. Plan payments, annual prepayments, add-ons and top-ups all add to it. - **Only successful requests are charged.** Errors, timeouts and `429`s cost nothing. - **Credits roll over** and each purchase is **valid for 12 months**. The oldest queries are used first. - The dashboard shows your balance and the next expiry ("X queries expire on "). ## Free allowance Every verified account gets **1,000 free queries a month**, used before your paid balance. It refills monthly and unused free queries don't roll over. No card is needed. ## Plans Plans set your throughput. Every $10/mo is 1 request per second and 66,667 queries. - **Monthly:** the month's queries are added each time you're billed. - **Annual:** the full year's queries are added upfront, at 25% off. - Self-serve plans go up to 100 RPS ($1,000/mo). Above that, [contact sales](mailto:sales@serpwiz.com). See [pricing](https://serpwiz.com/#pricing) for the full table. ## Top-ups Ran out before renewal? Buy more queries any time at $0.15/1K from the dashboard. Top-ups add to your balance (valid 12 months) but don't change your RPS. They're available while you have an active plan. ## Add-ons Need more RPS without changing plans? Add RPS in $10/mo steps, each with its monthly queries. Your account RPS is your plan plus add-ons, up to 100. ## Changing plans Upgrade, downgrade or cancel from the dashboard. Your balance always carries over. The dashboard shows exactly what each change costs before you confirm. Cards and invoices are managed in the billing portal. Refunds and price changes are covered in the [Terms](https://serpwiz.com/terms). --- URL: https://serpwiz.com/docs/openapi # OpenAPI spec The full SerpWiz API is described in an **OpenAPI 3.1** document: - **JSON:** [`https://serpwiz.com/openapi.json`](https://serpwiz.com/openapi.json) It covers every endpoint, parameter, response schema, error code and the `X-API-Key` security scheme. ## Uses - **Generate a client** in any language: ```bash npx @openapitools/openapi-generator-cli generate \ -i https://serpwiz.com/openapi.json -g python -o serpwiz-client ``` - **Import into Postman, Insomnia or Bruno** — paste the URL as a new import. - **Give an AI agent a tool definition.** Most agent frameworks can load OpenAPI directly as tools (for example, OpenAPI toolkits in LangChain, Semantic Kernel or custom GPT actions). See [AI agents & LLMs](/docs/ai-agents). The spec is generated from the same configuration that serves the API, so it always matches production. --- URL: https://serpwiz.com/docs/ai-agents # AI agents & LLMs SerpWiz is built to be called by software — including LLM agents that need fresh search results. ## What's available | Resource | URL | Use | |---|---|---| | `llms.txt` | [`https://serpwiz.com/llms.txt`](https://serpwiz.com/llms.txt) | Short index of the docs for LLMs. | | `llms-full.txt` | [`https://serpwiz.com/llms-full.txt`](https://serpwiz.com/llms-full.txt) | Every docs page in one Markdown file. | | Markdown pages | Append `.md` to any docs URL, e.g. [`/docs/google-search.md`](/docs/google-search.md) | Clean text without page chrome. | | OpenAPI 3.1 | [`https://serpwiz.com/openapi.json`](https://serpwiz.com/openapi.json) | Tool and client generation. | | MCP server | [`https://api.serpwiz.com/mcp`](/docs/mcp) | Hosted tools for Claude, ChatGPT, Cursor, VS Code and other MCP clients. Users connect by signing in (OAuth 2.1); no key to copy. | ## Function-calling schema Drop this into any tool-use / function-calling API, then have your code call SerpWiz when the model asks: ```json { "name": "google_search", "description": "Search Google in real time and return the results page as JSON (organic results, ads, top stories, knowledge panel, People Also Ask, related searches). Use for current events, facts that change, or anything after your training data.", "input_schema": { "type": "object", "properties": { "q": { "type": "string", "description": "Search query. Supports Google operators like site: and quotes." }, "gl": { "type": "string", "description": "2-letter country code, e.g. us" }, "hl": { "type": "string", "description": "Language code, e.g. en" }, "page": { "type": "integer", "minimum": 1, "description": "Results page, 10 per page" }, "tbs": { "type": "string", "description": "Time filter: qdr:h, qdr:d, qdr:w, qdr:m or qdr:y" } }, "required": ["q"] } } ``` The tool handler is one HTTP call: ```python import os, requests def google_search(**args): r = requests.get("https://api.serpwiz.com/v1/google/search", params=args, headers={"X-API-Key": os.environ["SERPWIZ_API_KEY"]}, timeout=60) if r.status_code != 200: return {"error": r.json()["error"]["message"]} # let the model see what went wrong data = r.json() # Trim to what the model needs: fewer tokens, same answer quality. return { "results": [{k: x.get(k) for k in ("position", "title", "url", "description")} for x in data.get("results", [])], "related": [k["keyword"] for k in data.get("related_keywords", {}).get("keywords", [])], } ``` ## Tips for agents - **Trim responses** before passing them to the model — titles, URLs and snippets are usually enough. - **Failed calls are free**, so let the agent retry `429`/`5xx` after `Retry-After`. - **Concurrency is capped by RPS.** Parallel tool calls past your limit get `429`; queue them or upgrade. - **Keep the key server-side.** Never put an API key in a prompt or in client code. --- URL: https://serpwiz.com/docs/mcp # MCP server SerpWiz runs a hosted [Model Context Protocol](https://modelcontextprotocol.io) server, so Claude, Cursor, VS Code and other MCP clients can search Google and Google Maps directly, without any glue code. | | | |---|---| | **URL** | `https://api.serpwiz.com/mcp` | | **Transport** | Streamable HTTP (stateless) | | **Auth** | Sign in with OAuth (clients that support it), or your API key in the `X-API-Key` header | | **Cost** | Same as the API: 1 query per successful `google_search` or `google_maps` call. Failed calls are free. | Most clients just need the URL: they open a SerpWiz sign-in page, you approve, and they connect. For clients without sign-in, get a key from your [dashboard](/dashboard/keys). Tool calls share your account's [rate limit](/docs/rate-limits) and show up in your request logs like any other request. **One-click install:** [Add to Claude](https://claude.ai/customize/connectors?modal=add-custom-connector&connectorName=SerpWiz&connectorUrl=https%3A%2F%2Fapi.serpwiz.com%2Fmcp) · [Add to Cursor](cursor://anysphere.cursor-deeplink/mcp/install?name=serpwiz&config=eyJ1cmwiOiJodHRwczovL2FwaS5zZXJwd2l6LmNvbS9tY3AifQ%3D%3D) · [Add to VS Code](vscode:mcp/install?%7B%22name%22%3A%22serpwiz%22%2C%22type%22%3A%22http%22%2C%22url%22%3A%22https%3A%2F%2Fapi.serpwiz.com%2Fmcp%22%7D) ## Tools | Tool | What it does | Cost | |---|---|---| | `google_search` | Live Google results: organic results, ads, top stories, knowledge panel, People Also Ask, related searches. Arguments: `q` (required), `gl`, `hl`, `page`, `tbs`. | 1 query | | `google_maps` | Places from Google Maps: name, address, rating, reviews, phone, website, hours, coordinates. Arguments: `q`, `place_id` or `url`, plus `num` (max 20), `gl`, `hl`, `location`, `lat`, `lng`, `radius_km`, `place_details`, `reviews`, `max_reviews`, `popular_times`. | 1 query | | `get_account` | Remaining balance, free allowance, next expiry, plan and rate limit. | Free | Arguments behave exactly like the REST parameters. See [Google Search](/docs/google-search) and [Google Maps](/docs/google-maps). ## Claude Code ```bash claude mcp add --transport http serpwiz https://api.serpwiz.com/mcp ``` Then run `/mcp` in Claude Code and choose **serpwiz** to sign in. To use an API key instead, add `--header "X-API-Key: sw_live_YOUR_KEY"` to the command. ## Claude and Claude Desktop (custom connector) 1. Open [this link](https://claude.ai/customize/connectors?modal=add-custom-connector&connectorName=SerpWiz&connectorUrl=https%3A%2F%2Fapi.serpwiz.com%2Fmcp): it opens **Add custom connector** with SerpWiz filled in. Or go to **Customize → Connectors**, choose **Add custom connector** and paste `https://api.serpwiz.com/mcp`. 2. Click **Add**. 3. Click **Connect**, sign in to SerpWiz (or create a free account) and approve. ## ChatGPT Add a custom connector (in developer mode) with the URL `https://api.serpwiz.com/mcp` and OAuth authentication. ChatGPT registers itself and sends you to SerpWiz to sign in and approve. ## Cursor [Install in Cursor](cursor://anysphere.cursor-deeplink/mcp/install?name=serpwiz&config=eyJ1cmwiOiJodHRwczovL2FwaS5zZXJwd2l6LmNvbS9tY3AifQ%3D%3D) with one click, or add to `~/.cursor/mcp.json` (global) or `.cursor/mcp.json` (one project). With only the `url`, Cursor asks you to sign in; with the header, it uses your key: ```json { "mcpServers": { "serpwiz": { "url": "https://api.serpwiz.com/mcp", "headers": { "X-API-Key": "sw_live_YOUR_KEY" } } } } ``` ## VS Code (GitHub Copilot) [Install in VS Code](vscode:mcp/install?%7B%22name%22%3A%22serpwiz%22%2C%22type%22%3A%22http%22%2C%22url%22%3A%22https%3A%2F%2Fapi.serpwiz.com%2Fmcp%22%7D) with one click. Or, with just the URL, VS Code asks you to sign in to SerpWiz: ```json { "servers": { "serpwiz": { "type": "http", "url": "https://api.serpwiz.com/mcp" } } } ``` Or use an API key. Add this to `.vscode/mcp.json`; VS Code asks for the key once and stores it securely: ```json { "inputs": [ { "type": "promptString", "id": "serpwiz-key", "description": "SerpWiz API key", "password": true } ], "servers": { "serpwiz": { "type": "http", "url": "https://api.serpwiz.com/mcp", "headers": { "X-API-Key": "${input:serpwiz-key}" } } } } ``` ## Other clients Any client that supports remote MCP servers over Streamable HTTP works. Point it at `https://api.serpwiz.com/mcp`. Clients that support MCP authorization sign in with OAuth; for the rest, send your key as an `X-API-Key` or `Authorization: Bearer` header. To check the server by hand: ```bash curl https://api.serpwiz.com/mcp \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -H "X-API-Key: $SERPWIZ_API_KEY" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"google_search","arguments":{"q":"best crm for startups"}}}' ``` ## Connected apps Apps you connect by signing in are listed with your keys under [API keys](/dashboard/keys), marked **Connected app**. **Disconnect** stops an app immediately; connecting it again takes one click. An account can have 20 keys and connected apps in total. ## For client developers SerpWiz follows the [MCP authorization spec](https://modelcontextprotocol.io/specification/latest/basic/authorization): OAuth 2.1 with PKCE. | | | |---|---| | Protected resource metadata | `https://api.serpwiz.com/.well-known/oauth-protected-resource/mcp` | | Authorization server metadata | `https://serpwiz.com/.well-known/oauth-authorization-server` | | Client registration | Dynamic client registration at `https://serpwiz.com/oauth/register`, or a client ID metadata document (an `https` URL as `client_id`) | | Grants | `authorization_code` with PKCE (`S256`, required) and `refresh_token` | | Scope | `api` | | Tokens | Access tokens last 1 hour. Refresh tokens rotate on each use and expire after 90 days without use. | | Server card | `https://api.serpwiz.com/.well-known/mcp/server-card.json` (also at `/.well-known/mcp.json` on both hosts): server info, auth and the tool list, without connecting | A request without credentials gets `401` with a `WWW-Authenticate` header pointing to the protected resource metadata. Access tokens also work on the [REST API](/docs/api) as `Authorization: Bearer …`. ## Errors - **Missing, invalid or expired credentials:** HTTP `401` with a `WWW-Authenticate` header, and a JSON-RPC error with code `-32001`. - **Everything else** (a bad argument, a rate limit, an empty balance, a search that failed) comes back as a tool result with `isError: true`. The [error object](/docs/errors) inside tells the model what to fix or how long to wait. You're never charged for errors. --- URL: https://serpwiz.com/docs/migrate # Migration guides Switching to SerpWiz usually takes a few minutes. Every API returns Google results as JSON, so most of the work is changing the URL, the auth header and a few field names. | From | Guide | Main changes | |---|---|---| | SerpApi | [Migrate from SerpApi](/docs/migrate-serpapi) | `api_key` param → `X-API-Key` header · `start` offset → `page` · `organic_results[].link` → `results[].url` | | Serper | [Migrate from Serper](/docs/migrate-serper) | `POST` + `X-API-KEY` → `GET` + `X-API-Key` · `organic[]` → `results[]` · `places` → `/v1/google/maps` | ## What stays the same - Google's own parameters: `q`, `gl`, `hl`, `tbs`, plus `lr` and `cr` for the Search endpoint. - JSON responses with organic results, ads, the knowledge panel and related searches. ## What's different about SerpWiz - **One price for every query:** $0.15 per 1,000 ($$0.1125 on annual plans). A search is always 1 query, never several credits. - **Failed requests are free.** Errors, timeouts and `429` responses are never charged. The `X-Credits-Charged` header on every response shows exactly what was billed. - **Unused queries roll over.** Purchased queries stay valid for 12 months. - **Rate limits are per account in requests per second.** Your plan sets the limit. See [Rate limits](/docs/rate-limits). You can try any request in the [Playground](/playground) before changing code, and new accounts get 1,000 free queries a month. --- URL: https://serpwiz.com/docs/migrate-serpapi # Migrate from SerpApi This guide maps SerpApi's Google Search and Google Maps engines to SerpWiz. For pricing, see [SerpApi vs SerpWiz](/vs/serpapi). ## Requests | | SerpApi | SerpWiz | |---|---|---| | Search endpoint | `GET https://serpapi.com/search?engine=google` | `GET https://api.serpwiz.com/v1/google/search` | | Maps endpoint | `GET https://serpapi.com/search?engine=google_maps&type=search` | `GET https://api.serpwiz.com/v1/google/maps` | | API key | `api_key` query parameter | `X-API-Key` header (an `api_key` query parameter also works, but the header keeps keys out of logs) | ### Search parameters | SerpApi | SerpWiz | Notes | |---|---|---| | `q` | `q` | Same. Google operators such as `site:` work. | | `gl` | `gl` | Same two-letter country code. | | `hl` | `hl` | Same language code. | | `start` | `page` | SerpApi uses a result offset (`0`, `10`, `20`…). SerpWiz uses page numbers (`1`, `2`, `3`…), so `page = start / 10 + 1`. | | `tbs` | `tbs` | Supported: `qdr:h/d/w/m/y`, `li:1` and custom date ranges (`cdr:1,cd_min:…,cd_max:…`). | | `lr` | `lr` | One value, e.g. `lang_en`. | | `cr` | `cr` | One value, e.g. `countryUS`. | | `location` | — | Not available on Search yet. Use `gl` for the country. | | `device`, `safe`, `num` | — | Not available. Results are desktop, 10 per page. | | `no_cache` | — | Results may come from a cache up to about an hour old. | | `output` | — | Always JSON. | ### Maps parameters | SerpApi (`google_maps`) | SerpWiz (`/v1/google/maps`) | Notes | |---|---|---| | `q` | `q` | Same. | | `ll` (`@lat,lng,zoomz`) | `lat`, `lng`, `zoom` | Split into three parameters. `radius_km` is also available. | | `place_id` | `place_id` | Look up one place. | | `start` (steps of 20) | `num` (1–20) | Up to 20 places per request. | | `hl`, `gl` | `hl`, `gl` | Same. | ## Responses | SerpApi | SerpWiz | |---|---| | `organic_results[]` | `results[]` | | `organic_results[].position` | `results[].position` | | `organic_results[].title` | `results[].title` | | `organic_results[].link` | `results[].url` | | `organic_results[].snippet` | `results[].description` | | `related_searches[]` | `related_keywords.keywords[]` (`keyword`) | | `related_questions[]` (People Also Ask) | `related_keywords.keywords[]`, as question text only | | `knowledge_graph` | `knowledge_panel` | | `pagination` / `serpapi_pagination` | `next_page`: pass it as `page` | | `local_results[]` (Maps) | `results[]` | | `local_results[].gps_coordinates` | `results[].location` (`lat`, `lng`) | | `local_results[].reviews` | `results[].reviewsCount` | | `local_results[].type` | `results[].categoryName` | See [Google Search](/docs/google-search) and [Google Maps](/docs/google-maps) for every field. ## Code: before and after ```python # Before: SerpApi import requests r = requests.get("https://serpapi.com/search", params={ "engine": "google", "q": "best crm for startups", "gl": "us", "start": 10, "api_key": SERPAPI_KEY, }) for item in r.json().get("organic_results", []): print(item["position"], item["title"], item["link"]) ``` ```python # After: SerpWiz import requests r = requests.get("https://api.serpwiz.com/v1/google/search", params={ "q": "best crm for startups", "gl": "us", "page": 2, }, headers={"X-API-Key": SERPWIZ_KEY}, timeout=60) r.raise_for_status() for item in r.json()["results"]: print(item["position"], item["title"], item["url"]) ``` ## Errors - **SerpApi** returns `{"error": "…"}`. - **SerpWiz** returns `{"error": {"status", "code", "message", "request_id"}}` with a matching HTTP status. Retry `429` and `503` after the `Retry-After` header. See [Errors](/docs/errors). - **Charging:** SerpWiz never charges for an error. --- URL: https://serpwiz.com/docs/migrate-serper # Migrate from Serper This guide maps Serper's Google Search and Places endpoints to SerpWiz. For pricing, see [Serper vs SerpWiz](/vs/serper). ## Requests | | Serper | SerpWiz | |---|---|---| | Search | `POST https://google.serper.dev/search` | `GET https://api.serpwiz.com/v1/google/search` | | Places / Maps | `POST https://google.serper.dev/places` | `GET https://api.serpwiz.com/v1/google/maps` | | API key | `X-API-KEY` header | `X-API-Key` header (header names aren't case-sensitive, so the same header works) | | Parameters | JSON body or query string | Query string | ### Parameters | Serper | SerpWiz | Notes | |---|---|---| | `q` | `q` | Same. | | `gl` | `gl` | Same two-letter country code. | | `hl` | `hl` | Same language code. | | `page` | `page` | Same: page numbers starting at 1. | | `tbs` | `tbs` | Supported: `qdr:h/d/w/m/y`, `li:1` and custom date ranges. | | `num` | — | Search returns 10 results per page. For Maps, use `num` (1–20). | | `location` | `location` (Maps only) | On Search, use `gl` for the country. | ## Responses | Serper | SerpWiz | |---|---| | `organic[]` | `results[]` | | `organic[].position` | `results[].position` | | `organic[].title` | `results[].title` | | `organic[].link` | `results[].url` | | `organic[].snippet` | `results[].description` | | `organic[].date` | `results[].date` | | `peopleAlsoAsk[]` | `related_keywords.keywords[]`, as question text only | | `relatedSearches[]` | `related_keywords.keywords[]` (`keyword`) | | `knowledgeGraph` | `knowledge_panel` | | `places[]` | `results[]` from `/v1/google/maps` | See [Google Search](/docs/google-search) and [Google Maps](/docs/google-maps) for every field. ## Code: before and after ```javascript // Before: Serper const res = await fetch("https://google.serper.dev/search", { method: "POST", headers: { "X-API-KEY": process.env.SERPER_API_KEY, "Content-Type": "application/json" }, body: JSON.stringify({ q: "best crm for startups", gl: "us", page: 2 }), }); const { organic } = await res.json(); organic.forEach(r => console.log(r.position, r.title, r.link)); ``` ```javascript // After: SerpWiz const params = new URLSearchParams({ q: "best crm for startups", gl: "us", page: 2 }); const res = await fetch(`https://api.serpwiz.com/v1/google/search?${params}`, { headers: { "X-API-Key": process.env.SERPWIZ_API_KEY }, }); if (!res.ok) throw new Error((await res.json()).error.message); const { results } = await res.json(); results.forEach(r => console.log(r.position, r.title, r.url)); ``` ## Errors - **SerpWiz errors** come back as `{"error": {"status", "code", "message", "request_id"}}` with a matching HTTP status. - **Retries:** retry `429` and `503` after the `Retry-After` header. See [Errors](/docs/errors). - **Charging:** failed requests are never charged. The `X-Credits-Charged` header on every response shows what was billed. --- # SerpWiz — Cheapest real-time search data Live Google results as clean JSON — organic results, ads, top stories, knowledge panel, People Also Ask and related searches — in one request. Flat $0.15/1K on every plan, $0.11 with a year prepaid. Only successful requests are charged. ## Pricing Every $10/mo buys 1 request per second and 66,667 queries. The rate is the same on every plan. Prepay a year and pay 25% less per query. | Throughput | Monthly price | Queries / mo | Annual price | Queries / yr (added upfront) | Effective $/1K (monthly · annual) | |---|---|---|---|---|---| | 1 RPS (Free) | $0 | 1,000 | — | — | — | | 1 RPS | $10 | 66,667 | $90 | 800,000 | $0.15 · $0.1125 | | 5 RPS | $50 | 333,333 | $450 | 4,000,000 | $0.15 · $0.1125 | | 10 RPS | $100 | 666,667 | $900 | 8,000,000 | $0.15 · $0.1125 | | 25 RPS | $250 | 1,666,667 | $2,250 | 20,000,000 | $0.15 · $0.1125 | | 50 RPS | $500 | 3,333,333 | $4,500 | 40,000,000 | $0.15 · $0.1125 | | 100 RPS | $1,000 | 6,666,667 | $9,000 | 80,000,000 | $0.15 · $0.1125 | - Only successful requests are charged - Credits roll over and are valid for 12 months from purchase - 1,000 free queries/mo, no card required - RPS scales with your plan - Cancel anytime Out of credits mid-term? Top up any time at $0.15/1K. Need more than 100 RPS or an SLA? Email sales@serpwiz.com. ## Entry price per 1,000 queries | Provider | Entry plan | $ / 1K | |---|---|---| | **SerpWiz** | from $10/mo | $0.15 ($0.1125 annual) | | [Serper](https://serpwiz.com/vs/serper) | $50 pack · 50,000 credits | $1.00 | | [Scrapingdog](https://serpwiz.com/vs/scrapingdog) | $40/mo · 40,000 searches | $1.00 | | [Bright Data](https://serpwiz.com/vs/bright-data) | no minimum | $1.50 | | [Zenserp](https://serpwiz.com/vs/zenserp) | $49.99/mo · 25,000 searches | $2.00 | | [DataForSEO](https://serpwiz.com/vs/dataforseo) | $50 minimum deposit | $2.00 | | [SearchApi](https://serpwiz.com/vs/searchapi) | $40/mo · 10,000 searches | $4.00 | | [ScraperAPI](https://serpwiz.com/vs/scraperapi) | $49/mo · 4,000 searches | $12.25 | | [SerpApi](https://serpwiz.com/vs/serpapi) | $25/mo · 1,000 searches | $25.00 | Prices checked 15 Oct 2026 from each provider's public pricing page. ## FAQ ### What counts as a query? One successful request to an endpoint such as /v1/google/search — any page, locale or device. The full results page comes back in that one query. ### What if a request fails? It's free. Only successful responses are deducted from your balance. You never pay for our downtime. ### Do credits expire? Queries you buy are valid for 12 months from purchase, and the oldest are used first. Unused queries roll over; nothing resets at month end. ### How do rate limits work? Every $10/mo of plan is 1 request per second, shared across all keys on your account. Self-serve up to 100 RPS; above that, talk to us. Over the limit you get a 429 with Retry-After. ### Can I lock in today's price? Yes, and it stays locked. Your plan keeps renewing at the price you signed up at for as long as it stays active, even if list prices go up for new customers later. A change to a different plan is priced at that day's list rate, so start on the largest plan you expect to need. Annual plans also add the full year's queries upfront. ### Can I change plans later? Upgrade any time from the dashboard — your remaining balance carries over. Downgrades apply at renewal. Cancel whenever you like. ### Which search engines are supported? Google Search and Google Maps today, each with its own endpoint. More engines are on the way, all at the same flat rate. ### Can AI agents use SerpWiz? Yes. Every endpoint is a plain HTTPS GET that returns JSON, described in an OpenAPI spec, with Markdown docs at /llms.txt.