Introduction

Plainserp is one endpoint that returns Google’s organic results as JSON. You send a query and get back titles, links and snippets. It’s built for AI agents and scripts that need search results and nothing around them.

The base address is https://plainserp.com. Every request is a GET over HTTPS, and every response is JSON.

Quickstart

  1. Create a key on the API keys page.
  2. Save it as PLAINSERP_KEY in your environment.
  3. Make a request.
Request
curl "https://plainserp.com/v1/search?q=postgres+connection+pooling&num=3" \
  -H "Authorization: Bearer $PLAINSERP_KEY"
Response
{
  "query": "postgres connection pooling",
  "results": [
    {
      "position": 1,
      "title": "PgBouncer - lightweight connection pooler for PostgreSQL",
      "url": "https://www.pgbouncer.org/",
      "snippet": "PgBouncer keeps a pool of server connections and hands them to clients…"
    },
    {
      "position": 2,
      "title": "PostgreSQL: Documentation: Connections and Authentication",
      "url": "https://www.postgresql.org/docs/current/runtime-config-connection.html",
      "snippet": "max_connections determines the maximum number of concurrent connections…"
    },
    {
      "position": 3,
      "title": "pgpool Wiki",
      "url": "https://www.pgpool.net/",
      "snippet": "Pgpool-II is a middleware that works between PostgreSQL servers and clients…"
    }
  ],
  "cost_usd": 0.0003
}

Authentication

Send your key as a Bearer token in the Authorization header. Keys start with ps_live_.

Header
Authorization: Bearer $PLAINSERP_KEY

Keep keys on your server. Anyone who has a key can spend your balance, so revoke a key on the dashboard if it leaks.

Response

A successful call returns status 200 with this shape.

FieldTypeDescription
querystringThe query you sent.
resultsarrayThe organic results, in Google's order.
results[].positionintegerRank across all pages, starting at 1.
results[].titlestringThe page title.
results[].urlstringThe page address.
results[].snippetstringThe text Google shows under the title.
results[].thumbnailstringAn image address. Only present when Google has one.
cost_usdnumberWhat the call cost, in US dollars. One search for each page returned.

Pagination

Google returns results in pages of up to 20, and goes 6 pages deep, which is the first 120 results of a query. Set pages to fetch several pages in one call. They come back as one list, in order.

Three pages in one call
# Pages 1 to 3: results 1 to 60, charged as three searches
curl "https://plainserp.com/v1/search?q=postgres+connection+pooling&num=20&pages=3" \
  -H "Authorization: Bearer $PLAINSERP_KEY"

Each page is charged as one search, so the call above costs $0.0009. If a page fails it isn’t charged, and you get the pages that worked. To fetch one page from deeper in the results, set page instead, for example page=4.

Errors

Errors use standard HTTP status codes and a JSON body with a code you can match on. You are never charged for a request that returns an error.

StatusCodeMeaning
400invalid_requestA parameter is missing or out of range.
401invalid_api_keyThe key is missing, wrong or revoked.
402insufficient_balanceYour balance is too low. Top up to continue.
429rate_limitedYou passed your per-minute limit. Wait for Retry-After, then retry.
502upstream_errorGoogle didn't return results. Retry the request.
Error body
{
  "error": {
    "code": "insufficient_balance",
    "message": "Your balance is too low. Top up to continue."
  }
}

For 429 and 502, wait a second or two and try again. Doubling the wait after each failed attempt works well.

Rate limits

Each account can make 300 searches a minute by default. The count resets at the start of every clock minute, and a call that fetches several pages counts once per page. Your limit and how much of it you’re using are on the dashboard.

Every response says where you stand. Past the limit you get a 429 with a Retry-After header giving the seconds until the next minute. Requests refused this way are not charged.

Response headers
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 287
Retry-After: 23

Need more? Message @vvz25 on Telegram and say roughly what you need.

Billing

One successful search costs $0.0003, whatever num is. A call that fetches several pages is one search per page. That is $0.30 for a thousand searches. A new account starts with $0.30, which covers your first 1,000 searches.

You add money in advance from $6, and it doesn’t expire. Every response includes cost_usd, and your balance and daily usage are on the dashboard.

Use with agents

Most agent frameworks take a tool definition and a function to run when the model calls it. This definition works as it is with any model that supports tool use.

Tool definition
{
  "name": "web_search",
  "description": "Search Google. Returns titles, URLs and snippets.",
  "input_schema": {
    "type": "object",
    "properties": {
      "q": { "type": "string", "description": "The search query" },
      "num": { "type": "integer", "description": "Results to return, 1 to 20" }
    },
    "required": ["q"]
  }
}
Handler, in Python
import os, requests

def web_search(q: str, num: int = 10) -> list[dict]:
    r = requests.get(
        "https://plainserp.com/v1/search",
        params={"q": q, "num": num},
        headers={"Authorization": f"Bearer {os.environ['PLAINSERP_KEY']}"},
        timeout=15,
    )
    r.raise_for_status()
    return r.json()["results"]

Asking for 5 to 10 results is usually enough for a model to pick what to read, and it keeps the tool result short.

MCP server

To give an AI client search without writing any code, connect it to the Plainserp MCP server. It offers one tool, web_search, and uses your API key and balance like any other call.

SettingValue
URLhttps://plainserp.com/mcp
TransportStreamable HTTP
HeaderAuthorization: Bearer YOUR_KEY
Claude Code
claude mcp add --transport http plainserp https://plainserp.com/mcp \
  --header "Authorization: Bearer $PLAINSERP_KEY"
Clients that take a JSON config
{
  "mcpServers": {
    "plainserp": {
      "type": "http",
      "url": "https://plainserp.com/mcp",
      "headers": { "Authorization": "Bearer YOUR_KEY" }
    }
  }
}

The exact file and field names vary by client, so check your client’s own instructions for adding a remote server with a header.

Agent skill

A skill is a short instruction file that teaches a coding agent how to use something. The Plainserp skill covers the endpoint, parameters, errors, billing and ready-made code, so the agent can add search to your project correctly the first time.

Open the skill file, or install it for Claude Code:

Install
mkdir -p ~/.claude/skills/plainserp-search
curl -o ~/.claude/skills/plainserp-search/SKILL.md \
  https://plainserp.com/skill/plainserp-search/SKILL.md

Then ask your agent to “add web search with Plainserp”. For other agents, put the file wherever that agent reads its instructions from.

What it doesn't do

  • It returns organic results only. AI Overviews, People also ask, knowledge panels, ads and image or video packs are left out.
  • It doesn’t fetch or read the pages it links to.
  • It reaches the first 120 results of a query and no further.
  • Plainserp is an independent service and isn’t affiliated with Google. A change on Google’s side can cause a short outage, and failed requests are never charged.

Support

Questions, a payment that didn’t show up, or a higher rate limit: message @vvz25 on Telegram. Include the email on your account.