- Auth: API key (Authentication)
- Scope:
events:read - Cost: Free; never charged or retried.
Use it after creating a webhook to check your endpoint is reachable and your signature check passes. The sample has data.test: true and the domain example.com.
POSTs a signed sample (data.domain example.com, data.test: true) to the webhook's URL now and
reports what came back, so you can check your endpoint and signature check. Free, never retried.
Request
curl -X POST "https://api.installgraph.com/v1/webhooks/6731b2e4c9a1f20d8e4b7c15/test" \
-H "Authorization: Bearer $INSTALLGRAPH_API_KEY"
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
id |
string | Yes |
Response
200. The example's stores are fictional.
{
"data": {
"delivered": true,
"status": 204,
"error": null,
"body": {
"id": "test_6733d2f17be42c19f5a8e3a9",
"type": "technology.removed",
"subscriptionId": "6731b2e4c9a1f20d8e4b7c15",
"createdAt": "2026-11-10T12:01:00.000Z",
"data": {
"id": "test",
"type": "removed",
"domain": "example.com",
"app": {
"slug": "klaviyo",
"name": "Klaviyo",
"category": "email-sms"
},
"detectedAt": "2026-11-10T12:01:00.000Z",
"previousScanAt": "2026-11-03T12:01:00.000Z",
"lastSeenAt": null,
"country": "US",
"region": "north-america",
"industry": null,
"pricePoint": null,
"test": true
}
}
},
"meta": {
"requestId": "6f1c2a9e-4b7d-4e2a-9c51-0d3b8e7f2a14",
"creditsUsed": 0,
"creditsCharged": 0,
"creditsRemaining": 2480,
"freeRepulls": 0
}
}
Fields
| Field | Type | Description |
|---|---|---|
data.delivered |
boolean | |
data.status |
integer | null | |
data.error |
string | null | |
data.body |
WebhookPayload | |
data.body.id |
string | The delivery id; the same on every retry. Deduplicate on it. |
data.body.type |
string | One of technology.installed, technology.removed. |
data.body.subscriptionId |
string | |
data.body.createdAt |
string (date-time) | When this attempt was sent. |
data.body.data |
Event | |
data.body.data.id |
string | |
data.body.data.type |
string | One of installed, removed. |
data.body.data.domain |
string | |
data.body.data.app |
AppSummary | |
data.body.data.detectedAt |
string (date-time) | The scan that saw the change. |
data.body.data.previousScanAt |
string (date-time) | null | The healthy scan before it. |
data.body.data.lastSeenAt |
string (date-time) | null | For a removal, the last scan that still saw the app. |
data.body.data.country |
string | null | The store's current country. |
data.body.data.region |
Region | null | One of north-america, latin-america, europe, middle-east-africa, asia-pacific. |
data.body.data.industry |
Industry | null | Our reading of what the store sells, from its homepage, in the Store Leads taxonomy. |
data.body.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. |
Every keyed response also carries meta (requestId, creditsUsed, creditsRemaining, freeRepulls) and the X-Credits-* and X-RateLimit-* headers. See Credits and Rate limits.
Errors
| Status | Code | Meaning | What to do |
|---|---|---|---|
| 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. |
All codes: Errors.