{"openapi":"3.1.0","info":{"title":"StoreRadar API","version":"1.0.0","summary":"Shopify store intelligence: search, count, enrich and export.","description":"Search and enrich a database of Shopify stores.\n\nFree accounts receive anonymized rows: the domain and contact values are\nmasked and counts below 25 are reported as \"fewer than 25\". The annual\nplan returns real domains, contacts and exact counts. A one-time pass\nunlocks exports while keeping search masked.\n\nSearch returns at most about 520 rows for one query. Use POST /exports\nfor a full segment."},"servers":[{"url":"https://www.storeradar.io/api/v1"}],"externalDocs":{"description":"Full reference","url":"https://www.storeradar.io/api/docs"},"security":[{"bearerAuth":[]}],"tags":[{"name":"Discovery","description":"Search, count and list filter values."},{"name":"Enrichment","description":"Look up one store by domain."},{"name":"Exports","description":"Bulk CSV delivery. Requires a general API token."}],"paths":{"/health":{"get":{"tags":["Discovery"],"operationId":"health","summary":"Check the token and discover its tier","description":"Unmetered. Call it first to learn whether this credential is unmasked, verified, and allowed to export.","responses":{"200":{"description":"Capabilities of the calling token","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["ok"]},"capabilities":{"type":"object","properties":{"unmasked":{"type":"boolean","description":"Real domains and contacts are returned."},"verified":{"type":"boolean","description":"Verified-email filters are available."},"exports":{"type":"boolean","description":"This credential may call the export endpoints."}}},"documentation_url":{"type":"string"}}}}}},"401":{"description":"Missing, unknown or expired token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/stores/search":{"get":{"tags":["Discovery"],"operationId":"searchStores","summary":"Search stores by filter","description":"Returns a page of at most 20 stores. Paginate with `cursor`; the cursor is opaque and carries the original filters, so it wins over any filters sent alongside it. At most about 500 rows are reachable for one query -- `has_more: true` with no `next_cursor` means that window is exhausted, not that the segment ended. Use POST /exports for the whole segment.","parameters":[{"name":"q","in":"query","required":false,"description":"Free-text search over store name and domain.","schema":{"type":"string"}},{"name":"countries","in":"query","required":false,"description":"ISO-3166 alpha-2 country codes, e.g. US, GB. Comma-separated for multiple values.","schema":{"type":"string"}},{"name":"languages","in":"query","required":false,"description":"Language codes, e.g. en, fr. Comma-separated for multiple values.","schema":{"type":"string"}},{"name":"industries","in":"query","required":false,"description":"Industry names (see list_filter_options). Comma-separated for multiple values.","schema":{"type":"string"}},{"name":"technologies","in":"query","required":false,"description":"Technology ids (see list_filter_options). Comma-separated for multiple values.","schema":{"type":"string"}},{"name":"shopify_apps","in":"query","required":false,"description":"Shopify app ids (see list_filter_options). Comma-separated for multiple values.","schema":{"type":"string"}},{"name":"has_email","in":"query","required":false,"description":"'valid' (verified email) requires the annual tier.","schema":{"type":"string"}},{"name":"has_phone","in":"query","required":false,"schema":{"type":"string"}},{"name":"has_blog","in":"query","required":false,"schema":{"type":"string"}},{"name":"password_protected","in":"query","required":false,"schema":{"type":"string"}},{"name":"product_count_min","in":"query","required":false,"schema":{"type":"integer"}},{"name":"product_count_max","in":"query","required":false,"schema":{"type":"integer"}},{"name":"collections_count_min","in":"query","required":false,"schema":{"type":"integer"}},{"name":"collections_count_max","in":"query","required":false,"schema":{"type":"integer"}},{"name":"articles_count_min","in":"query","required":false,"schema":{"type":"integer"}},{"name":"articles_count_max","in":"query","required":false,"schema":{"type":"integer"}},{"name":"pages_count_min","in":"query","required":false,"schema":{"type":"integer"}},{"name":"pages_count_max","in":"query","required":false,"schema":{"type":"integer"}},{"name":"storeradar_score_min","in":"query","required":false,"schema":{"type":"integer"}},{"name":"storeradar_score_max","in":"query","required":false,"schema":{"type":"integer"}},{"name":"seo_lite_score_min","in":"query","required":false,"schema":{"type":"integer"}},{"name":"seo_lite_score_max","in":"query","required":false,"schema":{"type":"integer"}},{"name":"tlds","in":"query","required":false,"description":"Top-level domains, e.g. com, co.uk. Comma-separated for multiple values.","schema":{"type":"string"}},{"name":"social_platforms","in":"query","required":false,"description":"Comma-separated for multiple values.","schema":{"type":"string"}},{"name":"pixels","in":"query","required":false,"description":"Tracking pixels present, e.g. facebook, tiktok, google. Comma-separated for multiple values.","schema":{"type":"string"}},{"name":"theme_name","in":"query","required":false,"description":"Shopify theme names. Comma-separated for multiple values.","schema":{"type":"string"}},{"name":"tags","in":"query","required":false,"description":"Comma-separated for multiple values.","schema":{"type":"string"}},{"name":"cursor","in":"query","required":false,"description":"Opaque continuation cursor from a prior response.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Rows per page, 1 to 20.","schema":{"type":"integer"}},{"name":"sort","in":"query","required":false,"description":"Sort column.","schema":{"type":"string","enum":["storeradar_score","seo_lite_score","product_count","collections_count","articles_count","pages_count","first_seen_at","last_detected_at","domain_created_at","domain_expires_at"]}},{"name":"sort_direction","in":"query","required":false,"description":"Sort direction.","schema":{"type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"A page of stores","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchResult"}}}},"401":{"description":"Missing, unknown or expired token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"invalid_cursor or invalid_params","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited or daily_limit_reached","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"description":"Seconds to wait before retrying. Honest, because the rate-limit windows are aligned to the clock rather than to the caller's first request.","schema":{"type":"integer"}}}}}}},"/stores/count":{"get":{"tags":["Discovery"],"operationId":"countStores","summary":"Count matching stores","description":"Returns no store rows, so it is the cheapest way to size a segment before searching or exporting.","parameters":[{"name":"q","in":"query","required":false,"description":"Free-text search over store name and domain.","schema":{"type":"string"}},{"name":"countries","in":"query","required":false,"description":"ISO-3166 alpha-2 country codes, e.g. US, GB. Comma-separated for multiple values.","schema":{"type":"string"}},{"name":"languages","in":"query","required":false,"description":"Language codes, e.g. en, fr. Comma-separated for multiple values.","schema":{"type":"string"}},{"name":"industries","in":"query","required":false,"description":"Industry names (see list_filter_options). Comma-separated for multiple values.","schema":{"type":"string"}},{"name":"technologies","in":"query","required":false,"description":"Technology ids (see list_filter_options). Comma-separated for multiple values.","schema":{"type":"string"}},{"name":"shopify_apps","in":"query","required":false,"description":"Shopify app ids (see list_filter_options). Comma-separated for multiple values.","schema":{"type":"string"}},{"name":"has_email","in":"query","required":false,"description":"'valid' (verified email) requires the annual tier.","schema":{"type":"string"}},{"name":"has_phone","in":"query","required":false,"schema":{"type":"string"}},{"name":"has_blog","in":"query","required":false,"schema":{"type":"string"}},{"name":"password_protected","in":"query","required":false,"schema":{"type":"string"}},{"name":"product_count_min","in":"query","required":false,"schema":{"type":"integer"}},{"name":"product_count_max","in":"query","required":false,"schema":{"type":"integer"}},{"name":"collections_count_min","in":"query","required":false,"schema":{"type":"integer"}},{"name":"collections_count_max","in":"query","required":false,"schema":{"type":"integer"}},{"name":"articles_count_min","in":"query","required":false,"schema":{"type":"integer"}},{"name":"articles_count_max","in":"query","required":false,"schema":{"type":"integer"}},{"name":"pages_count_min","in":"query","required":false,"schema":{"type":"integer"}},{"name":"pages_count_max","in":"query","required":false,"schema":{"type":"integer"}},{"name":"storeradar_score_min","in":"query","required":false,"schema":{"type":"integer"}},{"name":"storeradar_score_max","in":"query","required":false,"schema":{"type":"integer"}},{"name":"seo_lite_score_min","in":"query","required":false,"schema":{"type":"integer"}},{"name":"seo_lite_score_max","in":"query","required":false,"schema":{"type":"integer"}},{"name":"tlds","in":"query","required":false,"description":"Top-level domains, e.g. com, co.uk. Comma-separated for multiple values.","schema":{"type":"string"}},{"name":"social_platforms","in":"query","required":false,"description":"Comma-separated for multiple values.","schema":{"type":"string"}},{"name":"pixels","in":"query","required":false,"description":"Tracking pixels present, e.g. facebook, tiktok, google. Comma-separated for multiple values.","schema":{"type":"string"}},{"name":"theme_name","in":"query","required":false,"description":"Shopify theme names. Comma-separated for multiple values.","schema":{"type":"string"}},{"name":"tags","in":"query","required":false,"description":"Comma-separated for multiple values.","schema":{"type":"string"}}],"responses":{"200":{"description":"A match count","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CountResult"}}}},"401":{"description":"Missing, unknown or expired token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited or daily_limit_reached","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"description":"Seconds to wait before retrying. Honest, because the rate-limit windows are aligned to the clock rather than to the caller's first request.","schema":{"type":"integer"}}}}}}},"/filter_options":{"get":{"tags":["Discovery"],"operationId":"listFilterOptions","summary":"List valid filter values","description":"Omit `category` to list the categories. Technologies and apps return {name, id} pairs; pass the id into the corresponding filter.","parameters":[{"name":"category","in":"query","required":false,"description":"Which filter's values to list.","schema":{"type":"string","enum":["industries","countries","languages","technologies","shopify_apps","tlds","pixels","social_platforms","theme_name","tags"]}},{"name":"q","in":"query","required":false,"description":"Typeahead filter for the large lists.","schema":{"type":"string"}}],"responses":{"200":{"description":"Categories, or one category's values","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Missing, unknown or expired token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Unknown category","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/stores":{"get":{"tags":["Enrichment"],"operationId":"getStore","summary":"Look up one store by domain","description":"Returns the store when we have it. When we do not, the domain is queued for a crawl and the response is 202; poll the same URL. A domain we have crawled and found not to be a Shopify store answers 404.","parameters":[{"name":"domain","in":"query","required":true,"description":"Bare hostname, for example example.com.","schema":{"type":"string"}}],"responses":{"200":{"description":"The store","content":{"application/json":{"schema":{"type":"object","properties":{"store":{"$ref":"#/components/schemas/Store"}}}}}},"202":{"description":"Queued for analysis. Poll this URL again.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["processing"]},"message":{"type":"string"}}}}}},"401":{"description":"Missing, unknown or expired token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No store for that domain","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"invalid_domain","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited, daily_limit_reached or crawl_cap_reached","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"description":"Seconds to wait before retrying. Honest, because the rate-limit windows are aligned to the clock rather than to the caller's first request.","schema":{"type":"integer"}}}}}}},"/exports":{"post":{"tags":["Exports"],"operationId":"createExport","summary":"Start a scoped CSV export","description":"Requires an active pass and a general API token. Filters must actually narrow the scope; for the whole database use GET /exports/full. One export runs per account at a time.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"filters":{"type":"object","description":"Any filter accepted by /stores/search."}},"required":["filters"]}}}},"responses":{"202":{"description":"Accepted and queued","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Export"}}}},"401":{"description":"Missing, unknown or expired token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"No active pass, or the credential may not export","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"An export is already running; the body carries its export_id","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Filters do not narrow the scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited or daily_limit_reached","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"description":"Seconds to wait before retrying. Honest, because the rate-limit windows are aligned to the clock rather than to the caller's first request.","schema":{"type":"integer"}}}}}},"get":{"tags":["Exports"],"operationId":"listExports","summary":"List this caller's exports","responses":{"200":{"description":"Recent exports","content":{"application/json":{"schema":{"type":"object","properties":{"exports":{"type":"array","items":{"$ref":"#/components/schemas/Export"}}}}}}},"401":{"description":"Missing, unknown or expired token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The credential may not export","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/exports/{id}":{"get":{"tags":["Exports"],"operationId":"getExport","summary":"Poll one export","description":"Always 200 while the export exists. Branch on `status`, not on the HTTP code. `download_url` appears only once `status` is completed.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Current state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Export"}}}},"401":{"description":"Missing, unknown or expired token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The credential may not export","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No export with that id","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"410":{"description":"The file was deleted after the retention window","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/exports/full":{"get":{"tags":["Exports"],"operationId":"getFullDatabase","summary":"Download the whole database","description":"Returns a short-lived presigned link to the current nightly CSV. `variant` is `verified` for annual subscribers and verified add-on holders, `basic` otherwise.","responses":{"200":{"description":"A presigned download link","content":{"application/json":{"schema":{"type":"object","properties":{"download_url":{"type":"string"},"expires_at":{"type":"string","format":"date-time"},"variant":{"type":"string","enum":["basic","verified"]},"record_count":{"type":"integer"},"generated_at":{"type":["string","null"],"format":"date-time"}}}}}},"401":{"description":"Missing, unknown or expired token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"No active pass, or the credential may not export","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Daily link-issuance limit reached","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"description":"Seconds to wait before retrying. Honest, because the rate-limit windows are aligned to the clock rather than to the caller's first request.","schema":{"type":"integer"}}}},"503":{"description":"Today's file is still generating","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"description":"Seconds to wait before retrying. Honest, because the rate-limit windows are aligned to the clock rather than to the caller's first request.","schema":{"type":"integer"}}}}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"Send your API token as `Authorization: Bearer <token>`. `Authorization: token <token>` is also accepted. Export endpoints require a token you created yourself; tokens issued automatically for MCP or OAuth are read-only."}},"schemas":{"Store":{"type":"object","description":"A store, masked per the calling token's tier.","properties":{"domain":{"type":"string","description":"Store domain. Masked callers receive an anonymized form."},"masked":{"type":"boolean","description":"Whether identity and contact values are anonymized for this caller."},"storeradar_score":{"type":["integer","null"],"description":"Overall quality score, 0-100."},"seo_lite_score":{"type":["integer","null"],"description":"SEO health score, 0-100."},"industry":{"type":["string","null"],"description":"Detected industry."},"country_codes":{"type":"array","items":{"type":"string"},"description":"ISO country codes the store ships to or targets."},"languages":{"type":"array","items":{"type":"string"},"description":"Storefront languages."},"product_count":{"type":["integer","null"],"description":"Products found in the sitemap."},"collections_count":{"type":["integer","null"],"description":"Collections found in the sitemap."},"articles_count":{"type":["integer","null"],"description":"Blog articles found in the sitemap."},"pages_count":{"type":["integer","null"],"description":"Content pages found in the sitemap."},"has_blog":{"type":["boolean","null"],"description":"Whether the storefront publishes a blog."},"password_protected":{"type":"boolean","description":"Whether the storefront is behind a password."},"theme":{"type":["object","null"],"description":"{name, version} of the detected Shopify theme. A masked caller receives •••••• for a name that contains the store's own brand."},"technologies":{"type":"array","items":{"type":"string"},"description":"Detected third-party technologies."},"apps":{"type":"array","items":{"type":"string"},"description":"Detected Shopify apps."},"emails":{"type":"array","items":{"type":"string"},"description":"Contact emails. Starred for masked callers."},"phone_numbers":{"type":"array","items":{"type":"string"},"description":"Contact phone numbers. Starred for masked callers."},"social_media":{"type":["object","array","null"],"items":{"type":"string"},"description":"Platform to handle map. Masked callers receive platform names only."},"first_seen_at":{"type":["string","null"],"description":"RFC3339 timestamp of the first detection.","format":"date-time"},"last_detected_at":{"type":["string","null"],"description":"RFC3339 timestamp of the most recent successful crawl.","format":"date-time"},"domain_created_at":{"type":["string","null"],"description":"RFC3339 domain registration date from WHOIS.","format":"date-time"},"domain_expires_at":{"type":["string","null"],"description":"RFC3339 domain expiry date from WHOIS.","format":"date-time"},"people":{"type":"array","items":{"$ref":"#/components/schemas/Person"},"description":"Named contacts. Enrichment endpoint only, unmasked callers only."}},"required":["domain","masked","storeradar_score","seo_lite_score","industry","country_codes","languages","product_count","collections_count","articles_count","pages_count","has_blog","password_protected","theme","technologies","apps","emails","phone_numbers","social_media","first_seen_at","last_detected_at","domain_created_at","domain_expires_at"]},"Person":{"type":"object","description":"A named contact. Returned only by the enrichment endpoint, and only to unmasked callers.","properties":{"first_name":{"type":["string","null"],"description":"Contact's first name."},"last_name":{"type":["string","null"],"description":"Contact's last name."},"full_name":{"type":["string","null"],"description":"Contact's full name."},"position":{"type":["string","null"],"description":"Job title as published."},"email":{"type":["string","null"],"description":"Contact email address."},"seniority":{"type":["string","null"],"description":"junior, senior or executive."},"department":{"type":["string","null"],"description":"Detected department."},"linkedin":{"type":["string","null"],"description":"LinkedIn profile URL."},"twitter":{"type":["string","null"],"description":"X/Twitter handle."}}},"SearchResult":{"type":"object","properties":{"stores":{"type":"array","items":{"$ref":"#/components/schemas/Store"}},"total_count":{"type":"string","description":"ALWAYS a string label: an exact number, \"fewer than 25\", \"10000+\" or \"unknown\". Do not parse it as a number."},"exact_total_count":{"type":"integer","description":"Present ONLY when total_count is exact. Its absence is meaningful."},"next_cursor":{"type":"string","description":"Opaque; absent on the final page."},"has_more":{"type":"boolean","description":"More matches exist beyond this page. True with no next_cursor means the pagination window is exhausted."},"ignored_filters":{"type":"array","items":{"type":"string"},"description":"Filters your tier is not entitled to use. They were NOT applied, so the results are broader than you asked for."},"ignored_filters_message":{"type":"string"},"upgrade_url":{"type":"string","description":"Present only for masked callers."},"upgrade_message":{"type":"string"}},"required":["stores","total_count","has_more"]},"CountResult":{"type":"object","properties":{"count":{"type":"string","description":"Same string-label convention as total_count, and the same set: matches search can actually return for these filters. Rows that cannot be ranked by the default sort are unreachable through any cursor and are not counted."},"exact_count":{"type":"integer","description":"Present only when count is exact."},"ignored_filters":{"type":"array","items":{"type":"string"}},"ignored_filters_message":{"type":"string"},"upgrade_url":{"type":"string"},"upgrade_message":{"type":"string"}},"required":["count"]},"Export":{"type":"object","properties":{"id":{"type":"integer"},"status":{"type":"string","enum":["queued","processing","completed","failed","no_rows","entitlement_lapsed","purged"],"description":"Closed set. Branch on this, not on the HTTP status."},"created_at":{"type":"string","format":"date-time"},"completed_at":{"type":["string","null"],"format":"date-time"},"row_count":{"type":["integer","null"]},"truncated":{"type":"boolean","description":"The scope hit the 2000000-row ceiling, so the file is complete-looking but short."},"file_expires_at":{"type":"string","format":"date-time","description":"Present while downloadable."},"download_url":{"type":"string","description":"Presigned; present only when status is completed."}},"required":["id","status","truncated"]},"Error":{"type":"object","description":"Every non-2xx response on this API uses this shape.","properties":{"error":{"type":"string","enum":["unauthorized","invalid_domain","invalid_params","invalid_cursor","rate_limited","crawl_cap_reached","daily_limit_reached","forbidden","not_found","export_in_progress","export_purged","entitlement_lapsed","no_rows","generating","server_error"],"description":"Stable machine-readable code. Branch on this."},"message":{"type":"string","description":"Human-readable explanation."},"retry_after":{"type":"integer","description":"Seconds, on 429 and 503."},"export_id":{"type":"integer","description":"On 409 and 410."},"upgrade_url":{"type":"string","description":"On an entitlement 403."},"upgrade_message":{"type":"string"}},"required":["error","message"]}}}}