Webhooks and Slack
A webhook sends an HTTP request to a service when an incident starts or clears. Use Slack to post a message in a channel. Use Generic JSON to send the event to your own application or an automation tool that accepts HTTP POST requests.
You can configure one webhook destination per workspace. Email can remain enabled alongside it. Webhooks use the same incident detection and thresholds as email; they do not require an agent update.
Connect Slack
- Open Slack app settings and create an app for your workspace, or choose an existing app.
- Open Incoming Webhooks and turn on Activate Incoming Webhooks.
- Click Add New Webhook to Workspace, choose the channel, and approve access. Your workspace may require an administrator to approve the app.
- Copy the generated webhook URL. It starts with
https://hooks.slack.com/services/. - In Cloud, open Alert settings and enable Webhook alerts. Choose Slack and paste the URL.
- Click Save.
Slack messages include the server name, affected resource, value, threshold, time, and an Open dashboard button. The URL chooses the channel; changing channels requires a new URL from Slack. Treat the URL as a password and keep it out of public repositories or screenshots.
Slack's setup guide has details about app creation and workspace permissions.
Connect a JSON receiver
Your receiver needs a public HTTPS URL on port 443. This can be a POST endpoint in your application or a webhook URL created by your automation tool. Use the production URL, not a temporary local test address. Cloud cannot reach private network addresses and does not follow redirects.
- Configure the receiver to accept HTTP POST requests with a JSON body.
- In Alert settings, enable Webhook alerts, choose Generic JSON, and paste the receiver URL.
- Click Save.
- Reopen Alert settings and copy the Signing secret. Use it on the receiver to verify requests as described below.
- Return a successful
2xxresponse after accepting an event. Store or queue the event before responding if further work may take time.
Changing the URL or format creates a new signing secret and cancels queued deliveries to the old destination. Copy the new secret after saving a change.
Check delivery
After saving, a new incident creates a delivery in Alert history on the left of the window. Recovery deliveries require a start queued for the same destination; a cancelled start prevents its recovery delivery too. Enabling a destination does not replay existing incidents. There is no test-send button.
To check the full path without loading a server, you can temporarily set the disk threshold below a monitored disk's current use. Save, wait for a new incident and its delivery, then restore the threshold to clear the incident. Use a server with no active disk incident, record the original threshold first, and remember that thresholds apply to the whole workspace. Other enabled channels can receive this test incident too.
Check Alert history and your receiver logs. Pending waits for delivery or retry. Sent means the receiver returned 2xx. Failed shows the last error. An HTTP 4xx error usually needs a receiver or URL fix; 408 and 429 are retried.
You can also use the sample payload below to test your receiver separately.
JSON payload
Cloud sends version 1 of this event format:
{
"version": 1,
"id": "vpscloud-incident-42-opened",
"type": "incident.opened",
"occurred_at": "2026-10-06T09:00:00Z",
"incident_id": 42,
"server_id": "srv_example",
"hostname": "web-01",
"rule": "cpu",
"value": 95.2,
"threshold": 90,
"unit": "percent"
}
| Field | Meaning |
|---|---|
id |
Stable event ID. Retries keep the same ID and JSON body. |
type |
incident.opened or incident.resolved. |
occurred_at |
UTC time of the incident transition, which can precede delivery. |
incident_id |
Identifies the incident; its start and recovery share this value. |
server_id, hostname |
Identify the affected server. |
rule |
cpu, memory, disk, or offline. |
value |
The detector's value at the transition: one-minute CPU/memory average, latest disk percentage, or offline duration. |
threshold |
The configured alert threshold, including in recovery events. |
unit |
percent for resources, seconds for offline events. |
Webhook events contain these incident fields. Live processes, incident snapshots, account emails, and agent credentials are not included.
Verify JSON signatures
JSON requests include these headers:
| Header | Value |
|---|---|
Content-Type |
application/json |
X-Vpsmon-Event-ID |
The event ID from the payload. |
X-Vpsmon-Timestamp |
Unix seconds of this delivery attempt. |
X-Vpsmon-Signature |
sha256= followed by the hexadecimal HMAC-SHA256 signature. |
Use the entire signing secret as the UTF-8 HMAC key. Sign the timestamp header, a literal ., and the exact raw request body. Verify before parsing or changing the JSON. Reject timestamps outside a short tolerance, such as five minutes, and compare signatures in constant time.
This Go helper checks the signature of an already-read body:
package receiver
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"net/http"
"strconv"
"time"
)
func ValidSignature(body []byte, headers http.Header, secret string, now time.Time) bool {
if secret == "" {
return false
}
timestamp := headers.Get("X-Vpsmon-Timestamp")
seconds, err := strconv.ParseInt(timestamp, 10, 64)
if err != nil || seconds < now.Unix()-300 || seconds > now.Unix()+300 {
return false
}
mac := hmac.New(sha256.New, []byte(secret))
mac.Write([]byte(timestamp + "."))
mac.Write(body)
expected := "sha256=" + hex.EncodeToString(mac.Sum(nil))
return hmac.Equal([]byte(headers.Get("X-Vpsmon-Signature")), []byte(expected))
}
Limit the request body size when reading it, then verify the signature. Save the event ID in your receiver's storage and ignore an ID you have already processed. A valid signature proves who sent the request; storing the ID prevents a retry from repeating your action.
Slack uses its secret incoming-webhook URL and Slack message format. The JSON signing headers apply to Generic JSON receivers.
Retries and pausing
Cloud retries timeouts, network failures, 408, 429, and 5xx responses with increasing delays. It respects Retry-After up to one hour. Other unsuccessful statuses stop that delivery. Each request has a ten-second timeout; automatic retries stop after 12 attempts or 24 hours.
Pending deliveries survive Cloud restarts. Within a workspace, a pending start is attempted before later events. Once it succeeds or fails permanently, later events can proceed. Use occurred_at to order incident changes in your own system.
A receiver can accept an event and lose the response before Cloud receives it. The retry can deliver that event twice, so JSON receivers must deduplicate by ID. Slack can show a duplicate message in this case.
To pause webhooks, turn off Webhook alerts and click Save. Monitoring continues. Queued deliveries are cancelled and are not replayed on resume. A request already in flight may finish after you pause. The Email alerts switch remains independent.
vpsmon Cloud