SERP Data API

Export published ranking history and search engine results page (SERP) evidence for one tracked keyword, search configuration and engine. Use this endpoint for reporting integrations that need the stored evidence behind Search Performance, including available page-conflict information.


Create with POST https://app.wheremore.com/api/v2/exports/serp . Retrieve with GET https://app.wheremore.com/api/v2/exports/{export_id} . This guide describes default data contract 2026-09-19 . See API Access and API Keys for credentials, shared response fields, callbacks and errors.


Identify the keyword and search configuration

Use the public workspace ID from API Access → Your Workspaces and Markets. Discover configurations for a website with:


curl --get "https://app.wheremore.com/api/v2/markets" \
  -H "X-API-Key: ${WHEREMORE_API_KEY}" \
  --data-urlencode "workspace_id=ws_your_workspace_id" \
  --data-urlencode "domain=example.com"

The free response contains data.workspace_id , domain , domain_id , markets  and total . Each markets  entry contains queue_id , market_id , market_name  and search_engines .


Use queue_id , not market_id , in the export. The queue identifies the exact search configuration; the market/group identifier is not interchangeable. Select an engine returned for that queue. You also need the numeric ID of a keyword tracked in that configuration. This API has no keyword-list endpoint; obtain the tracked keyword ID from your Wheremore configuration or workspace administrator.


Request fields

Send a JSON object. Unknown fields are rejected.


Field Required Accepted value
workspace_id Yes Public ws_...  ID.
queue_id Yes Positive search-configuration ID from market discovery.
keyword_id Yes Positive tracked keyword ID.
search_engine Yes google , bing  or yahoo , available in this queue.
date_from , date_to Yes Inclusive UTC YYYY-MM-DD  dates; 1–366 days, no future end date.
category_id No Positive category ID to narrow the keyword's reporting scope. Omit for the default scope.
freshness No latest_published  (default) or wait_for_fresh .
data_contract No 2026-09-19  (default) or 2026-09-10 .
callback_url No Public HTTPS readiness callback; see the shared guide for constraints.

domain , keyword  and market_id  are not valid fields for this export. They belong to the older request design or discovery metadata.


Create and retrieve a report

Replace the sample IDs and dates. Set WHEREMORE_API_KEY  securely before running the command.


curl --fail-with-body -X POST \
  "https://app.wheremore.com/api/v2/exports/serp" \
  -H "X-API-Key: ${WHEREMORE_API_KEY}" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: search-report-20260919-001" \
  -d '{
    "workspace_id": "ws_your_workspace_id",
    "queue_id": 101,
    "keyword_id": 456,
    "search_engine": "google",
    "date_from": "2026-09-01",
    "date_to": "2026-09-18",
    "freshness": "latest_published",
    "data_contract": "2026-09-19"
  }'

  1. Save export.id  from the creation response. HTTP 201 means ready and 202 means pending. Neither charges or returns report data.
  2. Retrieve that ID with the same user's API credentials:

curl --fail-with-body \
  "https://app.wheremore.com/api/v2/exports/exp_0123456789abcdef0123456789abcdef" \
  -H "X-API-Key: ${WHEREMORE_API_KEY}"

  1. If GET returns 202, poll with backoff or await the optional callback. HTTP 200 returns the saved report in data .

Retry an identical POST with the same idempotency key. Use a new key for different parameters or a later report. Repeated GETs never refresh the saved snapshot.


Choose freshness deliberately

latest_published  accepts the available published data even if its selected observation predates export creation. Use it for historical reporting.


wait_for_fresh  requires date_to  to include the export's UTC creation date. It waits for a selected SERP observation whose observed_at  is at or after creation. It does not start a search or force a monitoring run. The saved date window stays fixed; if no qualifying observation arrives in that window, the job can remain pending until expiry. Ranking history alone does not satisfy this policy.


Returned data

Field inside data Meaning
data_contract , workspace_id Response format and public workspace scope.
contract_version The published reader's own contract version, separate from the API date.
scope Queue, keyword, engine, category, website and related scope metadata.
periods Current/comparison date windows and their available as-of dates.
snapshot Publication coverage, projection status, snapshot identity and error flags.
ranking Published current/comparison summaries and ranking history.
serp Selected observation, organic_top_10 , SERP features, AI Overview evidence, events and counts.
page_conflict Page-conflict evidence supplied by the reader, or null when unavailable.
data_quality Reader coverage and confidence limitations, or null when unavailable.
evidence_limits Reader limits on evidence rows, or null when unavailable.
freshness policy , requested_at  and source_observed_at .
empty Whether the export lacks both a selected observation and current/comparison ranking history.
definitions Interpretation notes included with the saved report.

For example, this is a response fragment, not a complete report:


{
  "data_contract": "2026-09-19",
  "workspace_id": "ws_your_workspace_id",
  "freshness": {
    "policy": "latest_published",
    "requested_at": "2026-09-19 10:00:00 UTC",
    "source_observed_at": "2026-09-18 09:00:00"
  },
  "empty": false
}

Honor each history point's observation state. Missing observations are different from observed unranked results. A null position is not proof that a page is absent from the whole search engine.


organic_top_10  is bounded stored evidence, not the complete SERP. Features and AI Overview evidence belong to the selected observation; missing evidence does not prove a feature was absent. Preserve data_quality  alongside conclusions. A null page_conflict  is not a verified “no conflict” result. Read non-null findings with their evidence and limitations; overlapping pages alone do not establish harmful cannibalisation.


The API excludes cross-engine summaries. It does not export the full Search dashboard, same-page context, competitor series or AI analysis reports. Under explicit contract 2026-09-10 , page_conflict , data_quality  and evidence_limits  are omitted.


Charges, retention and access

A report with a selected observation or ranking history in either period costs 0.5 credits on first successful GET. A zero-unit published report is free. An unavailable selection may instead return a reader error; do not convert an error into an empty report. When the reader returns no publication, the export remains pending.


Repeated GETs of a paid export return identical data at zero additional charge. A new export is separately billable. Exports expire seven days after creation and are limited to 8 MiB.


Retrieval rechecks workspace and market access and that the queue still identifies the saved domain. Revocation can prevent retrieval even after an earlier payment.


Troubleshooting

  • 400 after following an old example: replace keyword text and market/group fields with keyword_id  and queue_id , and supply both dates.
  • 403 or inaccessible market: rediscover configurations for the correct workspace/website, check permissions and choose an engine available in the selected queue.
  • 503 or no evidence for the period: check that the selected configuration has published data in the requested current period. Persistent errors can require source-processing investigation. Retain meta.request_id .
  • Pending with wait_for_fresh : check the fixed date window and monitoring schedule. Creating an export does not schedule a search.
  • An old observation keeps returning: the export is frozen. Create a new export to read a later publication.
  • New fields are missing: check export.data_contract . The earlier contract omits them. A current-contract field with null means the reader did not supply a value.
  • 413: narrow the reporting window or scope and use a new idempotency key.

For shared authentication, credit, callback and retry errors, use API Access and API Keys.

Did this answer your question? Thanks for the feedback There was a problem submitting your feedback. Please try again later.