Outbound webhooks
Outbound webhooks are the escape hatch for anything GreenSlope doesn't integrate with natively. PagerDuty, Opsgenie, internal incident pipelines, custom escalation bots — point the webhook at your URL and we'll POST the same payload format as our native integrations.
For the full payload schema, see Webhook payloads.
Adding a webhook destination
- In the dashboard, Settings → Alerts → Webhook destinations.
- Click Add webhook.
- Paste the target URL. It must be HTTPS.
- Optionally pick a signing secret — we'll HMAC-sign every payload with it, so you can verify the request came from GreenSlope.
- Click Send test — we POST a test payload and show the response
code. Confirm
2xxbefore using the destination in a route.
Event kinds
A single webhook destination receives every event kind you enable:
alert.openedalert.acknowledgedalert.resolvedalert.escalatedchange_event.created
Pick the subset you care about per destination.
Signing and verification
If you configured a signing secret, every request carries a
x-greenslope-signature header containing an HMAC-SHA256 of the raw
request body. Verify:
import { createHmac, timingSafeEqual } from "node:crypto"
export function isValid(body: string, signature: string, secret: string) {
const expected = createHmac("sha256", secret).update(body).digest("hex")
return timingSafeEqual(Buffer.from(expected), Buffer.from(signature))
}Retries and delivery
- We retry
5xxand timeout (>10 s) responses with exponential backoff up to 24 hours. 4xxresponses (except 408) are treated as permanent failures — they go into the dead-letter view rather than retrying forever.- Per-destination delivery state is visible under Settings → Alerts → Webhook destinations → Activity.
Example: PagerDuty
To bridge into PagerDuty v2 Events API, point the webhook at a small Lambda (or similar) that translates the payload:
export default async function handler(body) {
if (body.kind === "alert.opened" && body.alert.severity === "sev1") {
await fetch("https://events.pagerduty.com/v2/enqueue", {
method: "POST",
body: JSON.stringify({
routing_key: process.env.PD_ROUTING_KEY,
event_action: "trigger",
dedup_key: body.alert.id,
payload: {
summary: body.alert.title,
severity: "critical",
source: body.alert.service,
custom_details: body.alert
}
})
})
}
}V2+ will ship a native PagerDuty integration (ADR 0011). Until then, this pattern is supported and our API stability contract applies.
Related