{
  "openapi": "3.0.3",
  "info": {
    "title": "CrustAPI",
    "version": "2.0.0",
    "description": "Self-scraped Google data as a clean JSON API. One endpoint returns a stable, serper-compatible shape for every Google surface: Web Search, Maps, Places, News, Shopping, Images, Videos, Reviews, Scholar, Patents, Autocomplete, and Webpage scrape. Choose a surface with `type`. Billed on success with never-expiring, top-up credits: 1 credit per successful query for every type (Maps bills 1 credit per business returned); empty results are free."
  },
  "servers": [{ "url": "https://crustapi.com" }],
  "security": [{ "ApiKeyAuth": [] }],
  "paths": {
    "/v1/search": {
      "get": {
        "operationId": "search",
        "summary": "Query any Google surface",
        "description": "One endpoint for the whole Google menu. Set `type` to choose the surface (default `web`). Each type returns a serper-compatible shape under its own key: web/scholar/patents/lens -> `organic`; news -> `news`; shopping -> `shopping`; images -> `images`; videos -> `videos`; maps/places -> `places`; reviews -> `reviews`; autocomplete -> `suggestions`; webpage -> `text` + `metadata` + `jsonld`. Billed 1 credit per successful query (Maps bills 1 credit per business returned). Blocked/empty rides are free.",
        "parameters": [
          { "name": "type", "in": "query", "required": false, "description": "Which Google surface to query.", "schema": { "type": "string", "default": "web", "enum": ["web", "maps", "places", "news", "shopping", "images", "videos", "reviews", "scholar", "patents", "autocomplete", "webpage", "lens"] } },
          { "name": "q", "in": "query", "required": false, "description": "The search query. Required for every type EXCEPT webpage and lens (use `url`) and reviews (use `placeId` / `cid` / `fid`).", "schema": { "type": "string" } },
          { "name": "url", "in": "query", "required": false, "description": "type=webpage: the page URL to scrape. type=lens: the image URL for reverse image search.", "schema": { "type": "string" } },
          { "name": "gl", "in": "query", "required": false, "description": "Country code (us, gb, de, ...). Not used by maps, patents, or webpage.", "schema": { "type": "string", "default": "us" } },
          { "name": "hl", "in": "query", "required": false, "description": "Language code (en, es, ...). Not used by patents or webpage.", "schema": { "type": "string", "default": "en" } },
          { "name": "page", "in": "query", "required": false, "description": "Result page. Not used by reviews, autocomplete, webpage, or lens.", "schema": { "type": "integer", "minimum": 1, "default": 1 } },
          { "name": "tbs", "in": "query", "required": false, "description": "Time filter for web/news/images/videos (e.g. qdr:h past hour, qdr:d past day, qdr:w past week, qdr:m past month, qdr:y past year).", "schema": { "type": "string" } },
          { "name": "num", "in": "query", "required": false, "description": "type=reviews: reviews per page (default 20, max 50).", "schema": { "type": "integer" } },
          { "name": "ll", "in": "query", "required": false, "description": "type=maps: GPS position and zoom as @latitude,longitude,zoom.", "schema": { "type": "string" } },
          { "name": "placeId", "in": "query", "required": false, "description": "Google place id (ChIJ...). Optional for maps; identifies the place for reviews.", "schema": { "type": "string" } },
          { "name": "cid", "in": "query", "required": false, "description": "Google customer id. Optional for maps; identifies the place for reviews.", "schema": { "type": "string" } },
          { "name": "fid", "in": "query", "required": false, "description": "Google feature id (0x..:0x..). Identifies the place for reviews.", "schema": { "type": "string" } },
          { "name": "sortBy", "in": "query", "required": false, "description": "type=reviews: review sort order.", "schema": { "type": "string", "enum": ["mostRelevant", "newest", "highest", "lowest"], "default": "mostRelevant" } },
          { "name": "nextPageToken", "in": "query", "required": false, "description": "type=reviews: cursor from the previous response to fetch the next page of reviews.", "schema": { "type": "string" } },
          { "name": "includeMarkdown", "in": "query", "required": false, "description": "type=webpage: also return the page rendered as Markdown.", "schema": { "type": "boolean", "default": false } },
          { "name": "location", "in": "query", "required": false, "description": "City/region hint for web and places.", "schema": { "type": "string" } },
          { "name": "limit", "in": "query", "required": false, "description": "type=maps only: how many businesses to return (1-100). Each is one credit.", "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 20 } },
          { "name": "stars", "in": "query", "required": false, "description": "type=maps: include the 1-5 star rating distribution per place.", "schema": { "type": "boolean" } }
        ],
        "responses": {
          "200": { "description": "Results for the chosen surface. The populated array key depends on `type`.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SearchResult" } } } },
          "400": { "description": "Missing or invalid parameter." },
          "401": { "description": "Missing or invalid API key." },
          "402": { "description": "Out of credits." },
          "429": { "description": "Rate limited." },
          "502": { "description": "Upstream fetch failed (uncharged)." },
          "503": { "description": "Surface temporarily unavailable, retry shortly (uncharged)." }
        }
      }
    },
    "/v1/demo": {
      "get": {
        "operationId": "demoSearch",
        "summary": "Public demo (no key, rate-limited)",
        "description": "A public, rate-limited demo of the search endpoint. No API key. For trying the API without signing up.",
        "security": [],
        "parameters": [
          { "name": "type", "in": "query", "required": false, "schema": { "type": "string", "default": "maps", "enum": ["maps", "web"] } },
          { "name": "q", "in": "query", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "A small sample of results.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SearchResult" } } } },
          "429": { "description": "Demo rate limit reached." }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKeyAuth": { "type": "apiKey", "in": "header", "name": "x-api-key" }
    },
    "schemas": {
      "SearchResult": {
        "type": "object",
        "description": "Polymorphic result. `searchParameters` echoes your request; the populated array key depends on `type`.",
        "properties": {
          "searchParameters": { "type": "object", "additionalProperties": true },
          "organic": { "type": "array", "description": "web, scholar, patents, lens", "items": { "$ref": "#/components/schemas/OrganicResult" } },
          "places": { "type": "array", "description": "maps, places", "items": { "$ref": "#/components/schemas/Place" } },
          "news": { "type": "array", "items": { "$ref": "#/components/schemas/NewsItem" } },
          "shopping": { "type": "array", "items": { "$ref": "#/components/schemas/ShoppingItem" } },
          "images": { "type": "array", "items": { "$ref": "#/components/schemas/ImageItem" } },
          "videos": { "type": "array", "items": { "$ref": "#/components/schemas/VideoItem" } },
          "reviews": { "type": "array", "items": { "$ref": "#/components/schemas/Review" } },
          "suggestions": { "type": "array", "items": { "$ref": "#/components/schemas/Suggestion" } },
          "text": { "type": "string", "description": "type=webpage: the page's readable text." },
          "markdown": { "type": "string", "description": "type=webpage with includeMarkdown=true." },
          "metadata": { "type": "object", "description": "type=webpage: title + og/twitter/article meta.", "additionalProperties": true },
          "jsonld": { "description": "type=webpage: parsed JSON-LD." },
          "nextPageToken": { "type": "string", "description": "type=reviews: cursor for the next page." },
          "creditsRemaining": { "type": "integer", "nullable": true },
          "tookMs": { "type": "integer" }
        }
      },
      "OrganicResult": {
        "type": "object",
        "description": "Web / Scholar / Patents / Lens result.",
        "properties": {
          "title": { "type": "string" },
          "link": { "type": "string" },
          "snippet": { "type": "string", "nullable": true },
          "date": { "type": "string", "nullable": true },
          "position": { "type": "integer" },
          "source": { "type": "string", "nullable": true, "description": "Scholar publication info / Lens source site." },
          "citedBy": { "type": "integer", "nullable": true, "description": "Scholar." },
          "assignee": { "type": "string", "nullable": true, "description": "Patents." },
          "filingDate": { "type": "string", "nullable": true, "description": "Patents." },
          "imageUrl": { "type": "string", "nullable": true, "description": "Lens." }
        }
      },
      "Place": {
        "type": "object",
        "description": "Maps returns the rich record; Places returns serper's lean local-pack shape.",
        "properties": {
          "position": { "type": "integer" },
          "title": { "type": "string", "description": "Business name." },
          "address": { "type": "string", "nullable": true },
          "latitude": { "type": "number", "nullable": true },
          "longitude": { "type": "number", "nullable": true },
          "rating": { "type": "number", "nullable": true, "description": "Star rating out of 5." },
          "ratingCount": { "type": "integer", "nullable": true },
          "reviewsCount": { "type": "integer", "nullable": true, "description": "Maps: exact review count." },
          "reviewsDistribution": { "type": "object", "nullable": true, "description": "Maps with stars=true: 1-5 star histogram." },
          "category": { "type": "string", "nullable": true },
          "phoneNumber": { "type": "string", "nullable": true },
          "website": { "type": "string", "nullable": true },
          "cid": { "type": "string", "nullable": true },
          "placeId": { "type": "string", "nullable": true }
        }
      },
      "NewsItem": {
        "type": "object",
        "properties": {
          "title": { "type": "string" }, "link": { "type": "string" }, "snippet": { "type": "string", "nullable": true },
          "date": { "type": "string", "nullable": true }, "source": { "type": "string", "nullable": true },
          "imageUrl": { "type": "string", "nullable": true }, "position": { "type": "integer" }
        }
      },
      "ShoppingItem": {
        "type": "object",
        "properties": {
          "title": { "type": "string" }, "source": { "type": "string", "nullable": true }, "condition": { "type": "string", "nullable": true },
          "link": { "type": "string", "nullable": true }, "price": { "type": "string", "nullable": true },
          "imageUrl": { "type": "string", "nullable": true }, "rating": { "type": "number", "nullable": true },
          "ratingCount": { "type": "integer", "nullable": true }, "productId": { "type": "string", "nullable": true }, "position": { "type": "integer" }
        }
      },
      "ImageItem": {
        "type": "object",
        "properties": {
          "title": { "type": "string" }, "imageUrl": { "type": "string" }, "imageWidth": { "type": "integer", "nullable": true },
          "imageHeight": { "type": "integer", "nullable": true }, "thumbnailUrl": { "type": "string" },
          "thumbnailWidth": { "type": "integer", "nullable": true }, "thumbnailHeight": { "type": "integer", "nullable": true },
          "source": { "type": "string", "nullable": true }, "domain": { "type": "string", "nullable": true },
          "link": { "type": "string", "nullable": true }, "googleUrl": { "type": "string", "nullable": true }, "position": { "type": "integer" }
        }
      },
      "VideoItem": {
        "type": "object",
        "properties": {
          "title": { "type": "string" }, "link": { "type": "string" }, "snippet": { "type": "string", "nullable": true },
          "imageUrl": { "type": "string", "nullable": true }, "duration": { "type": "string", "nullable": true },
          "source": { "type": "string", "nullable": true }, "channel": { "type": "string", "nullable": true },
          "date": { "type": "string", "nullable": true }, "position": { "type": "integer" }
        }
      },
      "Review": {
        "type": "object",
        "properties": {
          "rating": { "type": "integer" }, "date": { "type": "string", "nullable": true }, "isoDate": { "type": "string", "nullable": true },
          "snippet": { "type": "string", "nullable": true }, "likes": { "type": "integer" },
          "user": { "type": "object", "properties": { "name": { "type": "string", "nullable": true }, "thumbnail": { "type": "string", "nullable": true }, "link": { "type": "string", "nullable": true }, "reviews": { "type": "integer", "nullable": true }, "photos": { "type": "integer", "nullable": true } } },
          "media": { "type": "array", "items": { "type": "object", "properties": { "type": { "type": "string" }, "imageUrl": { "type": "string" }, "caption": { "type": "string" } } } },
          "link": { "type": "string", "nullable": true }, "id": { "type": "string", "nullable": true }
        }
      },
      "Suggestion": {
        "type": "object",
        "properties": { "value": { "type": "string" } }
      }
    }
  }
}
