Skip to content

Outbound webhooks

Event payload shape, HMAC signature verification, retry policy.

When a channel of type webhook fires, Pulse POSTs a JSON payload to the configured URL with these headers:

Content-Type: application/json
User-Agent: PulseNotifier/<version>
X-Pulse-Event: incident.opened | incident.resolved | alert.firing | ...
X-Pulse-Signature: t=<unix>,v1=<hex>
X-Pulse-Delivery: <uuid>

Concatenate <timestamp>.<raw body>, HMAC-SHA256 with the channel’s secret, hex-encode, compare to the v1 field. Reject if the timestamp is older than 5 minutes (replay defense).

import hmac, hashlib, time
def verify(secret, header, body, max_age=300):
parts = dict(p.split("=", 1) for p in header.split(","))
if abs(time.time() - int(parts["t"])) > max_age:
return False
expected = hmac.new(secret.encode(), f"{parts['t']}.{body}".encode(),
hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, parts["v1"])
  • Attempt 1: immediately
  • Attempt 2: +30s
  • Attempt 3: +2m
  • Attempt 4: +5m
  • Attempt 5: +10m

After 5 failed attempts the delivery is dropped. Failures surface in Settings → Channels → <channel> → Recent deliveries.

{
"event": "incident.opened",
"delivery_id": "01HN...",
"occurred_at": "2026-05-19T01:23:45Z",
"org_id": "...",
"data": {
"incident": { "id": "INC-104", "title": "...", "severity": "P1", "status": "investigating" }
}
}