Integrations
Configure where ExitProbe sends notifications — webhook, Slack, Discord, Telegram, or email — and which events each one should fire on.
Types
webhook — POSTs a signed JSON payload to any URL you control (see Webhooks & Events for the exact payload shape and HMAC signature verification). slack and discord post to an incoming webhook URL from those apps. telegram sends via a bot token + chat id. email sends to one address.
https://example.com/…/1a2b, never the full value again. Only Rotate Secret returns a plaintext secret, and only once.is_active: false) and the account owner is emailed once about it — check last_error and failure_count on List Integrations, or the Delivery History endpoint below, to diagnose why./integrations/metaThe canonical list of integration types (with their config fields) and events you can subscribe to — build your integration-creation UI from this rather than hardcoding it.
curl -X GET "https://api.exitprobe.com/api/v1/integrations/meta" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/json"{
"success": true,
"data": {
"types": [
{ "type": "webhook", "label": "Webhook", "fields": [
{ "key": "url", "label": "URL", "type": "url", "required": true },
{ "key": "secret", "label": "Signing Secret", "type": "password", "required": false },
{ "key": "headers", "label": "Extra Headers (JSON)", "type": "textarea", "required": false }
] },
{ "type": "email", "label": "Email", "fields": [{ "key": "email", "label": "Email Address", "type": "email", "required": true }] },
{ "type": "telegram", "label": "Telegram", "fields": [
{ "key": "bot_token", "label": "Bot Token", "type": "password", "required": true },
{ "key": "chat_id", "label": "Chat ID", "type": "text", "required": true }
] },
{ "type": "slack", "label": "Slack", "fields": [{ "key": "webhook_url", "label": "Webhook URL", "type": "password", "required": true }] },
{ "type": "discord", "label": "Discord", "fields": [{ "key": "webhook_url", "label": "Webhook URL", "type": "password", "required": true }] }
],
"events": [
{ "event": "monitor.down", "label": "Monitor Down" },
{ "event": "monitor.up", "label": "Monitor Up" },
{ "event": "monitor.degraded", "label": "Monitor Degraded" },
{ "event": "monitor.ip_mismatch", "label": "Exit IP Mismatch" },
{ "event": "incident.created", "label": "Incident Created" },
{ "event": "incident.resolved", "label": "Incident Resolved" },
{ "event": "incident.correlated", "label": "Incidents Correlated" }
]
}
}/integrations- •Sensitive config fields (secrets, tokens, webhook URLs) are always masked in this response — the plaintext only ever appears once, from Rotate Secret.
curl -X GET "https://api.exitprobe.com/api/v1/integrations" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/json"{
"success": true,
"data": {
"integrations": [
{
"id": 1, "project_id": null, "type": "webhook", "name": "My Webhook", "is_active": true,
"events": ["monitor.down", "monitor.up"],
"config": { "url": "https://example.com/…/1a2b", "secret": "whsec_…d4f9" },
"last_triggered_at": "2026-09-26T00:00:00Z", "last_status": "success", "last_error": null,
"failure_count": 0, "deliveries_count": 12
}
],
"usage": { "used": 1, "limit": 3, "remaining": 2, "percentage": 33, "is_unlimited": false, "is_exhausted": false }
}
}/integrationsproject_id null makes this an account-wide integration (also required for VPS events, since a VPS has no project).
| type* | string | webhook, email, telegram, slack, or discord. |
| name* | string | Max 255 chars. |
| project_id | integer | Omit for account-wide. |
| is_active | boolean | Default true. |
| events* | array<string> | At least 1 — see Webhooks & Events for the full catalogue. |
| config* | object | Fields depend on type — see Integration Types & Events above. |
- •422 if your plan doesn't include integrations, or you're at your plan's integration limit.
- •A `url`/`webhook_url` config value must be a public address — internal/loopback/link-local URLs are rejected (SSRF guard).
curl -X POST /api/v1/integrations \
-H "Authorization: Bearer 1|K7f9XyZaQ2mN8pL4vR6tW1sJ0hD3cB5gA7eF9uI2oY4" \
-H "Content-Type: application/json" \
-d '{
"type": "webhook",
"name": "My Webhook",
"events": ["monitor.down", "monitor.up", "incident.created"],
"config": {"url": "https://example.com/hooks/exitprobe"}
}'{ "success": true, "message": "Integration created successfully.", "data": { "integration": { "id": 1, "type": "webhook", "name": "My Webhook", "events": ["monitor.down", "monitor.up", "incident.created"] } } }/integrations/{id}curl -X GET "https://api.exitprobe.com/api/v1/integrations/{id}" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/json"/integrations/{id}All fields optional (partial update). Echoing back a masked secret unchanged (e.g. resubmitting the exact masked value shown by List) keeps the real stored value rather than overwriting it with the mask string.
curl -X PUT "https://api.exitprobe.com/api/v1/integrations/{id}" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/json"/integrations/{id}curl -X DELETE "https://api.exitprobe.com/api/v1/integrations/{id}" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/json"/integrations/{id}/testDelivers a synthetic sample event (a fake "Sample Server (test)" monitor going down) through this integration, so you can confirm it's wired up correctly.
curl -X POST "https://api.exitprobe.com/api/v1/integrations/{id}/test" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/json"{ "success": true, "message": "Test notification delivered successfully.", "data": { "delivery": { "id": 999, "status": "success", "response_code": 200, "duration_ms": 184 } } }/integrations/{id}/rotate-secretWebhook integrations only. Generates a new HMAC signing secret. The previous secret keeps working for 24 hours (both are used to sign deliveries during that window) so you have time to update your endpoint.
- •422 "Secret rotation only applies to webhook integrations." for any other type.
- •The plaintext secret is returned exactly once, here.
curl -X POST "https://api.exitprobe.com/api/v1/integrations/{id}/rotate-secret" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/json"{
"success": true,
"message": "Secret rotated. The previous secret stays valid for 24 hours so you can update your endpoint.",
"data": { "secret": "whsec_9f8e7d6c5b4a3210...", "secondary_secret_expires_at": "2026-09-27T00:00:00Z" }
}/integrations/deliveriesEvery attempted notification across all your integrations (or filtered to one).
| per_page | integer | Default 50, max 200. |
| integration_id | integer | Filter to one integration. |
curl -X GET "https://api.exitprobe.com/api/v1/integrations/deliveries" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/json"{
"success": true,
"data": {
"deliveries": [
{ "id": 999, "integration_id": 1, "integration_name": "My Webhook", "integration_type": "webhook", "event": "monitor.down", "monitor_id": 42, "monitor_name": "US-East WG1", "status": "success", "response_code": 200, "error": null, "duration_ms": 184, "created_at": "2026-09-26T00:00:00Z" }
]
}
}