- Auth: API key (Authentication)
- Scope:
companies:read - Cost: 1 credit per store in the page; stores you unlocked from this app's list in the last 7 days are free.
Count first with GET /v1/apps/{slug}/companies/count (free), then page through only as many rows as you need with limit.
Stores whose latest healthy scan found the app, by domain. 1 credit per row. Scope companies:read.
Request
curl "https://api.installgraph.com/v1/apps/klaviyo/companies?country=GB&industry=Apparel&limit=2" \
-H "Authorization: Bearer $INSTALLGRAPH_API_KEY"
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
slug |
string | Yes | Example: klaviyo. |
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
country |
string | No | ISO 3166-1 alpha-2 country the store sells from (Shopify's Shopify.country). Example: US. |
region |
Region | No | A world region, i.e. its countries. Combined with country, both must hold. One of north-america, latin-america, europe, middle-east-africa, asia-pacific. |
industry |
string | No | A top-level industry (Apparel, which also matches stores placed at that level only) or a subcategory (Apparel/Footwear). GET /v1/industries lists them. Example: Apparel/Footwear. |
aov |
string | No | One or more typical order-value bands in USD, comma-separated (100-200,200-500). GET /v1/industries lists them. Example: 100-200. |
limit |
integer | No | 1–500. Default 100. |
cursor |
string | No | pagination.nextCursor from the previous page, unchanged, within 24 hours, with the same key's account and the same filters. |
Response
200. The example's stores are fictional.
{
"data": [
{
"domain": "example.net",
"name": "Example Knitwear",
"country": "GB",
"region": "europe",
"industry": {
"category": "Apparel",
"subcategory": "Knitwear",
"path": "/Apparel/Knitwear",
"confidence": "medium"
},
"pricePoint": {
"aovBand": "50-100",
"label": "$50–100",
"confidence": "medium",
"medianProductPriceUsd": 72,
"productPriceRangeUsd": [
58,
94
],
"productPricesSeen": 18
},
"currency": "GBP",
"status": "live",
"lastScannedAt": "2026-11-01T22:15:03.000Z",
"firstSeenAt": "2026-02-08T09:30:00.000Z",
"lastSeenAt": "2026-11-01T22:15:03.000Z",
"evidence": [
"webPixel"
]
},
{
"domain": "example.org",
"name": "Example Outdoor",
"country": "GB",
"region": "europe",
"industry": {
"category": "Apparel",
"subcategory": null,
"path": "/Apparel",
"confidence": "low"
},
"pricePoint": null,
"currency": "GBP",
"status": "live",
"lastScannedAt": "2026-10-31T18:02:51.000Z",
"firstSeenAt": "2026-05-19T11:47:20.000Z",
"lastSeenAt": "2026-10-31T18:02:51.000Z",
"evidence": [
"themeAppExtension",
"script"
]
}
],
"pagination": {
"nextCursor": "eyJrIjoiYXBwLWNvbXBhbmllcyIsImQiOiJleGFtcGxlLm9yZyJ9",
"hasMore": true
},
"meta": {
"requestId": "6f1c2a9e-4b7d-4e2a-9c51-0d3b8e7f2a14",
"creditsUsed": 2,
"creditsCharged": 2,
"creditsRemaining": 47,
"freeRepulls": 0
}
}
Fields
| Field | Type | Description |
|---|---|---|
data[].domain |
string | |
data[].name |
string | null | |
data[].country |
string | null | |
data[].region |
Region | null | One of north-america, latin-america, europe, middle-east-africa, asia-pacific. |
data[].industry |
Industry | null | Our reading of what the store sells, from its homepage, in the Store Leads taxonomy. |
data[].industry.category |
string | Example: Apparel. |
data[].industry.subcategory |
string | null | Null when the store fits a category but none of its subcategories (a general bookshop). Example: Footwear. |
data[].industry.path |
string | /Books & Literature alone when there is no subcategory. Example: /Apparel/Footwear. |
data[].industry.confidence |
string | null | One of high, medium, low. |
data[].pricePoint |
PricePoint | null | The store's typical order value, in USD bands so it reads the same in every country. Our own reading of the homepage: the product prices shown there (converted from the store's currency), and what is sold. |
data[].pricePoint.aovBand |
string | One of under-25, 25-50, 50-100, 100-200, 200-500, 500-1000, 1000-plus. |
data[].pricePoint.label |
string | Example: $100–200. |
data[].pricePoint.confidence |
string | null | One of high, medium, low. |
data[].pricePoint.medianProductPriceUsd |
integer | null | Median product price on the homepage, in USD. |
data[].pricePoint.productPriceRangeUsd |
integer[] | null | Interquartile range of homepage product prices, in USD. |
data[].pricePoint.productPricesSeen |
integer | |
data[].currency |
string | null | |
data[].status |
Status | The latest scan's verdict: live, password (behind a password page), closed (store unavailable), not_shopify (the domain no longer serves a Shopify store), or unreachable (we could not read the page this time). Apps are from the latest live scan (lastHealthyScanAt). One of live, password, closed, not_shopify, unreachable. |
data[].lastScannedAt |
string (date-time) | null | |
data[].firstSeenAt |
string (date-time) | null | |
data[].lastSeenAt |
string (date-time) | null | |
data[].evidence |
Evidence[] | One of webPixel, themeAppExtension, appProxy, customPixel, script, html. |
Every keyed response also carries meta (requestId, creditsUsed, creditsRemaining, freeRepulls) and the X-Credits-* and X-RateLimit-* headers. See Credits and Rate limits.
Lists page with limit and cursor. See Pagination.
Errors
| Status | Code | Meaning | What to do |
|---|---|---|---|
| 400 | invalid_request |
A parameter or body field is missing or malformed. | Fix the request; message names the field. Do not retry unchanged. |
| 400 | invalid_cursor |
The cursor is not one this endpoint issued (edited, truncated, or from another list). |
Pass pagination.nextCursor back unchanged, or start again without a cursor. |
| 401 | missing_api_key |
No key was sent. | Send Authorization: Bearer sfs_… or X-API-Key: sfs_…. |
| 401 | invalid_api_key |
The key is not one we issued. | Check for truncation or whitespace; keys are sfs_ plus 32 letters and digits. |
| 401 | api_key_revoked |
The key was revoked. | Make a new key at installgraph.com/account. |
| 402 | insufficient_credits |
The balance cannot cover one row or lookup. Nothing was charged. | Buy credits: error.offers.pack.buyUrl, or POST /v1/billing/purchase if agent purchases are on. |
| 402 | usage_cap_reached |
The account unlocked 40,000 distinct stores in the last 30 days. | Wait for the window to roll, or Talk to us: error.offers.talkToUs.url. |
| 403 | insufficient_scope |
The key lacks this endpoint's scope. | Use a key with the scope the endpoint lists (GET /v1/usage shows yours). |
| 403 | api_key_suspended |
The key is suspended. | Talk to us, quoting requestId. |
| 404 | not_found |
No such endpoint, app, or store (or not scanned yet). | Check the slug or domain. Store 404s are free within the lookup-miss allowance. |
| 429 | rate_limited |
Too many requests this minute. | Wait Retry-After seconds, then retry. |
All codes: Errors.