Managing your API keys

Use the Wheremore API to export published Search Performance, AI Visibility and Conversion Performance reports, or accessible Action Board tasks, into your own application. Open API Access to manage keys and find your public workspace ID.


This developer guide describes API v2, with default data contract 2026-09-19 . The data contract identifies the response format. GET https://app.wheremore.com/api/v2  returns the server's default contract and advertised endpoints without requiring authentication. Check that contract before adopting these examples.


The base URL is https://app.wheremore.com/api/v2 . Export requests read stored information; they do not trigger searches, AI responses, analysis or conversion processing. They do not create or edit Action Board tasks.


Create and protect an API key

  1. Sign in and open API Access.
  2. In API Keys, select Generate new key.
  3. Enter Key name, then choose Expiry: No expiry, 30 days, 90 days or 1 year.
  4. Select Generate key and copy the complete secret immediately. It is shown once; the list subsequently shows identifying metadata rather than the complete secret.
  5. Store it in your server's secret manager or protected environment. Use separate named keys for independent integrations.

The default limit is five active, unexpired keys per user. Select Revoke on an active key to stop requests using it. Revocation cannot recover a lost secret; generate a replacement instead. Key access follows the owning user's resource permissions. Do not expose keys in browser code, URLs or logs.


Under Your Workspaces and Markets, copy the public ws_...  workspace ID. This is different from a numeric internal workspace ID. Send it as workspace_id  when creating an export or discovering markets. Export retrieval needs only the export ID and authentication.


Authentication

Send either header:


X-API-Key: sk_live_YOUR_COMPLETE_SECRET

Authorization: Bearer sk_live_YOUR_COMPLETE_SECRET

If both are supplied, X-API-Key  takes precedence. Examples below assume WHEREMORE_API_KEY  is already set securely. Replace every sample workspace and resource ID with your own.


Choose an endpoint

Method and path, relative to the base URL Purpose
GET /markets?workspace_id=...&domain=... Discover search queues and enabled engine identifiers for a website. No credit charge.
POST /exports/serp Save one keyword/queue/engine report for a date range.
POST /exports/visibility Save project metrics and one page of monitored answers.
POST /exports/conversions Save a website report, optionally narrowed to a conversion path.
POST /exports/action-board Save one page of active tasks.
GET /exports/{export_id} Poll or retrieve a saved export.

Use the Search Performance API, AI Visibility API, Conversions API and Action Board API guides for request fields and data definitions. There are no public keyword, persona, project or conversion-path listing endpoints in this export API. Obtain those IDs from the corresponding Wheremore configuration or your workspace administrator; do not substitute display names unless the endpoint explicitly accepts them.


Create and retrieve an export

  1. Send a JSON POST to the chosen export endpoint. Include Content-Type: application/json , authentication and Idempotency-Key .
  2. Save the returned export.id , export.status_url  and export.expires_at . POST returns metadata, not exported data, and does not charge credits. HTTP 201 means ready; HTTP 202 means pending.
  3. GET the returned export ID. A pending export returns HTTP 202 without a charge. Use a modest polling interval and back off on transient errors.
  4. A successful ready GET returns HTTP 200 with data . The first retrieval of non-empty data charges once. Subsequent GETs return the same saved data without another charge.

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

A saved export is immutable: later changes in Wheremore do not refresh its data. Create a new export with a new idempotency key for a later snapshot. Exports expire seven days after creation, including time spent pending. Retrieval after expiry returns HTTP 410 when access checks succeed. No endpoint extends retention or refreshes a saved export.


Retry POST safely

Idempotency-Key  is an HTTP header, not a JSON field. It must contain 8–128 characters drawn from letters, digits, . , _ , : , /  and - .


Reuse the same key, API credential and identical request when retrying a POST after a network failure. Idempotency is scoped to the API key. Changing the export type or request while reusing that key returns HTTP 409 idempotency_conflict . Retrying an existing pending job returns 202; an existing non-pending job can return 200, so inspect export.status .


Use a new key for each new report or page. Do not rotate API credentials in the middle of a POST retry and assume the original idempotency key will prevent another export. Expired export records do not reserve an idempotency key forever.


Dates and contracts

Search, Visibility and Conversions require date_from  and date_to  in YYYY-MM-DD  format. Dates are inclusive UTC dates. The period must cover 1–366 days and cannot end in the future. Action Board uses task filters instead of reporting dates.


Omit data_contract  for the default 2026-09-19 , or specify it explicitly. Search, Visibility and Conversions also accept 2026-09-10 ; Search then omits the newer page-conflict, data-quality and evidence-limit fields. Newly created Action Board exports accept only 2026-09-19 .


Saved ready exports keep their original contract and data. Check export.data_contract  on retrieval. Unknown request fields are rejected. Treat omitted fields and explicit values as different requests for idempotency purposes.


Credits and billing states

Export Charge on first successful non-empty GET
Search Performance 0.5 credits per report. Ranking history can make a report billable even without a SERP observation.
AI Visibility 0.5 credits per distinct conversation/persona pair on the returned answer page.
Conversions 0.5 credits per report with starting sessions in either returned period, even if conversions are zero.
Action Board 0.5 credits per non-empty task page, containing up to 100 tasks.

POSTs, pending polls, market discovery, readiness callbacks and empty exports do not consume export credits. Charges use the workspace account's shared balance.


billing_status Meaning
not_charged No retrieval charge has completed. Common in creation/pending responses.
deducted This retrieval completed the charge.
already_deducted The saved export was already charged; this response uses zero additional credits.
not_charged_empty_export The export has zero billable units.

credits_used  describes this response's charge. balance  can contain the post-charge balance on first paid retrieval. Repeated paid retrievals return balance: null ; do not treat a historical balance as the current account balance. If credits are insufficient, resolve the balance issue and retry the same export GET before expiry.


Response envelope

This illustrative ready response uses an intentionally abbreviated data  object. Each endpoint guide describes its contents.


{
  "success": true,
  "export": {
    "id": "exp_0123456789abcdef0123456789abcdef",
    "type": "serp",
    "data_contract": "2026-09-19",
    "status": "ready",
    "created_at": "2026-09-19T10:00:00Z",
    "ready_at": "2026-09-19T10:00:00Z",
    "expires_at": "2026-09-26T10:00:00Z",
    "status_url": "/api/v2/exports/exp_0123456789abcdef0123456789abcdef"
  },
  "credits_used": 0.5,
  "balance": 99.5,
  "billing_status": "deducted",
  "data": {},
  "meta": {
    "request_id": "0123456789abcdef",
    "api_version": "v2",
    "data_contract": "2026-09-19",
    "duration_ms": 42
  }
}

An export can be ready while its underlying report says it is updating: readiness means a usable snapshot was saved, not that all source processing has finished. Keep source publication/coverage fields when displaying data. Nested metric structures come from the published reporting readers; honor their null values, units and availability flags, and tolerate additional response properties.


Optional readiness callbacks

Supply callback_url  in the creation JSON to receive a JSON POST when the export is ready. It must be an absolute public HTTPS URL, at most 500 characters, using port 443 with no embedded credentials or fragment. Private/local addresses and redirects are not supported.


{
  "event": "export.ready",
  "export": {
    "id": "exp_0123456789abcdef0123456789abcdef",
    "type": "serp",
    "status": "ready",
    "status_url": "/api/v2/exports/exp_0123456789abcdef0123456789abcdef",
    "ready_at": "2026-09-19T10:00:00Z",
    "expires_at": "2026-09-26T10:00:00Z"
  }
}

Callbacks contain metadata only: no exported data, workspace field or payment confirmation. They have no API-provided signature header. Treat them as a notification to check an export your application already created, then retrieve it using your stored ID, the known API host and authenticated GET. Do not trust a callback-supplied URL for arbitrary outbound requests.


Return 2xx  promptly; delivery has a ten-second timeout and up to three attempts. Handle duplicates safely. Scheduling delays and delivery failures are possible, so retain polling as a fallback. There is no separate failure-notification event.


Access checks and limits

Retrieval is restricted to the user who created the export; a replacement key for that same user can retrieve it while authorized. Every GET rechecks workspace access. Visibility also checks the project and any selected persona; Conversions checks the domain; Search checks the current market and saved domain; Action Board checks projects and tags represented in the payload. An earlier successful charge does not override later access revocation.


The default rate limit is 60 requests per minute per key; a configured key limit can differ. Authenticated discovery and polling requests count too. On HTTP 429, wait for Retry-After  seconds before retrying.


Saved payloads are limited to 8 MiB. On HTTP 413, reduce the answer/task page size or narrow the applicable filters and create a new export. A reporting reader can impose its own capacity limit before the saved-payload limit is reached.


Errors and recovery

Errors contain success: false , an error  object with numeric code , string type  and message , plus meta.request_id , api_version  and data_contract . Log the HTTP status and request ID; do not log the secret key.


HTTP status What to do
400 Correct JSON, required fields, filter values, dates or unsupported contract.
401 Check the complete key and header; replace expired or revoked keys.
402 Resolve insufficient credits, then retry the same GET.
403 Check resource permissions. export_access_revoked  means saved-export access no longer passes.
404 Check the route, export ID and resource/workspace identifiers.
405 Use the method shown for the endpoint.
409 Resolve idempotency_conflict ; retry export_retrieval_in_progress  shortly. For export_scope_unverifiable , create a new export because the old record lacks verifiable resource scope.
410 The saved export expired. Create a new one.
413 Narrow the export and use a new idempotency key.
422 The job failed to prepare. Check source processing; retain the request ID for support.
429 Respect Retry-After .
500 or 503 Back off and retry transient failures. Persistent errors can indicate missing reporting services or capacity limits; narrow scope where possible and contact support with the request ID.

A ready export does not change when polled repeatedly. A pending export cannot make progress until its source reporting is available; creation itself does not schedule new monitoring. When seeking support, provide the endpoint, export ID, workspace ID, UTC time, HTTP status and request ID, never the API secret.

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