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-Signature—t=<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.