Webhook Setup
Overview
A webhook lets Haltless notify your systems the moment an alert fires. You stand up an HTTPS endpoint, register it as a webhook notification channel, and Haltless sends a JSON POST to it for each alert , so you can page an on-call engineer, open a ticket, or trigger downstream automation.
Webhooks are one of several notification channel types. This guide covers the webhook channel specifically. For the full channel API, see the Notifications API.
How it works
Alert fires in Haltless
│
▼
Haltless POSTs a JSON payload ──────▶ Your HTTPS endpoint
│ │
│ respond 2xx promptly
▼
Delivery complete
Requirements for your endpoint
- It must be reachable over HTTPS at a publicly resolvable address. Haltless validates the URL when you register the channel and rejects endpoints it cannot safely reach; plain
http://and private/internal addresses are not accepted. - It should respond with a
2xxstatus quickly. Do the minimum inline (acknowledge and enqueue), and process asynchronously.
Register a webhook channel
Creating a channel requires an admin or operator (JWT) session. You can do it from the Client Portal (Settings → Notifications) or the API.
curl -X POST "https://api.haltless.io/api/v1/notification-channels" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"channel_type": "webhook",
"name": "ops-pager",
"config": {
"url": "https://hooks.example.com/haltless",
"headers": {
"Authorization": "Bearer YOUR_SHARED_SECRET"
}
},
"notify_on_alert": true,
"is_active": true
}'
| Field | Description |
|---|---|
channel_type | Must be webhook |
name | A label for the channel |
config.url | Your HTTPS endpoint. Required |
config.headers | Optional map of custom headers Haltless sends with every delivery , use this to authenticate deliveries (see below) |
notify_on_alert | Send this channel a delivery when an alert fires |
is_active | Whether the channel is enabled |
When you read a channel back, any secrets in config (such as an authorization header) are masked in the response.
Delivery payload
Haltless delivers a JSON body via POST. An alert delivery looks like this:
{
"message": "Temperature exceeded threshold",
"severity": "critical",
"metric_name": "temperature",
"trigger_value": 87.3,
"threshold_value": 85.0,
"machine_id": "9c8b7a6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d"
}
| Field | Description |
|---|---|
message | Human-readable summary of the alert |
severity | info, warning, or critical |
metric_name | The metric that crossed its threshold |
trigger_value | The value that fired the alert |
threshold_value | The configured threshold that was crossed |
machine_id | The machine the alert is for |
Design your handler to tolerate additional fields , new keys may be added over time, and your parser should ignore anything it doesn't recognize.
Test your receiver
Send a test delivery through a channel to confirm your endpoint is wired up correctly, without waiting for a real alert:
curl -X POST "https://api.haltless.io/api/v1/notification-channels/CHANNEL_ID/test" \
-H "Authorization: Bearer YOUR_JWT_TOKEN"
{ "success": true }
A test delivery carries a "type": "test" marker so your endpoint can distinguish it from a live alert:
{
"type": "test",
"message": "Test notification from Haltless — channel 'ops-pager'",
"severity": "info",
"metric_name": "test_metric",
"trigger_value": 0.0,
"threshold_value": 0.0
}
success: true means Haltless reached your endpoint and it responded successfully.
Secure your receiver
Because your endpoint is publicly reachable, verify that each request genuinely came from Haltless:
- Authenticate with a header. Put a shared secret in
config.headers(for example, anAuthorizationheader). Haltless sends those headers with every delivery. Reject any request that doesn't carry the expected value. - Require HTTPS. Haltless only delivers to validated HTTPS endpoints; terminate TLS at your edge and refuse plain HTTP.
- Rotate the secret periodically by updating the channel's
config.headers. - Scope the endpoint. Give the webhook URL a hard-to-guess path and treat it as sensitive.
Never act on an unauthenticated request. Validate the shared secret before doing any work.
Delivery behavior
- Haltless expects a prompt
2xx. If your endpoint is slow, unreachable, or returns a non-2xxstatus, the delivery is treated as failed for that attempt. - Make your handler idempotent: the same alert may reach you more than once, so key on the alert's fields (for example,
machine_id+metric_name+trigger_value) and de-duplicate on your side. - Webhooks are a notification mechanism, not a system of record. For critical workflows, reconcile against the Alerts API , poll it or query on reconnect , so a missed delivery never means a missed alert.
Managing channels
# List channels
curl "https://api.haltless.io/api/v1/notification-channels" \
-H "Authorization: Bearer YOUR_JWT_TOKEN"
# Update a channel (for example, rotate the auth header or pause it)
curl -X PUT "https://api.haltless.io/api/v1/notification-channels/CHANNEL_ID" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "is_active": false }'
# Delete a channel
curl -X DELETE "https://api.haltless.io/api/v1/notification-channels/CHANNEL_ID" \
-H "Authorization: Bearer YOUR_JWT_TOKEN"
Next steps
- Notifications API , all channel types and their config
- Alerts API , query alert history and reconcile deliveries
- WebSocket Integration , receive alerts live in a dashboard instead of via webhook