Documentation

Webhooks

Receive real-time delivery events at your own endpoint — delivered, bounced, complained, opened, clicked — each one signed so you can verify it's really from us.

Create an endpoint

curl -X POST https://api.raanse.com/v1/webhooks \
  -H "Authorization: Bearer rk_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
        "url": "https://acme.co/webhooks/ranse",
        "eventTypes": [
          "Delivered",
          "Bounced"
        ]
      }'
The signingSecret is returned once, on creation. You need it to verify signatures — store it securely.

Verify the signature

Every request carries these headers:

  • Ranse-Signaturet=<unix>,v1=<hex>
  • Ranse-Event-Id — a stable id for the event (use it to dedupe)
  • Ranse-Event-Type — e.g. Delivered

Compute an HMAC-SHA256 over `${timestamp}.${rawBody}` with your signing secret and compare it to v1:

import crypto from "node:crypto";

function verify(rawBody, header, secret) {
  const [t, v1] = header.split(",").map((p) => p.split("=")[1]);
  const expected = crypto
    .createHmac("sha256", secret)
    .update(`${t}.${rawBody}`)
    .digest("hex");
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
}
Retries re-send the same Ranse-Event-Id, so make your handler idempotent — process each event id once.

Retries

If your endpoint doesn't return a 2xx, we retry with exponential backoff up to six times. Inspect the attempt log with list deliveries.