Get started
Documentation

Webhook alerts

CronAlive POSTs to your URL on every check event. The body is signed with HMAC-SHA256 and its format is customizable with a template.

Setup

Dashboard → Integrations → New integration → Webhook: set the URL and, optionally, a signing secret, a body template and a Content-Type. Event filters (down / up / late), tag filters, quiet hours and reminders work like for any other channel.

Default payload

Without a template you receive JSON (Content-Type: application/json):

{
  "event": "down",
  "check": {
    "id": "e4c9ffb6-9d7e-4c1f-9df6-04642b6ad301",
    "name": "nightly backup",
    "tags": ["backups", "prod"],
    "status": "down",
    "previous_status": "late"
  },
  "reason": "timeout",
  "ts": "2026-07-21T00:30:00+00:00",
  "subject": "🔴 nightly backup is DOWN",
  "message": "Check 'nightly backup' went down…"
}

Verifying the signature

With a secret configured, every request carries X-CronAlive-Signature — hex(HMAC-SHA256) of the raw request body (custom templates included):

# PHP
$valid = hash_equals(
    hash_hmac('sha256', $request->getContent(), $secret),
    $request->header('X-CronAlive-Signature')
);

# Python
import hmac, hashlib
valid = hmac.compare_digest(
    hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest(),
    request.headers["X-CronAlive-Signature"],
)

Custom body template

The body template replaces the payload entirely: {{…}} placeholders are substituted with event values, so the webhook fits any third-party format without middleware.

Placeholder Value
{{event}}down / up / late / ssl_expiring
{{check_id}}check UUID
{{check_name}}check name
{{status}}new check status
{{previous_status}}previous status (empty for SSL)
{{reason}}flip reason
{{ts}}event time, ISO 8601
{{tags}}check tags, comma separated
{{subject}}alert headline (localized)
{{message}}alert text (multiline)

Example — a third-party messenger format:

{"text": "{{subject}}", "channel": "#ops", "meta": {"check": "{{check_name}}", "state": "{{status}}"}}

With Content-Type: application/json (the default) values are substituted JSON-escaped — quotes and newlines in {{message}} never break the document. Other content types (e.g. text/plain) get raw substitution:

ALERT {{check_name}} is {{status}} ({{reason}})

Delivery & retries

Any 2xx response counts as success. On errors or a 10-second timeout the delivery retries up to 3 times (10 s → 1 min → 5 min); each delivery's status and error text are visible in the integration journal (the Journal button).