Render25 — High-performance transactional email platform. Now available.
Platform

Webhooks

Receive real-time HTTP notifications when email events occur — delivered, bounced, opened, clicked, or marked as spam.

Create a Webhook

Navigate to Settings → Webhooks and click Add Endpoint. Enter a publicly accessible HTTPS URL that Render25 will POST events to.

Warning

The endpoint URL must use HTTPS. HTTP endpoints will be rejected.

Event Types

EventDescription
email.deliveredMessage accepted by the recipient mail server
email.bouncedDelivery permanently failed (hard bounce)
email.soft_bouncedDelivery temporarily failed (soft bounce)
email.openedRecipient opened the email (pixel tracked)
email.clickedRecipient clicked a tracked link
email.complainedRecipient marked the email as spam
email.unsubscribedRecipient clicked an unsubscribe link

Payload Format

Each webhook event is delivered as a JSON POST request. All events share a common envelope:

webhook payload
{
  "id": "evt_01J3K9X7YDBTKMR5NXQZG4HW",
  "type": "email.delivered",
  "created_at": "2024-09-12T10:42:05Z",
  "data": {
    "message_id": "msg_01J3K9X7YDBTKMR5NXQZG4HWFP",
    "to": "[email protected]",
    "subject": "Welcome!",
    "domain": "yourdomain.com",
    "tags": ["welcome"]
  }
}

Signature Verification

Every webhook request includes a Render25-Signature header containing an HMAC-SHA256 signature. Always verify this signature before processing the payload.

verify-webhook.ts
import crypto from "crypto";

function verifyWebhook(
  payload: string,
  signature: string,
  secret: string
): boolean {
  const expected = crypto
    .createHmac("sha256", secret)
    .update(payload)
    .digest("hex");
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

// In your route handler:
const sig = request.headers.get("Render25-Signature") ?? "";
const body = await request.text();
if (!verifyWebhook(body, sig, process.env.WEBHOOK_SECRET!)) {
  return new Response("Unauthorized", { status: 401 });
}

Always verify signatures

Processing webhook events without signature verification exposes your application to spoofed requests. Never skip this step in production.

Retry Policy

If your endpoint returns a non-2xx status code or times out (timeout is 10s), Render25 retries the delivery with exponential backoff:

AttemptDelay
1st retry30 seconds
2nd retry5 minutes
3rd retry30 minutes
4th retry2 hours
5th retry5 hours — final attempt