A webhook is the channel for people who want to connect an alert to their own tools: a script, a status board, an on-call system, a small service that opens a ticket. When a website goes down, and when it comes back, UptimeWire sends one HTTP request to the address you set.
Note
Webhooks are built and have been tested against a test receiver. Delivery to a live public address has not been independently verified yet. Test your own address with the test message before you rely on it.
What a webhook carries
| Event | Header value | When it is sent |
|---|---|---|
| Outage | incident.opened |
A failure has been confirmed and an incident has opened. |
| Recovery | incident.closed |
The website answers again and the incident has closed. |
| Test | test |
You press "Send test message" in your account. |
Certificate, domain, and DNS warnings are not sent by webhook. They reach you by email and, if connected, Telegram.
Set it up
You set the address in your UptimeWire account, in the notification settings of your profile. Only the account owner can add, change, test, or remove it.
- Enter the address of your receiver. It must start with
https://. - Press "Save address". A signing secret is created the first time you save.
- Copy the signing secret into your receiver. It starts with
whsec_. - Press "Send test message". The result is shown at once.
The address is the same for every website in the account. You cannot choose a different address for one website.
Which addresses are accepted
UptimeWire refuses an address that:
- does not use
https://, or contains a username or password; - points to a private or internal network, to the machine itself, or to a numeric trick such as a decimal or hexadecimal IP address;
- is longer than 2,048 characters.
The address is checked when you save it, and again before every message is sent.
The message
The request is an HTTP POST with a JSON body. This example is illustrative: the values are made up.
{
"id": "4182",
"event": "incident.opened",
"site": {
"id": "00000000-0000-0000-0000-000000000000",
"name": "Shop",
"url": "https://shop.example.com"
},
"incident": {
"id": "00000000-0000-0000-0000-000000000001",
"started_at": "2026-11-01T10:15:00Z",
"ended_at": null,
"duration_seconds": null,
"cause": "HTTP 503"
}
}
For incident.closed the body has the same shape, with ended_at and duration_seconds filled in. For test, site and incident are null. Times are in UTC.
The id identifies the delivery, not the incident. The incident part shows its state when the message is sent, so a late incident.opened can already carry an ended_at. Ignore fields you do not know, so that your receiver keeps working if a field is added.
Headers
| Header | Value |
|---|---|
Content-Type |
application/json |
User-Agent |
UptimeWire-Webhook/1 |
X-UptimeWire-Delivery |
The same value as id in the body. |
X-UptimeWire-Event |
incident.opened, incident.closed, or test. |
X-UptimeWire-Signature |
t=<unix time>,v1=<signature> |
Check the signature
Anyone who learns your address can send it a request. The signature lets your receiver tell a real UptimeWire message from a forged one.
The signature is an HMAC with SHA-256, written in hexadecimal. It is computed with your signing secret over the text made of the time t, a full stop, and the raw body.
To check a message:
- Read the raw body before you parse it as JSON. Parsing and writing it again can change it.
- Read
tandv1from theX-UptimeWire-Signatureheader. - Compute the HMAC of
t, a full stop, and the raw body, with your signing secret. - Compare your result with
v1using a constant-time comparison. - Reject the message if
tis more than five minutes from your own clock.
If you make a new secret in your account, the old one stops working at once. There is no overlap.
Delivery and retries
A delivery counts as successful when your receiver answers with a 2xx status within five seconds. Anything else is a failure: another status, a timeout, a certificate problem, or a refused connection. UptimeWire does not follow redirects, and a 3xx answer is a failure.
A failed message is tried up to five times in all: at once, then after 1, 5, 30, and 120 minutes. After the last try it is marked as failed. UptimeWire does not email you about it, but the dashboard shows that an alert was not delivered. It does not switch the address off.
In rare cases the same message can arrive twice, and messages can arrive out of order. Store the id of each message you handle, and use started_at to decide which state is newer.
What you can see in your account
The webhook card in your account has a delivery log with the last 20 messages. For each one it shows the website, the type of message, the status (delivered, failed, will retry, waiting, or cancelled), the number of tries, and the result, such as "Answered 200".
Limits
- One address per account, shared by all websites. Only the account owner can change it.
- Outage and recovery only.
- Included from the Starter plan. If an account moves to a plan without webhooks, waiting messages are cancelled and no new ones are made. The address and secret are kept, and messages resume after an upgrade.
- Messages are sent at least once, not exactly once.
- UptimeWire does not read the answer your receiver sends back.
Troubleshooting
- "This address is not allowed." The address leads to a private or internal network. Use a public address.
- "The address must start with https://." Plain
http://is not accepted. - "The address did not answer in 5 seconds." Answer first and do the slow work afterwards, for example by putting the message in a queue.
- "Answered 3xx: redirects are not followed." Set the address to the final one.
- Messages arrive but the signature does not match. Check that you compute it over the raw body, and that you use the current secret.
- "Too many test messages." The test button is limited to five a minute.
Telegram, Discord, Slack, and Microsoft Teams are separate channels. See the integrations overview for what each one carries.