Relayloft docsSign in

Webhooks

API base URL: https://api.relayloft.com

Add endpoints under Webhooks in the portal. Each event is a POST of JSON to your https URL, signed the same way as Resend's (Svix).

Events

email.scheduled, email.sent, email.delivered, email.delivery_delayed, email.bounced, email.complained, email.failed, email.suppressed, and with tracking on, email.opened and email.clicked.

{
  "type": "email.bounced",
  "created_at": "2026-09-25T10:00:00.000Z",
  "data": {
    "email_id": "…",
    "created_at": "2026-09-25T09:59:58.000Z",
    "from": "hello@mail.yourcompany.com",
    "to": ["user@example.com"],
    "subject": "Welcome",
    "tags": [{ "name": "flow", "value": "signup" }],
    "bounce": { "type": "Permanent", "subType": "General", "message": "…" }
  }
}

Extra fields by type: bounce (type, subType, message), complaint (type), delay (type, message), failed (reason), suppressed (message), click (ipAddress, link, timestamp, userAgent: camelCase, as Resend sends it). email.sent lists any suppressed_recipients it skipped.

Check the signature

Every request has svix-id, svix-timestamp and svix-signature headers. Verify them against the raw body with your endpoint's signing secret (whsec_..., shown once when you create or rotate it):

import { Webhook } from "svix"; // or resend.webhooks.verify(...)

const wh = new Webhook(process.env.RELAYLOFT_WEBHOOK_SECRET);
const event = wh.verify(rawBody, {
  "svix-id": req.headers["svix-id"],
  "svix-timestamp": req.headers["svix-timestamp"],
  "svix-signature": req.headers["svix-signature"],
});

After you rotate the secret, the old one keeps working for 24 hours: during that time each request carries both signatures. Use svix-id to drop duplicates.

Retries

Answer with any 2xx within 10 seconds. Anything else (including a redirect) is retried with growing gaps, for about 20 hours. An endpoint that fails for about 20 hours straight is turned off and your Owner is emailed; turn it back on in the portal. You can replay any delivery or send a test event from the portal.

Endpoint rules

https on the standard port, a public host name (not an IP address or an internal name), no user name or password in the URL. Checked when saved and before every delivery.