Alerts
Create and manage alerts for email, Slack, Discord, PagerDuty, and webhook notifications. Maximum 10 per team.
Alerts notify you when monitors detect issues. Each team can have up to 10 alerts with different notification strategies: email, webhook, Slack, Discord, or PagerDuty.
Sensitive data such as webhook URLs, signing secrets and PagerDuty integration keys are never returned in API responses for security.
Repeat Behaviour
cooldownMinutes controls how far apart repeat notifications are spaced while a monitor stays broken. For one outage an alert notifies:
Immediately on the first failing check. The first notification of an outage ignores
cooldownMinutesentirely, so no value you set can delay it.Again every
cooldownMinutesfor as long as the monitor stays broken. Nothing bounds the total number of notifications one outage produces.Once on recovery, when
notifyOnRecoveryistrue.
Repeats are additionally floored at five minutes: however low cooldownMinutes is, repeats are never sent more often than once every five minutes. A cooldownMinutes of 0 therefore means "as often as allowed" (at most 12 notifications an hour), not one notification per check. The floor does not apply to the recovery notification, which is spaced only by the cooldownMinutes you set.
Omitting cooldownMinutes defaults it to 60 — one hour — matching the default an alert created in the dashboard gets. Send 0 explicitly if you want repeats as often as the floor allows.
GET /api/v1/alerts
Returns the alerts for your team. This endpoint is paginated; see Pagination for how to walk the whole list.
Required scope: alerts:read
Query Parameters
perPageintegerResults per page, 1-200 (default: 50)
cursorstringPage to fetch, taken from a
Linkheader
Webhook URLs, secrets and integration keys stay out of config, so a Slack, Discord or PagerDuty alert reports only its strategy, and a webhook alert its strategy and signature scheme.
Errors (3)
| Status | Type | Meaning |
|---|---|---|
| 400 | bad-request | The request is malformed |
| 401 | unauthorized | The API key is missing or invalid |
| 403 | forbidden | The API key lacks the required scope |
Response fields (200)
dataobjectRequiredShow nested fields
alertsAlert[]RequiredShow nested fields
idstringRequirednamestringRequirednotifyOnRecoverybooleanRequiredcooldownMinutesintegerRequiredconfigobjectRequiredmonitorTypestring | nullRequiredMonitor type the alert covers; null covers every type One of
http,dns,tcp,cron,flow.monitorIdstring | nullRequiredThe one monitor the alert covers; null covers the whole type
createdAtintegerRequiredEpoch milliseconds
updatedAtintegerRequiredEpoch milliseconds
metaobjectRequiredShow nested fields
requestIdstringRequiredFormat: uuid.
timestampstringRequiredFormat: date-time.
paginationobjectRequiredShow nested fields
nextstring | nullRequiredCursor of the following page
prevstring | nullRequiredCursor of the preceding page
perPageintegerRequiredtotalinteger
cURL
Response
{
"data": {
"alerts": [
{
"id": "alt_abc123",
"name": "Email Alert",
"notifyOnRecovery": true,
"cooldownMinutes": 5,
"config": {
"strategy": "email",
"to": "ops@example.com",
"subjectPrefix": "[Uptime]"
},
"monitorType": null,
"monitorId": null,
"createdAt": 1771070400000,
"updatedAt": 1771070400000
},
{
"id": "alt_def456",
"name": "Slack Notifications",
"notifyOnRecovery": true,
"cooldownMinutes": 0,
"config": {
"strategy": "slack"
},
"monitorType": "http",
"monitorId": "mon_abc123",
"createdAt": 1771074000000,
"updatedAt": 1771074000000
}
]
},
"meta": {
"requestId": "3f2504e0-4f89-11d3-9a0c-0305e82c3301",
"timestamp": "2026-02-14T12:00:00.000Z",
"pagination": {
"next": null,
"prev": null,
"perPage": 25,
"total": 2
}
}
}POST /api/v1/alerts
Creates a new alert. The request body varies based on the notification strategy.
Required scope: alerts:write
Common Fields
namestringRequiredDisplay name for the alert, 1-255 characters
strategystringRequiredOne of:
email,webhook,slack,discord,pagerdutynotifyOnRecoverybooleanSend notification when monitor recovers (default:
true)cooldownMinutesintegerMinutes between repeat notifications while a monitor stays broken, 0-1440 (default:
60; repeats are floored at 5 minutes, and the first notification of an outage is never delayed — see Repeat Behaviour)monitorTypestringLimit the alert to one kind of monitor:
http,dns,tcp,cronorflow. Sent on its own, the alert covers every monitor of that kind, including ones created later.monitorIdstringLimit the alert to a single monitor. Sent together with
monitorType, the id is looked up in that kind's monitors; sent on its own it is read as an HTTP monitor, which is what it has always meant. The id carries the prefix of its kind:mon_(HTTP),dns_,tcpm_,cron_orflow_.
Strategy: Email
emailstringRequiredEmail address to notify
subjectPrefixstringPrefix for email subject lines, up to 100 characters
Strategy: Webhook
urlstringRequiredWebhook URL to POST notifications to
secretstringSecret every delivery is signed with, up to 255 characters
signaturestringstandard-webhooks(default) orlegacy. See Verifying Webhook Signatures for both
Strategy: Slack
webhookUrlstringRequiredSlack incoming webhook URL, starting
https://hooks.slack.com/
The incoming webhook posts to the channel it was created for in Slack.
Strategy: Discord
webhookUrlstringRequiredDiscord webhook URL, starting
https://discord.com/api/webhooks/
Strategy: PagerDuty
routingKeystringRequiredIntegration key of a PagerDuty service's Events API v2 integration, up to 255 characters, trimmed
Errors (8)
| Status | Type | Meaning |
|---|---|---|
| 400 | validation-error | The request failed validation |
| 400 | limit-exceeded | The team has reached its limit for this resource |
| 400 | idempotency-key-invalid | The Idempotency-Key header is not valid |
| 401 | unauthorized | The API key is missing or invalid |
| 403 | forbidden | The API key lacks the required scope |
| 404 | not-found | The resource does not exist |
| 409 | idempotency-key-in-use | A request with this idempotency key is still being processed |
| 422 | idempotency-key-reused | This idempotency key was already used for a different request |
Request body fields
strategy: emailobjectShow nested fields
strategy"email"RequiredemailstringRequiredFormat: email.
subjectPrefixstring0–100 characters.
namestringRequired1–255 characters.
notifyOnRecoverybooleanDefaulttruecooldownMinutesnumberDefault600–1440.
monitorTypestringDefaults to
httpbeside amonitorIdOne ofhttp,dns,tcp,cron,flow.monitorIdstring
strategy: webhookobjectShow nested fields
strategy"webhook"RequiredurlstringRequiredFormat: uri.
secretstring0–255 characters.
signaturestringDefault"standard-webhooks"standard-webhookssigns withwebhook-id,webhook-timestampandwebhook-signature: v1,<base64>;legacywithWebhook-Signature: sha256=<hex>One ofstandard-webhooks,legacy.namestringRequired1–255 characters.
notifyOnRecoverybooleanDefaulttruecooldownMinutesnumberDefault600–1440.
monitorTypestringDefaults to
httpbeside amonitorIdOne ofhttp,dns,tcp,cron,flow.monitorIdstring
strategy: slackobjectShow nested fields
strategy"slack"RequiredwebhookUrlstringRequiredA Slack incoming webhook URL on
https://hooks.slack.com/Format: uri.namestringRequired1–255 characters.
notifyOnRecoverybooleanDefaulttruecooldownMinutesnumberDefault600–1440.
monitorTypestringDefaults to
httpbeside amonitorIdOne ofhttp,dns,tcp,cron,flow.monitorIdstring
strategy: discordobjectShow nested fields
strategy"discord"RequiredwebhookUrlstringRequiredA Discord webhook URL on
https://discord.com/api/webhooks/Format: uri.namestringRequired1–255 characters.
notifyOnRecoverybooleanDefaulttruecooldownMinutesnumberDefault600–1440.
monitorTypestringDefaults to
httpbeside amonitorIdOne ofhttp,dns,tcp,cron,flow.monitorIdstring
strategy: pagerdutyobjectShow nested fields
strategy"pagerduty"RequiredroutingKeystringRequiredThe integration key of a PagerDuty service's Events API v2 integration 0–255 characters.
namestringRequired1–255 characters.
notifyOnRecoverybooleanDefaulttruecooldownMinutesnumberDefault600–1440.
monitorTypestringDefaults to
httpbeside amonitorIdOne ofhttp,dns,tcp,cron,flow.monitorIdstring
Response fields (201)
dataobjectRequiredShow nested fields
alertobjectRequiredShow nested fields
idstringRequirednamestringRequirednotifyOnRecoverybooleanRequiredcooldownMinutesintegerRequiredmonitorTypestring | nullRequiredMonitor type the alert covers; null covers every type One of
http,dns,tcp,cron,flow.monitorIdstring | nullRequiredThe one monitor the alert covers; null covers the whole type
configobjectRequiredShow nested fields
strategystringRequiredOne of
email,webhook,slack,discord,pagerduty.
createdAtintegerRequiredEpoch milliseconds
updatedAtintegerRequiredEpoch milliseconds
metaobjectRequiredShow nested fields
requestIdstringRequiredFormat: uuid.
timestampstringRequiredFormat: date-time.
Example Request (Email)
cURL
Example Request (Webhook)
cURL
Example Request (Slack)
cURL
Example Request (Discord)
cURL
Example Request (PagerDuty)
cURL
Response
Returns 201 Created. The alert's config reports only its strategy.
{
"data": {
"alert": {
"id": "alt_abc123",
"name": "Team Email Alert",
"notifyOnRecovery": true,
"cooldownMinutes": 5,
"monitorType": null,
"monitorId": null,
"config": { "strategy": "email" },
"createdAt": 1771070400000,
"updatedAt": 1771070400000
}
},
"meta": {
"requestId": "3f2504e0-4f89-11d3-9a0c-0305e82c3301",
"timestamp": "2026-02-14T12:00:00.000Z"
}
}GET /api/v1/alerts/:id
Returns a single alert by ID.
Required scope: alerts:read
Webhook URLs, secrets and integration keys stay out of config, so a Slack, Discord or PagerDuty alert reports only its strategy, and a webhook alert its strategy and signature scheme.
Errors (4)
| Status | Type | Meaning |
|---|---|---|
| 400 | validation-error | The request failed validation |
| 401 | unauthorized | The API key is missing or invalid |
| 403 | forbidden | The API key lacks the required scope |
| 404 | not-found | The resource does not exist |
Response fields (200)
dataobjectRequiredShow nested fields
alertobjectRequiredShow nested fields
idstringRequirednamestringRequirednotifyOnRecoverybooleanRequiredcooldownMinutesintegerRequiredconfigobjectRequiredmonitorTypestring | nullRequiredMonitor type the alert covers; null covers every type One of
http,dns,tcp,cron,flow.monitorIdstring | nullRequiredThe one monitor the alert covers; null covers the whole type
createdAtintegerRequiredEpoch milliseconds
updatedAtintegerRequiredEpoch milliseconds
metaobjectRequiredShow nested fields
requestIdstringRequiredFormat: uuid.
timestampstringRequiredFormat: date-time.
cURL
Response
{
"data": {
"alert": {
"id": "alt_abc123",
"name": "Team Email Alert",
"notifyOnRecovery": true,
"cooldownMinutes": 5,
"monitorType": null,
"monitorId": null,
"config": {
"strategy": "email",
"to": "alerts@example.com",
"subjectPrefix": "[Uptime]"
},
"createdAt": 1771070400000,
"updatedAt": 1771070400000
}
},
"meta": {
"requestId": "3f2504e0-4f89-11d3-9a0c-0305e82c3301",
"timestamp": "2026-02-14T12:00:00.000Z"
}
}PATCH /api/v1/alerts/:id
Updates an existing alert with a JSON merge patch.
Required scope: alerts:write
Request Body
Every field POST /api/v1/alerts accepts is accepted here, with the same limits. Include only the fields you want to change:
nullresetsnotifyOnRecovery,cooldownMinutesandsignatureto their defaults, and clearssubjectPrefixandsecret.{"signature": "standard-webhooks"}moves a webhook alert created with the legacy signature onto Standard Webhooks.name,strategyand a strategy's required setting (email,url,webhookUrlorroutingKey) cannot be removed.A channel setting changes on its own, keeping the others:
{"email": "oncall@example.com"}keeps the alert'ssubjectPrefix.Switching
strategyneeds the new strategy's required setting in the same patch,{"strategy": "discord", "webhookUrl": "..."}, and drops the previous strategy's settings.
monitorType and monitorId are the alert's scope, and they move as a pair: change either one and both are rewritten, so narrowing an alert to a whole kind of monitor cannot leave the previous monitor's id behind it. Mention neither and the scope is left exactly as it is.
{"monitorType": "dns"}— every DNS monitor{"monitorType": "dns", "monitorId": "..."}— that one DNS monitor{"monitorId": null}or{"monitorType": null}— back to team-wide{"monitorId": "..."}— that one HTTP monitor
A monitorId that does not belong to the team, or that belongs to a different kind of monitor than monitorType names, answers a 404 not-found problem.
Update With PUT
PUT /api/v1/alerts/:id updates name, notifyOnRecovery, cooldownMinutes, monitorType and monitorId, for integrations written before PATCH existed. Any other field, including strategy and the channel settings, is ignored, so the channel changes only through PATCH. A field you leave out keeps its value, and null is refused everywhere except monitorId. Sending either scope field rewrites both, as listed above: {"monitorType": "dns"} also clears a previous monitor id.
Required scope: alerts:write
Errors (4)
| Status | Type | Meaning |
|---|---|---|
| 400 | validation-error | The request failed validation |
| 401 | unauthorized | The API key is missing or invalid |
| 403 | forbidden | The API key lacks the required scope |
| 404 | not-found | The resource does not exist |
Request body fields
namestring1–255 characters.
notifyOnRecoverybooleancooldownMinutesnumber0–1440.
monitorTypestringOne of
http,dns,tcp,cron,flow.monitorIdstring | null
Response fields (200)
dataobjectRequiredShow nested fields
alertobjectRequiredShow nested fields
idstringRequirednamestringRequirednotifyOnRecoverybooleanRequiredcooldownMinutesintegerRequiredmonitorTypestring | nullRequiredMonitor type the alert covers; null covers every type One of
http,dns,tcp,cron,flow.monitorIdstring | nullRequiredThe one monitor the alert covers; null covers the whole type
configobjectRequiredShow nested fields
strategystringRequiredOne of
email,webhook,slack,discord,pagerduty.
createdAtintegerRequiredEpoch milliseconds
updatedAtintegerRequiredEpoch milliseconds
metaobjectRequiredShow nested fields
requestIdstringRequiredFormat: uuid.
timestampstringRequiredFormat: date-time.
cURL
Response
The alert's config reports only its strategy.
{
"data": {
"alert": {
"id": "alt_abc123",
"name": "Updated Alert Name",
"notifyOnRecovery": false,
"cooldownMinutes": 10,
"monitorType": null,
"monitorId": null,
"config": { "strategy": "email" },
"createdAt": 1771070400000,
"updatedAt": 1771074000000
}
},
"meta": {
"requestId": "3f2504e0-4f89-11d3-9a0c-0305e82c3301",
"timestamp": "2026-02-14T12:00:00.000Z"
}
}DELETE /api/v1/alerts/:id
Deletes an alert.
Required scope: alerts:write
Errors (4)
| Status | Type | Meaning |
|---|---|---|
| 400 | validation-error | The request failed validation |
| 401 | unauthorized | The API key is missing or invalid |
| 403 | forbidden | The API key lacks the required scope |
| 404 | not-found | The resource does not exist |
Response fields (200)
dataobjectRequiredShow nested fields
deletedtrueRequired
metaobjectRequiredShow nested fields
requestIdstringRequiredFormat: uuid.
timestampstringRequiredFormat: date-time.
cURL
Response
Returns 200 OK:
{
"data": {
"deleted": true
},
"meta": {
"requestId": "3f2504e0-4f89-11d3-9a0c-0305e82c3301",
"timestamp": "2026-02-14T12:00:00.000Z"
}
}GET /api/v1/alerts/:id/events
Returns the event history for an alert, newest first. The history is paginated; see Pagination for how to walk further back.
Required scope: alerts:read
Query Parameters
perPageintegerResults per page, 1-200 (default: 50)
cursorstringPage to fetch, taken from a
Linkheader
Event Fields
idstringUnique event identifier
alertIdstringThe alert the event belongs to
monitorIdstringThe monitor that caused the event
eventTypestringWhat the monitor did:
down,up, ordegradedstatusstringDelivery outcome:
pendingwhile it waits to be sent, thensent,skipped_cooldown,skipped_cap, orfailedsentAtintegerUnix timestamp in milliseconds of when the notification was sent
errorMessagestring | nullWhy delivery failed, or
nullwhen it succeededcreatedAtintegerUnix timestamp in milliseconds of when the event was recorded
Errors (5)
| Status | Type | Meaning |
|---|---|---|
| 400 | bad-request | The request is malformed |
| 400 | validation-error | The request failed validation |
| 401 | unauthorized | The API key is missing or invalid |
| 403 | forbidden | The API key lacks the required scope |
| 404 | not-found | The resource does not exist |
Response fields (200)
dataobjectRequiredShow nested fields
eventsAlertEvent[]RequiredShow nested fields
idstringRequiredalertIdstringRequiredmonitorIdstringRequiredeventTypestringRequiredOne of
down,up,degraded.statusstringRequiredOne of
pending,sent,skipped_cooldown,skipped_cap,failed.sentAtintegerRequiredEpoch milliseconds
errorMessagestring | nullRequiredcreatedAtintegerRequiredEpoch milliseconds
metaobjectRequiredShow nested fields
requestIdstringRequiredFormat: uuid.
timestampstringRequiredFormat: date-time.
paginationobjectRequiredShow nested fields
nextstring | nullRequiredCursor of the following page
prevstring | nullRequiredCursor of the preceding page
perPageintegerRequiredtotalinteger
cURL
Response
{
"data": {
"events": [
{
"id": "evt_abc123",
"alertId": "alt_abc123",
"monitorId": "mon_def456",
"eventType": "down",
"status": "sent",
"sentAt": 1771072200000,
"errorMessage": null,
"createdAt": 1771072200000
},
{
"id": "evt_def456",
"alertId": "alt_abc123",
"monitorId": "mon_def456",
"eventType": "up",
"status": "sent",
"sentAt": 1771072500000,
"errorMessage": null,
"createdAt": 1771072500000
}
]
},
"meta": {
"requestId": "3f2504e0-4f89-11d3-9a0c-0305e82c3301",
"timestamp": "2026-02-14T12:00:00.000Z",
"pagination": {
"next": "eyJkIjoiYWZ0ZXIi",
"prev": null,
"perPage": 10
}
}
}