Sitelet https://maple.dev/docs/reference/webhooks/
Skip to content
Maple Docs
Open app
Browse the docs
On this page

Alert webhooks

The webhook destination contract: request headers, the JSON payload for each event, verifying the HMAC signature, retries, and idempotency.

A webhook notification destination sends every alert event to a URL you own. This page is the contract your endpoint can rely on.

The request

Maple sends a POST with a JSON body and these headers:

HeaderValue
content-typeapplication/json
x-maple-event-typetrigger, resolve, renotify or test
x-maple-delivery-keyA stable ID for this delivery. Retries reuse it; use it to deduplicate.
x-maple-signatureHex HMAC-SHA256 of the raw body. Only sent when a signing secret is set.

Respond with any 2xx within 15 seconds. The response body is ignored.

Events

EventSent when
triggerAn incident opens, after the rule’s required number of consecutive breaching checks
renotifyAn incident is still breaching after the rule’s re-notify interval (30 minutes by default)
resolveAn incident closes, after the rule’s required number of consecutive healthy checks
testYou press Send test on the destination, or test a rule with notifications on

Payload

{
	"eventType": "trigger",
	"incidentId": "b6f1…",
	"incidentStatus": "open",
	"dedupeKey": "org_…:alrt_…:checkout",
	"rule": {
		"id": "alrt_…",
		"name": "Checkout error rate",
		"signalType": "error_rate",
		"severity": "critical",
		"groupKey": "checkout",
		"comparator": "gt",
		"threshold": 5,
		"thresholdUpper": null,
		"windowMinutes": 5
	},
	"observed": { "value": 8.4, "sampleCount": 1250 },
	"template": null,
	"chart": { "url": "https://…" },
	"linkUrl": "https://app.maple.dev/alerts/…",
	"chatUrl": "https://app.maple.dev/chat?…",
	"sentAt": "2026-09-25T09:14:00.000Z",
	"event": { "specversion": "1.0", "type": "dev.maple.alert.lifecycle.trigger.v1", "…": "…" }
}
FieldDescription
eventTypeSame as the x-maple-event-type header
incidentIdThe incident this event belongs to. null for tests.
incidentStatusopen or resolved
dedupeKeyStable for one incident across trigger, renotify and resolve. Use it to thread events together.
rule.signalTypeerror_rate, p95_latency, p99_latency, apdex, throughput, builder_query or raw_query
rule.severitywarning or critical
rule.groupKeyThe group that breached, such as a service name. __total__ for an ungrouped rule.
rule.comparatorgt, gte, lt, lte, eq, neq, between or not_between
rule.thresholdThe threshold, or the lower bound for between and not_between
rule.thresholdUpperThe upper bound for between and not_between, otherwise null
rule.windowMinutesThe evaluation window
observed.valueThe value the check measured
observed.sampleCountHow many data points the value was computed from
templateThe rule’s rendered notification template, or null
charturl of a chart image and/or a sparkline, or null
linkUrlThe incident in the Maple dashboard
chatUrlOpens Maple’s AI chat with the incident as context
sentAtISO-8601 time the event was first generated. Retries keep the original value.
eventThe same event as a CloudEvents 1.0 envelope, for routers that speak CloudEvents

The body is identical for every destination’s webhook, regardless of the rule’s notification template. Treat unknown fields as additive: new fields can appear without notice.

Error issue notifications

A destination listed in your organization’s error notification policy (set with the update_error_notification_policy MCP tool or the API) also receives error issue events: a new issue, a regression, a resolve, and optionally workflow changes and claims. They carry the same headers and a smaller body: eventType, incidentId, incidentStatus, dedupeKey, rule, observed, linkUrl, chatUrl and sentAt, without event, template or chart. Here rule.id is the issue ID, rule.name reads <ExceptionType> in <service>, and observed.value is the occurrence count. dedupeKey starts with error:.

Issues escalated by triage arrive with eventType: "escalation" in the body and an extra escalation object describing the issue. The x-maple-event-type header on these reads trigger, so branch on the body’s eventType.

Verifying the signature

Set a signing secret on the destination and Maple signs each body. The signature is the lowercase hex HMAC-SHA256 of the exact bytes of the request body, keyed with the secret, with no prefix. Compute it over the raw body before parsing the JSON, and compare in constant time.

import { createHmac, timingSafeEqual } from "node:crypto"

export function isFromMaple(rawBody: Buffer, signature: string | undefined, secret: string): boolean {
	if (!signature) return false
	const expected = createHmac("sha256", secret).update(rawBody).digest()
	const received = Buffer.from(signature, "hex")
	return received.length === expected.length && timingSafeEqual(received, expected)
}
import hashlib, hmac

def is_from_maple(raw_body: bytes, signature: str | None, secret: str) -> bool:
    if not signature:
        return False
    expected = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, signature)

The signature covers the body only, and the body carries no delivery timestamp you can trust for freshness, so a captured request could be replayed. Deduplicate on x-maple-delivery-key to make replays harmless.

Retries and failures

Your responseWhat Maple does
2xxDelivered
408, 429, 5xx, timeout, connection errorRetries with backoff
401, 403Fails without retrying (authentication problem)
404, 410Fails without retrying (endpoint gone)
Any other 4xxFails without retrying (rejected)

Alert events are attempted up to 5 times, about 1, 2, 4 and 8 minutes apart, with every retry carrying the same body and x-maple-delivery-key. Send test is attempted once.

After 3 consecutive non-retryable failures, the destination is disabled and the reason is shown on it under Alerts → Destinations. Fix the endpoint and re-enable it; a successful delivery resets the count.

Endpoint checklist

  • Read the raw body, verify the signature, then parse.
  • Return 2xx quickly and do slow work asynchronously; anything past 15 seconds is a failed attempt.
  • Deduplicate on x-maple-delivery-key; retries are normal.
  • Group by dedupeKey to follow one incident from trigger to resolve.
  • Accept test events so Send test succeeds.