Webhooks & events
Receive signed event callbacks from Reeve — register a URL, verify the HMAC signature, and handle delivery events.
Webhooks & events
Webhooks let your integration react to things that happen in Reeve without polling. You register an HTTPS endpoint for an event type; when a matching event occurs, Reeve POSTs the event to your URL with a signature you can verify.
Webhooks are currently available for Comms delivery events. Each subscription is scoped to your app, so you only receive events for your own activity. Other event sources will be documented here as they become public.
How it works
- You register a webhook: an HTTPS URL + an event type to subscribe to.
- When that event occurs, Reeve sends a
POSTto your URL with the event payload as the request body. - Reeve signs each request with an HMAC-SHA256 signature so you can confirm it really came from Reeve.
- Your endpoint verifies the signature and responds quickly with a
2xx.
A URL can subscribe to multiple event types; registering the same URL for the same event twice is a no-op.
Comms delivery events
For the Comms product, you can subscribe to these delivery lifecycle events:
| Event | When it fires |
|---|---|
sent | A message was handed off for delivery |
delivered | The provider confirmed delivery |
bounced | Delivery failed (hard or soft bounce) |
opened | The recipient opened the message |
clicked | The recipient clicked a link |
complaint | The recipient marked the message as spam |
unsubscribed | The recipient unsubscribed |
Verifying the signature
Reeve signs each webhook request with an HMAC-SHA256 of a timestamp plus the raw request body, using the secret you were given when you registered the webhook. The signature is sent in a header of the form:
X-Reeve-Comms-Signature: t=<timestamp>,v1=<hex_hmac>To verify, recompute HMAC_SHA256(secret, "<timestamp>.<raw_body>") and compare it (in constant time) to the v1 value:
import crypto from 'node:crypto';
function verifyWebhook(rawBody, signatureHeader, secret) {
const parts = Object.fromEntries(
signatureHeader.split(',').map((kv) => kv.split('=')),
);
const expected = crypto
.createHmac('sha256', secret)
.update(`${parts.t}.${rawBody}`)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(parts.v1),
);
}Verify the signature against the raw, unparsed request body. Parsing and re-serializing the JSON first can change bytes (key order, whitespace) and break verification. Reject any request whose signature doesn't match.
Responding
Return a 2xx status as soon as you've accepted the event. Do any slow work asynchronously — a slow handler can cause retries. If your endpoint returns an error or times out, Reeve may retry delivery.
Registering a webhook
Webhook subscriptions are managed through the Reeve app / API for the Comms product. Each subscription stores your URL, the event type, and the signing secret used to verify deliveries.
Flagged: The exact public endpoint for self-service webhook registration is part of the Comms product surface and may not yet be exposed in the committed API reference. This page documents the verified event model, event types, and signature scheme; the registration call should be confirmed against the live API before you build against it.