Developer Docs

Google SERP API (Synchronous Search)

SERP endpoints are for "ask and get an answer" search: you submit a query and the server blocks until done and returns the results directly, unlike scraper's async "submit → poll → fetch" model. Ideal for small jobs; large jobs that exceed the sync window fall back to a pollable run (see below).


Three differences from scraper

Aspect scraper (/v1/scraper/*) SERP (/v1/serp/*)
Input { deliveryMode, recordLimit, targets:[ {...} ], deliveries } (array of targets) Flat: query fields at the top level of the body + recordLimit + dataFormat (single query)
Return Async: 201 + run id, poll to fetch Synchronous: 200 + results (records array), no polling
Push Supports deliveries webhooks Not supported (synchronous return, no async notifications)

Quick reference

  • Base URL: https://api.antsdata.com/v1
  • Method & path: POST /v1/serp/{platform}/{resource}. Currently platform is only google; see the endpoint list below for resource.
  • Auth: header Authorization: Bearer ants_xxx (static API Key, same as scraper)
  • Content-Type: application/json
  • Request body: query fields flattened at the top level, plus two optional run-level fields:
    • recordLimit: record cap for this query (omit / 0 = derived from available credits).
    • dataFormat: result format, json (default, returns a records array) / csv / html / markdown (the latter three return exported text).

Status codes & response body

Uniform envelope { code, message, data }; the shape of data depends on the outcome:

Case HTTP data
Success + json 200 { "runId", "status":"succeeded", "records":[ … ] }
Success + csv/html/markdown 200 { "runId", "status":"succeeded", "format":"csv", "content":"…" }
Scrape failed 200 { "runId", "status":"failed", "run":{ …per-task errorMessage… } }
Timed out (not terminal) 202 { "runId", "status":"queued"\|"running", "run":{ … } }
  • Timeout fallback: if a large query doesn't finish within the server's sync window → 202 + runId, and the run keeps running in the background. Switch to polling: GET /v1/serp/runs/{id}, then on success GET /v1/serp/runs/{id}/records to fetch or GET /v1/serp/runs/{id}/download?format=json|csv|excel to download.
  • Payload too large: a synchronous payload > 16 MiB returns an error — use GET /v1/serp/runs/{id}/download to fetch the full result.
  • Billing: same as scraper, charged per successfully returned record; failures release the hold and are not charged (see Authentication & Errors).

Endpoints

Endpoint Path Description
Web Search POST /v1/serp/google/search Web / image search results
Shopping POST /v1/serp/google/shopping Google Shopping products
News POST /v1/serp/google/news Google News articles
Maps POST /v1/serp/google/maps Google Maps places / businesses
Ad Creatives POST /v1/serp/google/ads-creatives Ads Transparency Center creative list
Creative Details POST /v1/serp/google/ads-creative-details Impression / spend / disclosure details for one creative

Search — Web Search

POST /v1/serp/google/search

Query fields (flattened at the top level of the body):

Field Type Required Description
query string Search keyword
searchType string web / image (default web)
geo_location string Geo location, e.g. California,United States
host_language string UI language hl, e.g. en (default en)
domain string Google domain suffix google.<domain> (default com)
page number SERP page number (default 1)

Output fields (records, one result per record):

Field Type Description
organic array Organic results (searchType=web, one per record)
organic.pos number Rank within section
organic.pos_overall number Overall rank on the page
organic.title string Title
organic.favicon_text string Site name / favicon text
organic.url_shown string Breadcrumb / displayed URL
organic.url string Landing URL
organic.desc string Snippet
imageResults array Image results (searchType=image, one per record)
imageResults.position number Order index
imageResults.thumbnailUrl string Thumbnail URL
imageResults.originalUrl string Original image URL
imageResults.source string Source domain
imageResults.title string Image title
total_results_count string Total-results text (e.g. About 1,230,000 results; null for some queries)
ai_overview string AI overview summary text (null if none)

Example:

curl -X POST "https://api.antsdata.com/v1/serp/google/search" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "bitcoin",
    "searchType": "web",
    "geo_location": "California,United States",
    "host_language": "en",
    "recordLimit": 50
  }'

Synchronous response (HTTP 200):

{
  "code": 0,
  "message": "ok",
  "data": {
    "runId": "1287345",
    "status": "succeeded",
    "records": [
      {
        "organic": {
          "pos": 1,
          "pos_overall": 1,
          "title": "Bitcoin - Open source P2P money",
          "url": "https://bitcoin.org/",
          "desc": "Bitcoin is an innovative payment network ..."
        }
      }
    ]
  }
}

Shopping

POST /v1/serp/google/shopping

Query fields:

Field Type Required Description
query string Product search term
gl string Country/region (default us)
hl string UI language (default en)
minPrice number Minimum price (local currency)
maxPrice number Maximum price
condition string new / used / refurbished
sortBy string relevance / price_asc / price_desc / rating
resultsLimit number Result cap (default 60; usually driven by recordLimit)

Output fields (records.products[], one product per record):

Field Type Description
totalResults number Estimated total hits
products.position number Rank index
products.productId string Google Shopping product ID
products.title string Product title
products.link string Shopping product detail page
products.price.amount string Current price
products.price.currency string Currency
products.price.originalAmount string Struck-through original price
products.seller string Seller name
products.rating string Product rating
products.reviewsCount number Number of reviews
products.thumbnail string Main thumbnail URL
products.isSponsored boolean Whether it's a sponsored / ad slot
products.shipping string Shipping note
products.badges array Platform badges
products.offers[].seller string Other seller name
products.offers[].price string That seller's price
products.offers[].currency string Currency
products.offers[].condition string Item condition
products.offers[].link string Seller landing page

Example:

curl -X POST "https://api.antsdata.com/v1/serp/google/shopping" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "wireless earbuds",
    "gl": "us",
    "hl": "en",
    "minPrice": 50,
    "maxPrice": 300
  }'

News

POST /v1/serp/google/news

Query fields:

Field Type Required Description
query string Search keyword
timeRange string 1h / 1d / 7d / 1m / 1y (default 7d, keyword only)
cluster boolean Cluster/dedupe same-event stories (default true, keyword only)
hl string Language (default en)
gl string Country/region (default us)
feedType string keyword / top / topic / publication (default keyword)
topicId string Required when feedType=topic
publicationId string Required when feedType=publication

Output fields (records.articles[], one article per record):

Field Type Description
feedType string Echoes the feed type used
articles.title string Article title
articles.link string News link
articles.source string Publisher name
articles.published string Published time
articles.snippet string Snippet
articles.thumbnail string Thumbnail URL
articles.clusterSize number Number of related stories (when clustering is on)

Example:

curl -X POST "https://api.antsdata.com/v1/serp/google/news" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "AI regulation EU",
    "timeRange": "7d",
    "cluster": true,
    "hl": "en",
    "gl": "us"
  }'

Maps

POST /v1/serp/google/maps

Query fields:

Field Type Required Description
query string Address / place / business search term
location string Natural-language area for business search, e.g. Manhattan, NY
gl string Country/region code (default us)
hl string UI language (default en)
openNow boolean Open now only (default false)
resultsLimit number Business-search result cap (default 20; usually driven by recordLimit)
minRating number Minimum-rating filter
pageToken string Pagination token (from previous nextPageToken)
lat / lng number Reverse-lookup coordinates (paired)
ll string Business-search center point, e.g. @40.7128,-74.0060,15z
mode string geocode / reverse / places (default places, usually left blank for auto-detect)

Output fields (records.places[], one place per record):

Field Type Description
places.placeId string Google Place ID
places.dataId string Maps data_id
places.title string Business name
places.address string Address
places.rating string User rating
places.reviewsCount number Total reviews
places.priceLevel string Price level
places.categories array Categories
places.lat string Latitude
places.lng string Longitude
places.phone string Phone
places.website string Website
places.thumbnail string Cover thumbnail URL
nextPageToken string Next-page token

Example:

curl -X POST "https://api.antsdata.com/v1/serp/google/maps" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "coffee shop",
    "location": "Manhattan, NY",
    "gl": "us",
    "hl": "en",
    "openNow": false
  }'

Ads-creatives — Ad Creatives

POST /v1/serp/google/ads-creatives

Creative list from the Google Ads Transparency Center. The returned creative_id / sponsor_id can feed the "Creative Details" endpoint.

Query fields:

Field Type Required Description
query string Website domain / keyword, e.g. nike.com (or use advertiser_id)
regions array Region-code array, e.g. ["US","GB"] (default ["us"], region format)
start_date string Start YYYY-MM-DD
end_date string End YYYY-MM-DD
platform number Platform filter 1–6 (1=Search / 2=Display / 3=YouTube / 4=Maps / 5=Play / 6=Shopping)
advertiser_id string Advertiser ID (or use query; comes from suggestions)
limit number Creative cap (1–1000, default 100; capped down by recordLimit)
topic string Set political to switch to the political-ads schema

Output fields (records, one creative per record):

Field Type Description
creative_id string Creative ID (feeds creative details)
sponsor_id string Advertiser ID
format string Creative format (e.g. video)
regions array Served regions
first_shown string First shown
last_shown string Last shown

Example:

curl -X POST "https://api.antsdata.com/v1/serp/google/ads-creatives" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "nike.com",
    "regions": ["US"],
    "start_date": "2026-01-01",
    "end_date": "2026-06-30",
    "platform": 1
  }'

Ads-creative-details — Creative Details

POST /v1/serp/google/ads-creative-details

Impression / spend / political-ad disclosure details for a single creative. Get sponsor_id and creative_id from the "Ad Creatives" endpoint first; don't hardcode them.

Query fields:

Field Type Required Description
sponsor_id string Advertiser ID
creative_id string Creative ID (get it from the ad-creatives endpoint first)
topic string Set political to switch to the political schema

Output fields (records, one creative detail per record):

Field Type Description
creative_id string Creative ID
sponsor_id string Advertiser ID
first_shown string First shown (ISO 8601)
last_shown string Last shown (ISO 8601)
topic string Ad topic (non-empty when political, else empty string)
funder string Funder (political-ad disclosure; empty for regular ads)
regions array Per-region detail, each {code, first_shown, last_shown, min_times, max_times} (impression ranges are strings)
impressions_lower number Impressions lower bound (political / EU disclosure; null for regular ads)
impressions_upper number Impressions upper bound (same)
spend_lower number Spend lower bound (political / EU disclosure; null for regular ads)
spend_upper number Spend upper bound (same)
eu_reach number EU reach (EU political-ad disclosure; else null)

Example:

curl -X POST "https://api.antsdata.com/v1/serp/google/ads-creative-details" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "sponsor_id": "AR00040546930815664129",
    "creative_id": "CR12886158981977866241"
  }'

FAQ

Q: How is SERP different from /v1/scraper/google/*?

They share the same underlying Google scraping capability, but SERP (/v1/serp/google/*) is a synchronous, flat-input wrapper: one call returns results directly, with no targets array and no polling. Use /v1/scraper/google/* for async batches and webhook delivery.

Q: I got a 202 — what now?

202 means the query was large and didn't finish within the sync window, but the run continues in the background. Take the runId and poll GET /v1/serp/runs/{id}; once succeeded, fetch with GET /v1/serp/runs/{id}/records or download via /download.

Q: Which dataFormat values are supported?

json (default, records array) and csv / html / markdown (returns content text + format).

Q: The result is too big to return?

The synchronous payload limit is 16 MiB; larger returns an error. Use GET /v1/serp/runs/{id}/download?format=json|csv|excel to fetch it all at once.

Q: How is it billed?

Same as scraper — charged per successfully returned record; failures release the hold and aren't charged. See Authentication & Errors.