{"openapi":"3.2.0","info":{"title":"Google API","description":"Google Search APIs","version":"1.0.0"},"servers":[{"url":"https://googleapis.jojapi.net"}],"security":[{"ApiKeyAuth":[]}],"tags":[{"name":"SERP","description":"SERP (Search Engine Results Page) Endpoints"},{"name":"Tasks","description":"Queue up to 100 searches at once and collect the results later, via webhook or polling. Built for volume jobs that don't need an instant answer."}],"x-agent-commerce":{"catalog_url":"https://googleapis.jojapi.net/_jojapi/agent/plans","discovery_url":"https://googleapis.jojapi.net/.well-known/x402","directory_url":"https://agents.jojapi.net/apis/googleapis","docs":"https://docs.jojapi.com/consumers/agents"},"paths":{"/v1/serp":{"get":{"operationId":"get_v1_serp","summary":"Full SERP","description":"One Google result page for a query. Every field comes off the HTML google.com served: `results` are the organic results in Google's order, each with the URL its own link resolves to (`matched: goto`) or the one Google printed in the clear (`matched: direct`); `ads`, `ai_overview` (with `text`, `html` and `references`), `people_also_ask`, `related_searches` and `page_blocks` (what sat where — an AI Overview above position four is the difference between \"ranked fourth\" and \"fourth thing on the page\"). `location_used` is where Google placed the search, always present. There is no `limit`: Google ignores `num`, a page shows what it shows, and depth is bought a page at a time with `page`.","tags":["SERP"],"responses":{"200":{"description":"The result page, read from google.com's own HTML: organic results in Google's order with resolved URLs, ads, the AI Overview, people-also-ask questions, related searches, where Google placed the search, and what sat between the results.","content":{"application/json":{"examples":{"success":{"value":{"status":"success","response":{"search_term":"best running shoes","hl":"en","gl":"us","device":"desktop","page":1,"location":"New York,New York,United States","uule":"w+CAIQICIfTmV3IFlvcmssTmV3IFlvcmssVW5pdGVkIFN0YXRlcw==","location_used":{"name":"New York","source":"ip"},"layout":"desktop","showing_results_for":null,"ai_overview":{"text":"AI Mode replied: The top-rated running shoes on the market combine high energy return, plush cushioning, and reliable support for different styles of running. According to recent gear testing from publications like Tom's Guide, RunRepeat, and Outside Magazine, here are 5 of the best running shoes ca …","html":"<div class=\"XTvndd k9pDj\" data-ftag=\"142\" data-ved=\"2ahUKEwic9czJ7feWAxVAK1kFHcLHOUYQ1KsPegQIBBAA\"><div jscontroller=\"g5dM4c\" class=\"hICk5e\" data-collapsed=\"1\"  …","references":[{"title":"7 Best Running Shoes in 2026 - RunRepeat","url":"https://runrepeat.com/guides/best-running-shoes","source":"RunRepeat","snippet":"And if you want to learn more about choosing the right running shoe, scroll down to our in-depth guide. * Best overall. adidas Adi..."},{"title":"What are the best running shoes that you'd actually buy again? - Reddit","url":"https://www.reddit.com/r/runninglifestyle/comments/1u5x7mx/what_are_the_best_running_shoes_that_youd/","source":"Reddit","snippet":"More replies flummoxed_ • 3mo ago Highly recommend ASICS Super Blasts ! I have tried out the Gel Kayanos and Novablasts but I foun..."}]},"ads":[{"position":1,"type":"text","title":"Running Shoes - Free Shipping & Returns","advertiser":"Example Store","displayed_link":"www.example-store.com/running","description":"Shop the latest running shoes. Free shipping on orders over $50.","url":"https://www.example-store.com/running","origin":"https://www.example-store.com","sitelinks":[]}],"results":[{"position":1,"slot":10,"title":"The 15 Best Running Shoes of 2026","site":"Runner's World","domain":"runnersworld.com","origin":"https://www.runnersworld.com","breadcrumb":"› ... › Running Shoes","subtitle":null,"snippet":"For new runners we recommend a shoe like the Brooks Ghost or Nike Pegasus as a starting point. These shoes are moderately cushioned and offer ...","sitelinks":[],"url":"https://www.runnersworld.com/gear/a19663621/best-running-shoes/","matched":"goto"},{"position":2,"slot":12,"title":"7 Best Running Shoes in 2026","site":"RunRepeat","domain":"runrepeat.com","origin":"https://runrepeat.com","breadcrumb":"› guides › best-running-shoes","subtitle":null,"snippet":"The New Balance 1080 v15 stands out in the all-rounder game, bringing a whole new level of comfort while sustaining lightness and responsiveness ...","sitelinks":[],"url":"https://runrepeat.com/guides/best-running-shoes","matched":"goto"},{"position":3,"slot":14,"title":"What are the best running shoes that you'd actually buy ...","site":"Reddit · r/runninglifestyle","domain":null,"origin":null,"breadcrumb":null,"subtitle":"220+ comments · 3 months ago","snippet":"I’m finally replacing my running shoes and I forgot how overwhelming this category is. Every list says something different and everyone seems to ...","sitelinks":[],"url":"https://www.reddit.com/r/runninglifestyle/comments/1u5x7mx/what_are_the_best_running_shoes_that_youd/","matched":"goto"}],"people_also_ask":["What are the top 5 best running shoes?","What are the best shoes for running?","What are the #1 running shoes?"],"related_searches":["Best running shoes men","Best running shoes long distance","Best running shoes women"],"page_blocks":[{"slot":10,"kind":"organic","results":1,"label":"Web results"},{"slot":12,"kind":"organic","results":1,"label":null},{"slot":14,"kind":"organic","results":1,"label":null},{"slot":18,"kind":"organic","results":1,"label":"Web results"}]}}}}}}},"400":{"description":"A required parameter is missing or a value is invalid: unknown country in `location`, malformed `uule`, `gl` disagreeing with the location's country, `page` out of 1–10, `start` not a page boundary.","content":{"application/json":{"examples":{"missing_required_parameters":{"value":{"status":"missing_required_parameters","required_parameters":[{"key":"query","type":"string"}]}},"invalid_location":{"value":{"status":"invalid_parameter","message":"location must be a Google Ads canonical name ending in a country, e.g. \"New York,New York,United States\", \"London,England,United Kingdom\", \"Istanbul,Turkiye\" or \"Germany\" (most specific part first)"}},"gl_mismatch":{"value":{"status":"invalid_parameter","message":"gl=us names a different country than \"London,England,United Kingdom\" (gl=uk); Google ignores a location whose country disagrees with gl, so send one or the other"}},"invalid_page":{"value":{"status":"invalid_parameter","message":"page must be a whole number from 1 to 10"}}}}}},"424":{"description":"Google served the page for a different place than the one asked for — the location is most likely not a name Google knows. `location_used` says what it rendered instead.","content":{"application/json":{"examples":{"location_not_honoured":{"value":{"status":"location_not_honoured","message":"Google served the page for \"Idaho\" rather than \"Nowhereville,Idaho,United States\"; the location is probably not a name Google knows","location":"Nowhereville,Idaho,United States","location_used":{"name":"Idaho","source":"ip"}}}}}}},"429":{"description":"Too many queries in flight on the server, no search capacity free right now, or the marketplace's rate limit. Retry after `Retry-After` seconds; for batches, queue the work with `/v1/serp/tasks` instead. Not billed.","content":{"application/json":{"examples":{"over_capacity":{"value":{"status":"over_capacity","message":"Too many SERP queries in flight on this server; retry in a moment. For batches, v1/serp/tasks queues the work instead."}},"no_capacity":{"value":{"status":"over_capacity","message":"No SERP capacity is free right now; retry in a minute. For batches, v1/serp/tasks queues the work instead."}},"rate_limited":{"value":{"status":"rate_limited","message":"Rate limit exceeded","retry_after":30}}}}}},"500":{"description":"The page could not be fetched: Google refused every attempt. Retry; not billed.","content":{"application/json":{"examples":{"server_error":{"value":{"status":"server_error","message":"Server error ##32"}}}}}}},"parameters":[{"name":"query","in":"query","description":"The search term, exactly as it would be typed into google.com. Google's own operators work (`\"exact phrase\"`, `-exclude`, `site:`, `intitle:`, `filetype:`, `before:`/`after:`). Also accepted as `q`.","required":true,"schema":{"type":"string","example":"best running shoes"}},{"name":"location","in":"query","description":"Place the search in a city, region or country, named the way Google Ads' geotargets table names it — most specific part first, ending in the country: `New York,New York,United States`, `London,England,United Kingdom`, `Istanbul,Turkiye`, `Germany`. Sets `gl` to the location's country; a `gl` that names another country is refused with 400. The place Google actually rendered the page for is returned in `location_used`, and if it names somewhere else the request fails with 424 rather than returning another city's results.","required":false,"schema":{"type":"string","example":"New York,New York,United States"}},{"name":"uule","in":"query","description":"Google's own encoded location parameter, for callers who already carry one. The canonical-name form only (`w+CAIQICI…`); it is decoded and must name a known country. Equivalent to `location`; send one or the other.","required":false,"schema":{"type":"string","example":"w+CAIQICIfTmV3IFlvcmssTmV3IFlvcmssVW5pdGVkIFN0YXRlcw=="}},{"name":"gl","in":"query","description":"Country to search as, two-letter code (`us`, `uk`, `de`, `tr`). Optional; when `location` or `uule` is given it is set from the location's country. Without a location the search follows the exit address's country.","required":false,"schema":{"type":"string","example":"us"}},{"name":"hl","in":"query","description":"Interface language, a BCP-47 tag (`en`, `en-GB`, `de`, `tr`). Defaults to `en`.","required":false,"schema":{"type":"string","example":"en","default":"en"}},{"name":"page","in":"query","description":"Which of Google's result pages to return, 1 to 10 — the range Google itself links to. Each page is one request. Pages after the first carry organic results and related searches; the AI Overview and people-also-ask are page-one blocks. Positions are absolute: page 2 starts at 11.","required":false,"schema":{"type":"integer","example":1,"default":1}},{"name":"start","in":"query","description":"The same thing as `page`, the way Google's URLs say it: offset of the first result, a multiple of 10 from 0 to 90. If both are sent they must agree.","required":false,"schema":{"type":"integer"}},{"name":"device","in":"query","description":"`desktop` (default) or `mobile`. Mobile fetches the page as a phone would, which changes the layout and what Google puts on it.","required":false,"schema":{"type":"string","enum":["desktop","mobile"],"example":"desktop","default":"desktop"}},{"name":"output","in":"query","description":"`json` (default) parses the page into the structure below. `html` returns the page exactly as google.com served it, in the same JSON envelope (`html` field, no `ai_overview`), for callers who parse a SERP themselves. Same cost.","required":false,"schema":{"type":"string","enum":["json","html"],"example":"json","default":"json"}}]}},"/v1":{"get":{"operationId":"get_v1","summary":"Basic SERP","description":"Get web search results, knowledge panel and related keywords","tags":["SERP"],"parameters":[{"name":"query","in":"query","required":true,"schema":{"type":"string","title":"Search query","example":"jojapi"}},{"name":"limit","in":"query","required":false,"schema":{"type":"number"}},{"name":"hl","in":"query","required":false,"schema":{"type":"string","title":"Language code","example":"en","default":"en"}},{"name":"gl","in":"query","required":false,"schema":{"type":"string","title":"Country code","example":"us","default":"us"}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"}},{"name":"related_keywords","in":"query","required":false,"schema":{"type":"boolean","example":false}}]}},"/v1/serp/tasks":{"post":{"operationId":"post_v1_serp_tasks","summary":"Queue Full SERP queries","description":"The same query as `/v1/serp`, queued. Submit up to 100 at once and get an id per task back at once (202); a worker runs them at the rate the pool sustains, and the answers are fetched with `/v1/serp/task` — each exactly what `/v1/serp` would have returned, or the error it would have answered with. Give a `callback_url` and a small notification (`{id, status, http_status}`) is POSTed to it as each task finishes, retried for hours if the endpoint does not answer 2xx; without one, poll `/v1/serp/task` with up to 100 ids per call. Every task is checked at submission with the same rules as `/v1/serp`, so a bad one refuses the whole submission (400 with `task_index`) and nothing is queued or billed. Billed per task queued; fetching is free. Results stay fetchable for 48 hours. This is the right entry point for batches: a night's keywords become queue depth rather than a wall of 429s, and the retries on the way are absorbed rather than surfaced.","tags":["Tasks"],"responses":{"202":{"description":"Queued. One id per task, in the order given; `queued_ahead` is how many tasks were already waiting.","content":{"application/json":{"examples":{"queued":{"value":{"status":"accepted","accepted":2,"tasks":[{"id":"h3chuhnlx4y5jah54xyhsi6m","status":"queued"},{"id":"o4yhfqjday3vi6fk5kmdxuyj","status":"queued"}],"callback_url":"https://example.com/serp-callback","queued_ahead":0}}}}}},"400":{"description":"A task or the callback URL is not acceptable; nothing was queued. `task_index` names the task.","content":{"application/json":{"examples":{"bad_task":{"value":{"status":"invalid_parameter","task_index":1,"message":"page must be a whole number from 1 to 10"}},"bad_callback":{"value":{"status":"invalid_parameter","message":"callback_url must resolve to a public address"}}}}}},"429":{"description":"The queue is at its limit, or the marketplace's rate limit. Retry after `Retry-After` seconds.","content":{"application/json":{"examples":{"queue_full":{"value":{"status":"queue_full","message":"the task queue holds 50000 of 50000; retry later","queued":50000}}}}}}},"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"tasks":{"type":"array","minItems":1,"maxItems":100,"description":"One object per query, each taking the parameters of `/v1/serp`.","items":{"type":"object","required":["query"],"properties":{"query":{"type":"string","description":"The search term. Also accepted as `q`."},"location":{"type":"string","description":"Place the search in a city, region or country, named the way Google Ads' geotargets table names it — most specific part first, ending in the country: `New York,New York,United States`, `London,England,United Kingdom`, `Istanbul,Turkiye`, `Germany`."},"uule":{"type":"string","description":"Google's own encoded location parameter, for callers who already carry one."},"gl":{"type":"string","description":"Country to search as, two-letter code (`us`, `uk`, `de`, `tr`)."},"hl":{"type":"string","description":"Interface language, a BCP-47 tag (`en`, `en-GB`, `de`, `tr`)."},"page":{"type":"integer","description":"Which of Google's result pages to return, 1 to 10 — the range Google itself links to."},"start":{"type":"integer","description":"The same thing as `page`, the way Google's URLs say it: offset of the first result, a multiple of 10 from 0 to 90."},"device":{"type":"string","description":"`desktop` (default) or `mobile`."},"output":{"type":"string","description":"`json` (default) or `html` — the page's bytes, unread, in the same envelope."}}}},"callback_url":{"type":"string","format":"uri","description":"Optional. An absolute public http(s) URL to POST `{\"id\", \"status\", \"http_status\"}` to as each task finishes. Any 2xx counts as delivered; otherwise retried after 1 min, 5 min, 30 min and 2 h, then given up (the result stays fetchable)."}}},"example":{"tasks":[{"query":"best running shoes","location":"New York,New York,United States"},{"query":"kubernetes vs docker","gl":"us","device":"mobile"}],"callback_url":"https://example.com/serp-callback"}}}}}},"/v1/serp/task":{"get":{"operationId":"get_v1_serp_task","summary":"Fetch queued Full SERP results","description":"The state and, once done, the answer of queued tasks. One id returns `task`; up to 100 comma-separated ids return `tasks` in the order asked, unknown ones as `not_found`. A done task carries `result` — exactly the `/v1/serp` answer — and a failed one `error` with the body and `http_status` `/v1/serp` would have answered. Free. Results are kept 48 hours.","tags":["Tasks"],"responses":{"200":{"description":"The task(s).","content":{"application/json":{"examples":{"done":{"value":{"status":"ok","task":{"id":"h3chuhnlx4y5jah54xyhsi6m","status":"done","params":{"query":"best running shoes","device":"mobile"},"created_at":"2026-09-21 20:17:32","started_at":"2026-09-21 20:17:32","finished_at":"2026-09-21 20:17:37","fetched_at":null,"http_status":200,"result":{"search_term":"best running shoes","results":["… the /v1/serp answer …"]},"callback":{"url":"https://example.com/serp-callback","status":"sent","attempts":1}}}},"queued":{"value":{"status":"ok","task":{"id":"o4yhfqjday3vi6fk5kmdxuyj","status":"queued","params":{"query":"kubernetes vs docker"},"created_at":"2026-09-21 20:17:32","started_at":null,"finished_at":null,"fetched_at":null}}},"failed":{"value":{"status":"ok","task":{"id":"eyjnvspbichhiboncfhlsa7y","status":"failed","params":{"query":"plumber","location":"Atlantis,Atlantis"},"http_status":424,"error":{"status":"location_not_honoured","message":"Google served the page for \"Tampa\" rather than \"Atlantis\"; the location is probably not a name Google knows"}}}},"many":{"value":{"status":"ok","tasks":[{"id":"h3chuhnlx4y5jah54xyhsi6m","status":"done","http_status":200,"result":{"…":"…"}},{"id":"aaaaaaaaaaaaaaaaaaaaaaaa","status":"not_found"}]}}}}}},"400":{"description":"Not a task id, or more than 100 of them.","content":{"application/json":{"examples":{"bad_id":{"value":{"status":"invalid_parameter","message":"not a task id: nope"}}}}}},"404":{"description":"A single id that does not exist (or has expired).","content":{"application/json":{"examples":{"not_found":{"value":{"status":"not_found","id":"aaaaaaaaaaaaaaaaaaaaaaaa","message":"no such task; results are kept 48 hours"}}}}}}},"parameters":[{"name":"id","in":"query","description":"A task id from `/v1/serp/tasks`, or up to 100 of them comma-separated.","required":true,"schema":{"type":"string","example":"h3chuhnlx4y5jah54xyhsi6m"}}]}}},"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-JoJAPI-Key","description":"Your JoJ API key."}}}}