Webhooks

Relay POSTs an event to your endpoint whenever a message is delivered, bounces, or is marked as spam — each one HMAC-signed so you can trust it.

Subscribing

Create a webhook in the console (or via POST /v1/webhooks) with a URL and the events you want (delivery, bounce, complaint). Relay returns a signing secret exactly once— store it.

Event payload

POST https://your-app/webhooks/relay
{
  "type": "bounce",
  "message_id": "msg_2h8Kd0Rk9Qa",
  "ses_message_id": "0100018f...",
  "recipients": ["ada@lovelace.io"],
  "timestamp": 1783386190864
}

Verifying the signature

Every delivery carries an X-Webhook-Signature: sha256=<hmac> header — the HMAC-SHA256 of the raw request body under your secret. Compute the same and compare in constant time before trusting the payload.

verify.js
import crypto from "node:crypto";

export function verify(rawBody, header, secret) {
  const expected =
    "sha256=" +
    crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
  // constant-time compare
  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(header),
  );
}

// in your handler:
if (!verify(rawBody, req.headers["x-webhook-signature"], SECRET)) {
  return res.status(401).end();
}

Return a 2xx quickly. Relay treats non-2xx as a failure and will retry with backoff.