Webhooks

Every alert, delivered to your own endpoint.

The moment a monitor changes state, CuliPulse sends a signed JSON message to your URL. Open a ticket, post to chat, start a runbook or store it. Your code decides.

A signed JSON message the moment a monitor changes state. Your code decides what happens next.

Included on every plan · no limit on endpoints

POST https://hooks.example.com/culipulseapplication/json
{  "version": "1",  "event": "monitor.down",  "delivery_id": "3f2a9c4e-7b1d-4e8a-9c5f-…",  "event_at": 1758700000,  "sent_at": 1758700001,  "monitor": {    "id": "mon_3fk9…",    "name": "Checkout API",    "type": "http",    "target": "https://api.example.com/health"  },  "state": "down",  "reason": "Connection timed out after 10s",  "detail": {    "sources_down": ["Singapore", "Frankfurt"],    "incident_id": "inc_8c1d…"  },  "url": "https://culipulse.dev/monitors/mon_3fk9…"}
{  "event": "monitor.down",  "monitor": { "name": "Checkout API" },  "state": "down",  "reason": "Connection timed out after 10s"}

Events

Seven events, one simple shape.

Every message has the same envelope: a version, the event name, a delivery id and two timestamps. The rest depends on the event.

monitor.downA monitor stops workingConnection timed out after 10s
monitor.degradedIt works, but not wellA provider reports a partial outage
monitor.upIt is working againBack up after 13 minutes
monitor.unknownWe cannot tell right nowNo location has reported yet
agent.offlineOne of your agents stops reportingOffice agent went quiet
agent.onlineThe agent is backOffice agent reporting again
advisory.domain_expiryA domain is about to expireexample.com expires in 14 days

Verify it came from us

Check the signature in a few lines.

Each delivery is signed with a secret only you and CuliPulse know. Compute an HMAC-SHA256 of the raw body and compare.

HMAC-SHA256 of the raw body with your signing secret, compared to X-CuliPulse-Signature.

X-CuliPulse-Signaturesha256= followed by the HMAC of the raw body
X-CuliPulse-EventThe event name, e.g. monitor.down
X-CuliPulse-DeliveryA unique id for this delivery
X-CuliPulse-TimestampWhen it was sent (not part of the signature)
import crypto from 'node:crypto';function verifyCuliPulse(rawBody, signatureHeader, signingSecret) {  const expected =    'sha256=' + crypto.createHmac('sha256', signingSecret)      .update(rawBody).digest('hex');  const a = Buffer.from(signatureHeader ?? '');  const b = Buffer.from(expected);  return a.length === b.length && crypto.timingSafeEqual(a, b);}
import hmac, hashlibdef verify_culipulse(raw_body: bytes, signature_header: str,                     signing_secret: str) -> bool:    expected = "sha256=" + hmac.new(        signing_secret.encode(), raw_body, hashlib.sha256    ).hexdigest()    return hmac.compare_digest(expected, signature_header or "")

Delivery

Predictable, and honest when it fails.

8sAnswer quickly

Reply with any 2xx within 8 seconds. Do slow work after you respond.

3×Retried on server errors

Timeouts and 5xx answers are retried up to 3 times. A 4xx answer is treated as final.

3xxRedirects are not followed

Use the final URL. A redirect counts as a failed delivery.

Test before you save

A webhook only goes live after a test delivery works. If it doesn't, the console tells you why in plain words.

Real CuliPulse console: a failed webhook test that says it could not reach the endpoint and to check the domain name
Real console · test failed, with the reason
Real CuliPulse console: webhook created after a successful test delivery, with the signing secret shown once
Real console · test passed, secret shown once (masked here)

Point it at your endpoint.

Paste a URL, send a test, and you're receiving alerts.

Paste a URL, send a test, done.