{
  "openapi": "3.0.3",
  "info": {
    "title": "ProxyScrape SERP API",
    "description": "SERP API — query Google search results as structured JSON. Authenticate with HTTP Basic Auth using a SERP API sub-user's username and password.",
    "version": "1.0.0"
  },
  "servers": [
    {
      "url": "https://serp.api.proxyscrape.com",
      "description": "ProxyScrape SERP API"
    }
  ],
  "tags": [
    {
      "name": "SERP API",
      "description": "Run Google searches and receive parsed results as JSON."
    }
  ],
  "security": [
    {
      "basicAuth": []
    }
  ],
  "paths": {
    "/": {
      "get": {
        "tags": [
          "SERP API"
        ],
        "summary": "Search",
        "description": "Run a Google search and receive parsed results as JSON. Authenticate with HTTP Basic Auth using a SERP API sub-user's `username` and `password` (create and manage sub-users in the dashboard). Every answer has a JSON body. Errors use the HTTP status code (4xx/5xx) and an `{\"Error\": {\"Status\", \"Message\", \"Code\"}}` body whose `Code` equals the status.",
        "operationId": "search",
        "security": [
          {
            "basicAuth": []
          }
        ],
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "description": "The search query. URL-encode it.",
            "schema": {
              "type": "string"
            },
            "example": "proxyscrape"
          },
          {
            "name": "gl",
            "in": "query",
            "required": false,
            "description": "Two-letter country code for the search location (Google `gl`), e.g. `us`, `de`, `fr`.",
            "schema": {
              "type": "string",
              "default": "us"
            },
            "example": "us"
          },
          {
            "name": "hl",
            "in": "query",
            "required": false,
            "description": "Two-letter interface language code (Google `hl`), e.g. `en`, `es`.",
            "schema": {
              "type": "string",
              "default": "en"
            },
            "example": "en"
          },
          {
            "name": "start",
            "in": "query",
            "required": false,
            "description": "Result offset for pagination. `0` is the first page, `10` the second, and so on.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            },
            "example": 0
          },
          {
            "name": "rawhtml",
            "in": "query",
            "required": false,
            "description": "Set to `1` to also return the raw HTML of every Google page the answer was read from, in `pages`. `0` omits it.",
            "schema": {
              "type": "integer",
              "enum": [
                0,
                1
              ],
              "default": 0
            },
            "example": 0
          }
        ],
        "responses": {
          "200": {
            "description": "An answer: parsed search results, organic results under `results[0].Organic`. A search Google finds nothing for is also an answer (HTTP 200) with an empty `results[0].Organic`, and is not billed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "query": {
                      "type": "string",
                      "description": "The query that was executed."
                    },
                    "url": {
                      "type": "string",
                      "description": "The Google search URL the request resolved to."
                    },
                    "pages": {
                      "type": "array",
                      "description": "Only with `rawhtml=1`: every Google page the answer was read from, in the order they were read (the first is the results page at `url`). When the answer would exceed the size limit, the last pages keep their `kind` and `url` with `html: null` and `truncated: true`.",
                      "items": {
                        "$ref": "#/components/schemas/RawPage"
                      }
                    },
                    "results": {
                      "type": "array",
                      "description": "Single-element array holding the parsed result groups.",
                      "items": {
                        "type": "object",
                        "description": "A group of results. The groups present vary by query — `Organic` and `PeopleAlsoSearchFor` are the most common, but others such as `Places` may also appear, and this set is not exhaustive.",
                        "properties": {
                          "Organic": {
                            "type": "array",
                            "description": "Organic search results, ordered by rank.",
                            "items": {
                              "$ref": "#/components/schemas/SerpResultItem"
                            }
                          },
                          "PeopleAlsoSearchFor": {
                            "type": "array",
                            "description": "Related \"people also search for\" suggestions.",
                            "items": {
                              "$ref": "#/components/schemas/SerpResultItem"
                            }
                          },
                          "Places": {
                            "type": "array",
                            "description": "Local business / map-pack results, when the query triggers them.",
                            "items": {
                              "$ref": "#/components/schemas/SerpResultItem"
                            }
                          }
                        }
                      }
                    }
                  }
                },
                "example": {
                  "query": "proxyscrape",
                  "url": "https://www.google.com/search?q=proxyscrape&num=10&start=0&hl=en",
                  "results": [
                    {
                      "Organic": [
                        {
                          "title": "ProxyScrape - Free Proxy List & Premium Proxies",
                          "url": "https://proxyscrape.com/",
                          "description": "ProxyScrape provides free proxy lists and premium proxy services...",
                          "moreinfo": "",
                          "rank": 0
                        }
                      ],
                      "PeopleAlsoSearchFor": [
                        {
                          "title": "proxyscrape free proxy",
                          "url": "https://www.google.com/search?q=proxyscrape+free+proxy",
                          "description": "",
                          "moreinfo": "",
                          "rank": 0
                        }
                      ],
                      "Places": [
                        {
                          "title": "Example Proxy Co.",
                          "url": "",
                          "description": "5.0(12) · Software company",
                          "moreinfo": "",
                          "rank": 0
                        }
                      ]
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid request parameters (e.g. no `q`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "Error": {
                    "Status": "INVALID_REQUEST",
                    "Message": "The search request parameter is incorrect",
                    "Code": 400
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid Basic Auth credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "Error": {
                    "Status": "Unauthorized",
                    "Message": "user/credit validation failure",
                    "Code": 401
                  }
                }
              }
            }
          },
          "402": {
            "description": "Not enough credit: the request can cost more than the credit left on the plan.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "Error": {
                    "Status": "INSUFFICIENT_CREDIT",
                    "Message": "This request can cost up to 3 units; 1 are available",
                    "Code": 402
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "Error": {
                    "Status": "Too Many Requests",
                    "Message": "Rate limit exceeded",
                    "Code": 429
                  }
                }
              }
            }
          },
          "500": {
            "description": "The search failed: Google refused it or returned an unexpected page, after retries. Not billed; try again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "Error": {
                    "Status": "FAILURE",
                    "Message": "BLOCKED: Google refused the search (retries exhausted)",
                    "Code": 500
                  }
                }
              }
            }
          },
          "502": {
            "description": "Google returned an unexpected status or could not be reached. Not billed; try again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "Error": {
                    "Status": "FAILURE",
                    "Message": "UPSTREAM: Google returned an unexpected HTTP status (retries exhausted)",
                    "Code": 502
                  }
                }
              }
            }
          },
          "503": {
            "description": "No search capacity available right now. Not billed; try again shortly.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "Error": {
                    "Status": "FAILURE",
                    "Message": "Failed to perform search, try again",
                    "Code": 503
                  }
                }
              }
            }
          },
          "504": {
            "description": "Google did not answer in time. Not billed; try again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "Error": {
                    "Status": "FAILURE",
                    "Message": "TIMEOUT: Google did not respond in time (retries exhausted)",
                    "Code": 504
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://serp.api.proxyscrape.com/?q=proxyscrape&gl=us&hl=en&start=0&rawhtml=0\" \\\n  -u \"<sub-user-username>:<sub-user-password>\""
          },
          {
            "lang": "javascript",
            "label": "NodeJS",
            "source": "const axios = require('axios');\n\nconst username = '<sub-user-username>';\nconst password = '<sub-user-password>';\nconst host = 'https://serp.api.proxyscrape.com';\n\nconst url = host + '?q=proxyscrape&gl=us&hl=en&start=0&rawhtml=0';\n\naxios\n  .get(url, { auth: { username, password } })\n  .then((res) => console.log(res.data.results[0]))\n  .catch((err) => console.error(err));"
          },
          {
            "lang": "python",
            "label": "Python3",
            "source": "#!/usr/bin/env python3\nimport requests\n\nusername = \"<sub-user-username>\"\npassword = \"<sub-user-password>\"\nhost = \"https://serp.api.proxyscrape.com\"\n\nurl = host + \"?q=proxyscrape&gl=us&hl=en&start=0&rawhtml=0\"\nheaders = {\"User-Agent\": \"curl/8.7.1\"}\n\nr = requests.get(url, auth=(username, password), headers=headers)\nprint(r.text)"
          }
        ]
      }
    }
  },
  "components": {
    "securitySchemes": {
      "basicAuth": {
        "type": "http",
        "scheme": "basic",
        "description": "HTTP Basic Auth using a SERP API sub-user's username and password."
      }
    },
    "schemas": {
      "SerpResultItem": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string",
            "description": "The result title."
          },
          "url": {
            "type": "string",
            "description": "The result URL."
          },
          "description": {
            "type": "string",
            "description": "The result snippet / description."
          },
          "moreinfo": {
            "type": "string",
            "description": "Additional metadata Google attaches to the result, when present. Often an empty string."
          },
          "rank": {
            "type": "integer",
            "description": "The result's position within its group."
          }
        }
      },
      "Error": {
        "type": "object",
        "required": [
          "Error"
        ],
        "properties": {
          "Error": {
            "type": "object",
            "required": [
              "Status",
              "Message",
              "Code"
            ],
            "properties": {
              "Status": {
                "type": "string",
                "description": "The error kind, e.g. `INVALID_REQUEST`, `Unauthorized`, `INSUFFICIENT_CREDIT`, `FAILURE`."
              },
              "Message": {
                "type": "string",
                "description": "What went wrong. Search failures start with a class such as `BLOCKED:`, `TIMEOUT:` or `UPSTREAM:`."
              },
              "Code": {
                "type": "integer",
                "description": "Same as the HTTP status code."
              }
            }
          }
        }
      },
      "RawPage": {
        "type": "object",
        "properties": {
          "kind": {
            "type": "string",
            "description": "`results` for a web search results page."
          },
          "url": {
            "type": "string",
            "description": "The Google URL of the page."
          },
          "html": {
            "type": "string",
            "nullable": true,
            "description": "The page's HTML; `null` when it did not fit in the answer (`truncated`)."
          },
          "truncated": {
            "type": "boolean",
            "description": "Present and `true` when the page's HTML was left out to stay within the size limit."
          }
        }
      }
    }
  }
}
