# UptimeRobot

EvoHub receives UptimeRobot alerts through a **Webhook** integration. A monitor going down opens an EvoHub alert, and the monitor coming back up resolves it. SSL and domain expiry notices open an alert of their own.

## Set it up

:::steps
### Create the integration
In EvoHub, go to **On-Call → Integrations → + Add Integration**, choose **UptimeRobot**, pick an **Escalation Policy** and click **Create Integration**. Copy the **Webhook URL**.
### Add a webhook
In UptimeRobot, go to **Integrations → Add Integration → Webhook** and set **Webhook URL** to your webhook URL.
### Set the POST value
Paste the POST value below as it is (the `*…*` parts are UptimeRobot variables), turn **Send as JSON** on and **Send as query string** off.
### Choose the events
Under the events to notify about, tick **Down** and **Up**. Without **Up**, nothing ever resolves. **SSL & Domain expiry** is optional.
### Add it to your monitors
Add the integration to the notifications of the monitors that should page.
:::

Webhook URL:

```text
https://evohub.io/ingest/uptimerobot?key=YOUR_INTEGRATION_KEY
```

POST value:

```json
{"monitorID":"*monitorID*","monitorFriendlyName":"*monitorFriendlyName*","monitorURL":"*monitorURL*","alertType":"*alertType*","alertTypeFriendlyName":"*alertTypeFriendlyName*","alertDetails":"*alertDetails*","sslExpiryDate":"*sslExpiryDate*","sslExpiryDaysLeft":"*sslExpiryDaysLeft*"}
```

EvoHub reads the same variables whichever way UptimeRobot sends them: as this JSON body, as POST form values, or appended to the URL as a query string. Variables missing from the body are taken from the URL.

### Set up through Alert Contacts?

An older setup made under **My Settings → Alert Contacts → Web-Hook**, with the URL ending in `&` (`…?key=YOUR_INTEGRATION_KEY&`) and no POST value, may not reach EvoHub. Without a POST value UptimeRobot only appends its variables to the URL, and such a webhook can be sent as a GET request ([UptimeRobot's webhooks were GET-only before POST values](https://uptimerobot.com/blog/post-support-for-web-hook-alert-contacts-now-available/)). EvoHub accepts POST only, so a GET is refused and the alert is lost. Add the POST value above to that webhook and turn **Send as JSON** on, or recreate it as described above. Then check that a test alert arrives in EvoHub.

## Turn on auto-resolve

Tick **Up** among the events the integration notifies about. The Up notification resolves the alert that the Down notification opened.

## What EvoHub reads

| EvoHub alert | Taken from |
| --- | --- |
| Title | "`monitorFriendlyName` is Down", for example "Checkout API is Down" (or "UptimeRobot: Monitor Down"). |
| Description | `alertDetails`, the reason the check failed. |
| Labels | `url` (`monitorURL`); for expiry notices also `ssl_expiry_date` and `ssl_expiry_days_left`. |
| Fingerprint | `monitorID`. Without it, the monitor's URL, else its name, else one fixed key for the integration. |

Down alerts are always **critical**, and so are SSL and domain expiry notices.

### SSL and domain expiry

An expiry notice (`alertType` 3) opens a separate alert, titled for example "Checkout API: SSL certificate expires in 14 days". It never resolves or merges into the monitor's down alert, and repeated notices for the same monitor are one alert. It does not resolve by itself either: resolve it in EvoHub once the certificate or domain is renewed.

## Resolve and deduplication

- EvoHub tells Down from Up by `alertTypeFriendlyName` (**Down** or **Up**), then by the numeric `alertType` (`1` down, `2` up; the older `0` also means down).
- An Up notification resolves the open alert for the same monitor. Another Down while the alert is open is recorded as **Retriggered**.
- A delivery that is neither an Up nor an expiry notice is treated as **Down**, so a monitoring notification is never silently dropped. That includes one with no variables at all, which opens "UptimeRobot: Monitor Down".
- Other bodies work too. UptimeRobot's own example body (`monitor`, `status`, `url`, `details`) is read when there is no `monitorID`. A custom body with only free text (`{"text": "..."}` or `{"message": "..."}`) opens an alert titled with its first line, and text such as "is up", "is back" or "recovered" resolves it.

## Troubleshooting

- **`401 INVALID_KEY`**: the URL's key is wrong or the integration is disabled. In an **Alert Contacts** setup, a URL without the trailing `&` corrupts the key in the same way.
- **`400 INVALID_BODY`**: the POST value is not valid JSON while **Send as JSON** is on. Paste the POST value above again.
- **All monitors share one alert**: the POST value leaves out `monitorID`, `monitorURL` and `monitorFriendlyName`. Use the POST value above.
- **Alerts never resolve**: **Up** is not ticked among the events.

## Related

- [Integrations overview](https://docs.evohub.io/integrations-overview.md)
- [Uptime Kuma](https://docs.evohub.io/uptime-kuma.md)
- [Escalation policies](https://docs.evohub.io/escalation-policies.md)
