Skip to main content

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​

When an alert is raised, Haltless POSTs it as JSON, with your headers, to your HTTPS endpoint, which checks the shared secret, answers first and does the work after, and ignores a repeat delivery. A 2xx within 10 seconds delivers it. A timeout, a dropped connection, or a 408, 425, 429, 500, 502, 503 or 504 is tried again, up to 3 tries, after 0.5 seconds and then 2 seconds. Any other answer, a redirect included, fails it.When an alert is raised, Haltless POSTs it as JSON, with your headers, to your HTTPS endpoint, which checks the shared secret, answers first and does the work after, and ignores a repeat delivery. A 2xx within 10 seconds delivers it. A timeout, a dropped connection, or a 408, 425, 429, 500, 502, 503 or 504 is tried again, up to 3 tries, after 0.5 seconds and then 2 seconds. Any other answer, a redirect included, fails it.

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 2xx status 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 whose role can open the Notifications or Integrations settings tab. You can do it from the Client Portal (Settings → Integrations) 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
}'
FieldDescription
channel_typeMust be webhook
nameA label for the channel
config.urlYour HTTPS endpoint. Required
config.headersOptional map of custom headers Haltless sends with every delivery. Use this to authenticate deliveries (see below)
notify_on_alertSend this channel a delivery when an alert fires
is_activeWhether 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:

{
"type": "alert",
"message": "Temperature exceeded threshold",
"severity": "critical",
"metric_name": "temperature",
"trigger_value": 87.3,
"threshold_value": 85.0,
"machine_id": "9c8b7a6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d"
}
FieldDescription
typeWhat the delivery is about (see below)
messageHuman-readable summary
severityinfo, warning, or critical
metric_nameThe metric that crossed its threshold
trigger_valueThe value that fired the alert
threshold_valueThe configured threshold that was crossed
machine_idThe machine the alert is for

type is one of:

typeSent when
alertAn alert is raised, or an open alert becomes more severe
escalationAn alert is still unacknowledged after an escalation policy's wait time. Sent to the channel that policy names; message starts with [ESCALATED — unacknowledged for N min]
prediction_criticalA machine's predicted health enters the critical band. metric_name is health_score, and the body adds machine_name, health_score, and days_to_maintenance
testYou send a test delivery (see below)

Design your handler to tolerate additional fields and type values: new ones 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, "error": null }

The test endpoint answers 200 even when the delivery fails, so read success. On failure, error says why, for example the status your endpoint returned.

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. Deliveries are not signed, so the shared secret you set in config.headers is what proves a request came from Haltless:

  1. Authenticate with a header. Put a shared secret in config.headers (for example, an Authorization header). Haltless sends those headers with every delivery. Reject any request that doesn't carry the expected value.
  2. Require HTTPS. Haltless only delivers to validated HTTPS endpoints; terminate TLS at your edge and refuse plain HTTP.
  3. Rotate the secret periodically by updating the channel's config.headers.
  4. 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 2xx within 10 seconds. Redirects are not followed, so a 3xx counts as a failure.
  • A delivery is tried up to 3 times in quick succession (about 0.5 seconds, then 2 seconds apart), but only when the failure looks temporary: a timeout, a dropped connection, or a 408, 425, 429, 500, 502, 503, or 504 response. Any other non-2xx status fails the delivery at once.
  • Every delivery and its outcome is recorded; read the history with GET /api/v1/notification-channels/{channel_id}/deliveries.
  • 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, polling it or querying it 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​