- Auth: API key (Authentication)
- Scope:
events:read - Cost: 1 credit per distinct store in the page.
Use it to watch for changes: who started or stopped running an app since your last read. Save pagination.nextCursor and resume from it next time.
The change stream, oldest first, so you can read it forward: page with the cursor, and resume a later
read with since set to the last detectedAt you have (cursors last 24 hours). An
event is reported by the scan that saw the change: the change happened between previousScanAt
and detectedAt. A store's first scan reports no installs (we cannot say when they happened), and
removals are only inferred from a scan that read the whole live page. Each event carries the
store's current country, region and industry. With country, region or industry, a page can
hold fewer than limit events while hasMore is true. 1 credit per row. Scope events:read.
Request
curl "https://api.installgraph.com/v1/events?app=klaviyo&type=removed&since=2026-10-01T00%3A00%3A00Z&limit=1" \
-H "Authorization: Bearer $INSTALLGRAPH_API_KEY"
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
app |
string | No | Example: klaviyo. |
type |
string | No | One of installed, removed. |
since |
string (date-time) | No | Events detected at or after this time (ISO 8601). |
until |
string (date-time) | No | Events detected before this time (ISO 8601). |
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": [
{
"id": "evt_6720a4c3f1b2",
"type": "removed",
"domain": "example.com",
"app": {
"slug": "klaviyo",
"name": "Klaviyo",
"category": "email-sms"
},
"detectedAt": "2026-10-12T04:20:31.000Z",
"previousScanAt": "2026-10-05T03:58:10.000Z",
"lastSeenAt": "2026-10-05T03:58:10.000Z",
"country": "US",
"region": "north-america",
"industry": {
"category": "Apparel",
"subcategory": "Footwear",
"path": "/Apparel/Footwear",
"confidence": "high"
},
"pricePoint": {
"aovBand": "100-200",
"label": "$100–200",
"confidence": "medium",
"medianProductPriceUsd": 128,
"productPriceRangeUsd": [
95,
165
],
"productPricesSeen": 24
}
}
],
"pagination": {
"nextCursor": "eyJrIjoiZXZlbnRzIiwiaWQiOiJldnRfNjcyMGE0YzNmMWIyIn0",
"hasMore": true
},
"meta": {
"requestId": "6f1c2a9e-4b7d-4e2a-9c51-0d3b8e7f2a14",
"creditsUsed": 1,
"creditsCharged": 1,
"creditsRemaining": 46,
"freeRepulls": 0
}
}
Fields
| Field | Type | Description |
|---|---|---|
data[].id |
string | |
data[].type |
string | One of installed, removed. |
data[].domain |
string | |
data[].app |
AppSummary | |
data[].app.slug |
string | Example: klaviyo. |
data[].app.name |
string | Example: Klaviyo. |
data[].app.category |
Category | One of 28 values (see Data model). |
data[].app.kind |
string | shopify-app: an app installed from Shopify. web: a website technology installed outside Shopify, by pasting its tag into the theme or through a tag manager (Google Tag Manager, Meta Pixel, Hotjar). A vendor with both has one entry of each (meta-pixel and meta-facebook-instagram-app). One of shopify-app, web. |
data[].detectedAt |
string (date-time) | The scan that saw the change. |
data[].previousScanAt |
string (date-time) | null | The healthy scan before it. |
data[].lastSeenAt |
string (date-time) | null | For a removal, the last scan that still saw the app. |
data[].country |
string | null | The store's current country. |
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 |
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. |
| 429 | rate_limited |
Too many requests this minute. | Wait Retry-After seconds, then retry. |
All codes: Errors.