Skip to content

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.

  • 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, a message or an errorKind. Ignore what you do not know.
  • Anything else is a new version: removing a field, renaming it, or changing what it holds.
  • reason, sentence and detail are words for a person, and their wording can change. Branch on errorKind or stoppingPoint, 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 an id you 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 and inc_ for an Incident.

The message field says what happened:

messageWhat happened
downAn Incident opened on one of the Monitor's Checks.
flappingAn 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.
upThe Incident ended because its Check passes again.
correctionThe Incident was reported in error, and is taken back. It leaves your uptime figure.
pausedThe Incident ended because someone paused the Monitor.
disabledThe Incident ended because someone turned its Check off.
resolvedSomeone resolved the Incident by hand. If the Monitor still fails, a new one opens.
regional_outageOne location cannot reach the Monitor while the others can. It is not an Incident, and it never counts against your uptime.
regional_recoveryThat location reaches the Monitor again.
regional_correctionThe Regional outage was reported in error, and is taken back.
warningA warning was announced, such as a certificate close to expiry.
testA test, sent when you add the Webhook, press Send test, or turn it back on. It is about no Monitor event.
FieldTypeWhat it holds
versionnumberThe payload's version. It changes only when a field is removed, renamed or changes what it means. Always 1.
idstringThe 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.
repeatintegerAlways 1: a Webhook gets each message once, and no Repeat alerts.
eventstring or nullThe 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.
messagestringWhich 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.
createdAttimeWhen the message was made. It is the same on every attempt to send it.
projectobjectThe Project the Monitor is in.
project.idstringThe Project's identifier.
project.namestringThe Project's name.
monitorobjectThe Monitor the message is about.
monitor.idstringThe Monitor's identifier.
monitor.namestringThe Monitor's name.
monitor.typestringThe Monitor's type. One of http, tcp, ping, heartbeat.
monitor.targetstringWhat the Monitor checks, as you entered it.
checkobject or nullThe Check the message is about. null for a test.
check.idstringThe Check's identifier.
check.typestringThe Check's type. One of uptime, performance, certificate, domain.
incidentobject or nullThe Incident the message is about. null on a message about a Regional outage, a warning or a test.
incident.idstringThe Incident's identifier. Every message about one Incident carries the same one.
incident.openedAttimeWhen the Incident opened.
incident.resolvedAttime or nullWhen the Incident ended. null while it is open.
incident.resolutionstring or nullHow 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.errorKindstring or nullWhat 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.reasonstringWhat failed, in the words the alerts use, such as “the connection was refused”. Its wording can change, so branch on errorKind.
incident.locationsobject or nullHow the Incident was confirmed: the locations that agreed, of those asked. null when no other location was asked.
incident.locations.agreedarray of stringsThe locations that agreed it failed, by their identifiers.
incident.locations.askedarray of stringsEvery location that was asked to look.
incident.flappingbooleantrue when the Incident is flapping: it opened soon after the one before it ended, with a flapping message in place of a down.
incident.acknowledgedAttime or nullWhen someone acknowledged the Incident. null until then, and on the message that opened it.
incident.downUnsentbooleantrue on an up whose down was never sent, because the Monitor came back before it went. false on every other message.
incident.stoppingPointstring or nullWhere 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.sentencestringnullWhere 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.detailstringnullWhere 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.
regionalOutageobject or nullThe Regional outage the message is about: one location cannot reach the Monitor while the others can. null on any other message.
regionalOutage.idstringThe Regional outage's identifier.
regionalOutage.regionstringThe location that cannot reach the Monitor.
regionalOutage.passingarray of stringsThe locations that still reached the Monitor when the message was made.
regionalOutage.openedAttimeWhen the location began to fail.
regionalOutage.resolvedAttime or nullWhen it ended. null while it is open.
regionalOutage.resolutionstring or nullHow 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.stoppingPointstring or nullWhere 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.sentencestringnullWhere 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.detailstringnullWhere 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.
warningobject or nullThe warning the message announces. null on any other message.
warning.idstringThe warning's identifier.
warning.typestringThe warning's type, the same as event. One of certificate.expiring, domain.expiring, domain.unreadable, performance.degraded, uptime.family_failing.
warning.factsobjectWhat the warning says. Its fields depend on its type: see Warning facts.
linksobjectLinks into the dashboard.
links.dashboardURLThe Monitor's page in the dashboard.
links.acknowledgeURL or nullA link that acknowledges the Incident, for anyone the message reaches. On a down or flapping message; null on any other.

incident.locations, regionalOutage.region and regionalOutage.passing name our locations by these identifiers:

IdentifierLocation
usNew York
us-sjoSan Jose
deFrankfurt
fiHelsinki
sgSingapore

A warning’s facts hold different fields for each type of warning.

certificate.expiring

FieldTypeWhat it holds
thresholdDaysintegerThe days-left mark this warning crossed: it sounds when that many days are left.
notAftertimeWhen the certificate expires.
fingerprintSha256stringThe certificate's SHA-256 fingerprint, in upper-case hex pairs separated by colons, so you can tell which certificate it is.

domain.expiring

FieldTypeWhat it holds
thresholdDaysintegerThe days-left mark this warning crossed: it sounds when that many days are left.
expiresAttimeWhen the domain's registration expires, as its registry gives it.

domain.unreadable

FieldTypeWhat it holds
registrystring or nullThe registry we could not read. null when we could not tell which one it is.
lastReadAttime or nullWhen we last read it. null when we never could.
unreadableSincetimeSince when every reading has failed.

performance.degraded

FieldTypeWhat it holds
medianMsnumberThe median Answer time that sounded this warning, in milliseconds.
thresholdMsintegerThe threshold it went over, in milliseconds.
regionsintegerHow many locations the Answer times came from.

uptime.family_failing

FieldTypeWhat it holds
familystringThe kind of address the Monitor did not answer on: ipv4 for the older form, ipv6 for the newer. One of ipv4, ipv6.
regionIdsarray of stringsThe locations that agreed it did not answer, in the order they said so.
{
"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"
}
}

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
}
}

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.