Webhook Alerts
Webhooks send HTTP POST requests to your endpoint when an incident is created or resolved. Use webhooks to integrate PingSLA with any custom system, ticketing platform, or on-call tool.
Adding a Webhook Channel
- Go to Settings → Notification Channels → New Channel
- Select Webhook
- Enter the endpoint URL (must be HTTPS)
- Optionally add a secret for payload verification
- Click Test
Webhook Payload
PingSLA sends a POST request with Content-Type: application/json.
Incident Created (DOWN)
{
"event": "incident.created",
"timestamp": "2026-05-18T14:32:00.000Z",
"incident": {
"id": "inc_abc123",
"url": "https://app.pingsla.com/incidents/inc_abc123",
"status": "open",
"createdAt": "2026-05-18T14:32:00.000Z"
},
"monitor": {
"id": "mon_xyz456",
"name": "Production API Health",
"type": "http",
"url": "https://api.yourapp.com/health"
},
"failure": {
"reason": "HTTP 503 Service Unavailable",
"statusCode": 503,
"responseTime": null,
"region": "us-east-1"
},
"workspace": {
"id": "ws_xxxxxxxxx",
"name": "Acme Corp"
}
}
Incident Resolved (RECOVERED)
{
"event": "incident.resolved",
"timestamp": "2026-05-18T14:36:22.000Z",
"incident": {
"id": "inc_abc123",
"url": "https://app.pingsla.com/incidents/inc_abc123",
"status": "resolved",
"createdAt": "2026-05-18T14:32:00.000Z",
"resolvedAt": "2026-05-18T14:36:22.000Z",
"durationSeconds": 262
},
"monitor": {
"id": "mon_xyz456",
"name": "Production API Health",
"type": "http",
"url": "https://api.yourapp.com/health"
},
"workspace": {
"id": "ws_xxxxxxxxx",
"name": "Acme Corp"
}
}
Payload Verification (HMAC-SHA256)
If you configure a webhook secret, PingSLA signs every request with HMAC-SHA256.
X-PingSLA-Signature: sha256=3d7e2c1a...
X-PingSLA-Timestamp: 1716042720
Verify in your receiver:
import crypto from 'crypto';
function verifyPingSLAWebhook(body, signature, timestamp, secret) {
const payload = `${timestamp}.${JSON.stringify(body)}`;
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signature)
);
}
Always verify webhook signatures in production. Unverified webhooks can be spoofed to trigger false incident reports in your systems.
Integration Recipes
PagerDuty
PagerDuty exposes native webhook ingestion. Use the PagerDuty Events API v2 endpoint:
https://events.pagerduty.com/v2/enqueue
Map PingSLA payload fields to PagerDuty:
// Your bridge function (Lambda or Express endpoint)
app.post('/pingsla-to-pagerduty', async (req, res) => {
const { event, monitor, failure } = req.body;
const pdPayload = {
routing_key: process.env.PAGERDUTY_INTEGRATION_KEY,
event_action: event === 'incident.created' ? 'trigger' : 'resolve',
dedup_key: req.body.incident.id,
payload: {
summary: `${monitor.name} is DOWN — ${failure?.reason ?? 'recovered'}`,
source: monitor.url,
severity: 'critical',
},
};
await fetch('https://events.pagerduty.com/v2/enqueue', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(pdPayload),
});
res.sendStatus(200);
});
Slack (Custom Format)
Use a webhook to build a custom Slack message if the native Slack channel doesn't meet your formatting needs.
Custom Ticketing / JIRA
POST the webhook payload to a Lambda or Express micro-service that translates it to a JIRA issue creation call.
Retry Behavior
| Attempt | Delay |
|---|---|
| Initial | Immediate |
| Retry 1 | 30 seconds |
| Retry 2 | 2 minutes |
| Retry 3 | 8 minutes |
After 3 failed retries, the delivery is marked as failed. The incident timeline records all delivery attempts.
Troubleshooting
| Issue | Resolution |
|---|---|
| Webhook receives no requests | Verify URL is HTTPS and publicly reachable |
| 401 / 403 from receiver | Add PingSLA to IP allowlist or fix auth config |
| Signature mismatch | Ensure you hash the raw body before JSON.parse |
| Test succeeds, real events don't | Verify alert policy is attached to the monitor |