Payload reference
Every request to a Webhook carries one JSON body, version 1 of the payload. This page lists everything in it. The request’s headers, and when we send a message again, are on Webhooks.
What version 1 promises
Section titled “What version 1 promises”- Every field is always there. A field that does not apply is
null, never missing. - New things can be added without notice: a field, an
event, amessageor anerrorKind. Ignore what you do not know. - Anything else is a new version: removing a field, renaming it, or changing what it holds.
reason,sentenceanddetailare words for a person, and their wording can change. Branch onerrorKindorstoppingPoint, never on that text.- One message can reach your endpoint more than once: when we send it again after your endpoint did not answer in time, and when someone presses Send again. It keeps its
id, so skip anidyou have already handled. - Times are in UTC, written as ISO 8601 with milliseconds. Every identifier starts with what it names, such as
mon_for a Monitor andinc_for an Incident.
Messages
Section titled “Messages”The message field says what happened:
message | What happened |
|---|---|
down | An Incident opened on one of the Monitor's Checks. |
flapping | An Incident opened soon after the one before it ended. It stays open while the Monitor goes up and down, and no up follows until the Monitor stays up. |
up | The Incident ended because its Check passes again. |
correction | The Incident was reported in error, and is taken back. It leaves your uptime figure. |
paused | The Incident ended because someone paused the Monitor. |
disabled | The Incident ended because someone turned its Check off. |
resolved | Someone resolved the Incident by hand. If the Monitor still fails, a new one opens. |
regional_outage | One location cannot reach the Monitor while the others can. It is not an Incident, and it never counts against your uptime. |
regional_recovery | That location reaches the Monitor again. |
regional_correction | The Regional outage was reported in error, and is taken back. |
warning | A warning was announced, such as a certificate close to expiry. |
test | A test, sent when you add the Webhook, press Send test, or turn it back on. It is about no Monitor event. |
Fields
Section titled “Fields”| Field | Type | What it holds |
|---|---|---|
version | number | The payload's version. It changes only when a field is removed, renamed or changes what it means. Always 1. |
id | string | The message's identifier. It is the same on every attempt to send this message, and on Send again, so your endpoint can skip a message it has already handled. |
repeat | integer | Always 1: a Webhook gets each message once, and no Repeat alerts. |
event | string or null | The event the message is about. null for correction, paused, disabled, resolved and test, which are about no event. One of uptime.failed, uptime.recovered, certificate.failed, certificate.recovered, domain.failed, domain.recovered, certificate.expiring, domain.expiring, domain.unreadable, performance.degraded, uptime.family_failing, uptime.regional_outage. |
message | string | Which message this is. Each is described under Messages, above. One of down, flapping, up, correction, paused, disabled, resolved, regional_outage, regional_recovery, regional_correction, warning, test. |
createdAt | time | When the message was made. It is the same on every attempt to send it. |
project | object | The Project the Monitor is in. |
project.id | string | The Project's identifier. |
project.name | string | The Project's name. |
monitor | object | The Monitor the message is about. |
monitor.id | string | The Monitor's identifier. |
monitor.name | string | The Monitor's name. |
monitor.type | string | The Monitor's type. One of http, tcp, ping, heartbeat. |
monitor.target | string | What the Monitor checks, as you entered it. |
check | object or null | The Check the message is about. null for a test. |
check.id | string | The Check's identifier. |
check.type | string | The Check's type. One of uptime, performance, certificate, domain. |
incident | object or null | The Incident the message is about. null on a message about a Regional outage, a warning or a test. |
incident.id | string | The Incident's identifier. Every message about one Incident carries the same one. |
incident.openedAt | time | When the Incident opened. |
incident.resolvedAt | time or null | When the Incident ended. null while it is open. |
incident.resolution | string or null | How the Incident ended: recovered when the Monitor came back, retracted when it was reported in error, check_disabled when its Check was turned off, monitor_paused when the Monitor was paused, manually_resolved when someone resolved it, and suspended when your Plan stopped covering the Monitor. null while it is open. One of recovered, retracted, check_disabled, monitor_paused, suspended, manually_resolved. |
incident.errorKind | string or null | What failed, by name. A new one can be added. null when it has no name. One of dns_failure, address_refused, connection_refused, connection_reset, timeout, tls_handshake_failed, certificate_expired, certificate_invalid, domain_expired, registry_unreadable, no_signal, redirect_downgrade, too_many_redirects, redirect_invalid, port_blocked, unexpected_status, keyword_missing, keyword_present, json_mismatch, json_invalid, body_truncated, read_failed, no_reply, packet_loss, probe_unavailable, unreachable. |
incident.reason | string | What failed, in the words the alerts use, such as “the connection was refused”. Its wording can change, so branch on errorKind. |
incident.locations | object or null | How the Incident was confirmed: the locations that agreed, of those asked. null when no other location was asked. |
incident.locations.agreed | array of strings | The locations that agreed it failed, by their identifiers. |
incident.locations.asked | array of strings | Every location that was asked to look. |
incident.flapping | boolean | true when the Incident is flapping: it opened soon after the one before it ended, with a flapping message in place of a down. |
incident.acknowledgedAt | time or null | When someone acknowledged the Incident. null until then, and on the message that opened it. |
incident.downUnsent | boolean | true on an up whose down was never sent, because the Monitor came back before it went. false on every other message. |
incident.stoppingPoint | string or null | Where the run that opened it stopped, by name. A new one can be added, as a new errorKind can. null when nothing can be said, as for a heartbeat. One of name, path, connection, secure_connection, answer, content, ours. |
incident.sentence | stringnull | Where it stopped, in the plain sentence the alerts say, such as “acme.com refused the connection.” It is for a person to read and its wording can change, so branch on stoppingPoint or errorKind, never on this text. null when stoppingPoint is. |
incident.detail | stringnull | Where it stopped in technical detail, as the Host report says it: with the address the name pointed to (the IP address) and the port, such as “203.0.113.10 refused the connection on port 443.” Like sentence, it is for a person to read. null when stoppingPoint is. |
regionalOutage | object or null | The Regional outage the message is about: one location cannot reach the Monitor while the others can. null on any other message. |
regionalOutage.id | string | The Regional outage's identifier. |
regionalOutage.region | string | The location that cannot reach the Monitor. |
regionalOutage.passing | array of strings | The locations that still reached the Monitor when the message was made. |
regionalOutage.openedAt | time | When the location began to fail. |
regionalOutage.resolvedAt | time or null | When it ended. null while it is open. |
regionalOutage.resolution | string or null | How it ended: recovered when the location reached the Monitor again, retracted when it was reported in error, and monitor_paused when the Monitor was paused. null while it is open. One of recovered, retracted, monitor_paused. |
regionalOutage.stoppingPoint | string or null | Where the run that opened it stopped, by name. A new one can be added, as a new errorKind can. null when nothing can be said, as for a heartbeat. One of name, path, connection, secure_connection, answer, content, ours. |
regionalOutage.sentence | stringnull | Where it stopped, in the plain sentence the alerts say, such as “acme.com refused the connection.” It is for a person to read and its wording can change, so branch on stoppingPoint or errorKind, never on this text. null when stoppingPoint is. |
regionalOutage.detail | stringnull | Where it stopped in technical detail, as the Host report says it: with the address the name pointed to (the IP address) and the port, such as “203.0.113.10 refused the connection on port 443.” Like sentence, it is for a person to read. null when stoppingPoint is. |
warning | object or null | The warning the message announces. null on any other message. |
warning.id | string | The warning's identifier. |
warning.type | string | The warning's type, the same as event. One of certificate.expiring, domain.expiring, domain.unreadable, performance.degraded, uptime.family_failing. |
warning.facts | object | What the warning says. Its fields depend on its type: see Warning facts. |
links | object | Links into the dashboard. |
links.dashboard | URL | The Monitor's page in the dashboard. |
links.acknowledge | URL or null | A link that acknowledges the Incident, for anyone the message reaches. On a down or flapping message; null on any other. |
Location identifiers
Section titled “Location identifiers”incident.locations, regionalOutage.region and regionalOutage.passing name our locations by these identifiers:
| Identifier | Location |
|---|---|
us | New York |
us-sjo | San Jose |
de | Frankfurt |
fi | Helsinki |
sg | Singapore |
Warning facts
Section titled “Warning facts”A warning’s facts hold different fields for each type of warning.
certificate.expiring
| Field | Type | What it holds |
|---|---|---|
thresholdDays | integer | The days-left mark this warning crossed: it sounds when that many days are left. |
notAfter | time | When the certificate expires. |
fingerprintSha256 | string | The certificate's SHA-256 fingerprint, in upper-case hex pairs separated by colons, so you can tell which certificate it is. |
domain.expiring
| Field | Type | What it holds |
|---|---|---|
thresholdDays | integer | The days-left mark this warning crossed: it sounds when that many days are left. |
expiresAt | time | When the domain's registration expires, as its registry gives it. |
domain.unreadable
| Field | Type | What it holds |
|---|---|---|
registry | string or null | The registry we could not read. null when we could not tell which one it is. |
lastReadAt | time or null | When we last read it. null when we never could. |
unreadableSince | time | Since when every reading has failed. |
performance.degraded
| Field | Type | What it holds |
|---|---|---|
medianMs | number | The median Answer time that sounded this warning, in milliseconds. |
thresholdMs | integer | The threshold it went over, in milliseconds. |
regions | integer | How many locations the Answer times came from. |
uptime.family_failing
| Field | Type | What it holds |
|---|---|---|
family | string | The kind of address the Monitor did not answer on: ipv4 for the older form, ipv6 for the newer. One of ipv4, ipv6. |
regionIds | array of strings | The locations that agreed it did not answer, in the order they said so. |
Examples
Section titled “Examples”{ "version": 1, "id": "dlv_01K5XQ8F7H2M3N4P5Q6R7S8T9V", "repeat": 1, "event": "uptime.failed", "message": "down", "createdAt": "2026-10-02T14:02:13.120Z", "project": { "id": "prj_01K5XQ8F7H2M3N4P5Q6R7S8T9A", "name": "acme.com" }, "monitor": { "id": "mon_01K5XQ8F7H2M3N4P5Q6R7S8T9B", "name": "Checkout", "type": "http", "target": "https://acme.com/checkout" }, "check": { "id": "chk_01K5XQ8F7H2M3N4P5Q6R7S8T9C", "type": "uptime" }, "incident": { "id": "inc_01K5XQ8F7H2M3N4P5Q6R7S8T9D", "openedAt": "2026-10-02T14:01:58.004Z", "resolvedAt": null, "resolution": null, "errorKind": "connection_refused", "reason": "the connection was refused", "locations": { "agreed": [ "de", "fi" ], "asked": [ "de", "fi", "us" ] }, "flapping": false, "acknowledgedAt": null, "downUnsent": false, "stoppingPoint": "connection", "sentence": "acme.com refused the connection.", "detail": "203.0.113.10 refused the connection on port 443." }, "regionalOutage": null, "warning": null, "links": { "dashboard": "https://app.uup.dev/projects/prj_01K5XQ8F7H2M3N4P5Q6R7S8T9A/monitors/mon_01K5XQ8F7H2M3N4P5Q6R7S8T9B", "acknowledge": "https://app.uup.dev/ack/3mJ8q0Xv5rT2yB7nK4cW9dLs" }}Recovery
Section titled “Recovery”The up that ends the same Incident:
{ "version": 1, "id": "dlv_01K5XQ8F7H2M3N4P5Q6R7S8T9W", "repeat": 1, "event": "uptime.recovered", "message": "up", "createdAt": "2026-10-02T14:09:41.517Z", "project": { "id": "prj_01K5XQ8F7H2M3N4P5Q6R7S8T9A", "name": "acme.com" }, "monitor": { "id": "mon_01K5XQ8F7H2M3N4P5Q6R7S8T9B", "name": "Checkout", "type": "http", "target": "https://acme.com/checkout" }, "check": { "id": "chk_01K5XQ8F7H2M3N4P5Q6R7S8T9C", "type": "uptime" }, "incident": { "id": "inc_01K5XQ8F7H2M3N4P5Q6R7S8T9D", "openedAt": "2026-10-02T14:01:58.004Z", "resolvedAt": "2026-10-02T14:09:40.882Z", "resolution": "recovered", "errorKind": "connection_refused", "reason": "the connection was refused", "locations": { "agreed": [ "de", "fi" ], "asked": [ "de", "fi", "us" ] }, "flapping": false, "acknowledgedAt": "2026-10-02T14:04:07.310Z", "downUnsent": false, "stoppingPoint": "connection", "sentence": "acme.com refused the connection.", "detail": "203.0.113.10 refused the connection on port 443." }, "regionalOutage": null, "warning": null, "links": { "dashboard": "https://app.uup.dev/projects/prj_01K5XQ8F7H2M3N4P5Q6R7S8T9A/monitors/mon_01K5XQ8F7H2M3N4P5Q6R7S8T9B", "acknowledge": null }}Warning
Section titled “Warning”A certificate close to expiry:
{ "version": 1, "id": "dlv_01K5XQ8F7H2M3N4P5Q6R7S8T9X", "repeat": 1, "event": "certificate.expiring", "message": "warning", "createdAt": "2026-10-02T09:00:00.214Z", "project": { "id": "prj_01K5XQ8F7H2M3N4P5Q6R7S8T9A", "name": "acme.com" }, "monitor": { "id": "mon_01K5XQ8F7H2M3N4P5Q6R7S8T9B", "name": "Checkout", "type": "http", "target": "https://acme.com/checkout" }, "check": { "id": "chk_01K5XQ8F7H2M3N4P5Q6R7S8T9E", "type": "certificate" }, "incident": null, "regionalOutage": null, "warning": { "id": "wrn_01K5XQ8F7H2M3N4P5Q6R7S8T9F", "type": "certificate.expiring", "facts": { "thresholdDays": 14, "notAfter": "2026-10-16T12:00:00Z", "fingerprintSha256": "3A:7F:12:C4:9B:E0:55:D1:8C:2F:A6:4E:91:0B:77:D3:EC:28:5A:B9:F0:13:6D:C8:42:9E:AB:07:F5:3C:81:D6" } }, "links": { "dashboard": "https://app.uup.dev/projects/prj_01K5XQ8F7H2M3N4P5Q6R7S8T9A/monitors/mon_01K5XQ8F7H2M3N4P5Q6R7S8T9B", "acknowledge": null }}Before your endpoint acts on a payload, it checks that the request came from us: Verifying signatures shows how.