> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mailofly.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhooks

# Webhooks

Mailofly can POST signed JSON to your HTTPS endpoint when mail log status changes — no polling required.

Configure endpoints in the panel under **API → Webhooks** (organization admins).

***

## Events

| Event           | When it fires                             |
| --------------- | ----------------------------------------- |
| `mail.sent`     | Message handed off to the provider        |
| `mail.failed`   | Send attempt failed                       |
| `mail.deferred` | Queued for a later day (daily quota)      |
| `mail.halted`   | Send halted (when that status is written) |

Open/click and provider delivery/bounce events (`mail.delivered`, `mail.bounced`) are not available yet.

***

## Source filter

Each webhook can subscribe to a **source**:

| Source          | Matches               |
| --------------- | --------------------- |
| `all`           | Any mail log          |
| `transactional` | `campaign_id` is null |
| `campaign`      | `campaign_id` is set  |

The payload always includes `campaign_id` (nullable) so consumers can branch further.

***

## Payload shape

```json theme={null}
{
  "type": "mail.sent",
  "created_at": "2026-08-08T12:00:00.000Z",
  "data": {
    "mail_log_id": "uuid",
    "to_email": "user@example.com",
    "subject": "Hello",
    "status": "sent",
    "campaign_id": null,
    "campaign_run_id": null,
    "account_id": "uuid",
    "contact_id": null,
    "error": null,
    "sent_at": "2026-08-08T12:00:00.000Z",
    "organization_id": "uuid"
  }
}
```

***

## Request headers

| Header                   | Description                              |
| ------------------------ | ---------------------------------------- |
| `Content-Type`           | `application/json`                       |
| `X-Mailofly-Event`       | Event name (e.g. `mail.sent`)            |
| `X-Mailofly-Delivery-Id` | Unique delivery id (use for idempotency) |
| `X-Mailofly-Timestamp`   | Unix seconds when the request was signed |
| `X-Mailofly-Signature`   | `t=<timestamp>,v1=<hex>` HMAC-SHA256     |

Signing string: `HMAC-SHA256(secret, "${timestamp}.${rawBody}")` where `rawBody` is the exact JSON body bytes.

***

## Verify signature (Node.js)

```js theme={null}
import { createHmac, timingSafeEqual } from "crypto";

function verify(secret, header, rawBody, toleranceSec = 300) {
  const parts = Object.fromEntries(
    header.split(",").map((p) => {
      const [k, ...rest] = p.trim().split("=");
      return [k, rest.join("=")];
    }),
  );
  const timestamp = parts.t;
  const signature = parts.v1;
  if (!timestamp || !signature) return false;

  const age = Math.abs(Math.floor(Date.now() / 1000) - Number(timestamp));
  if (age > toleranceSec) return false;

  const expected = createHmac("sha256", secret)
    .update(`${timestamp}.${rawBody}`, "utf8")
    .digest("hex");

  const a = Buffer.from(expected, "utf8");
  const b = Buffer.from(signature, "utf8");
  return a.length === b.length && timingSafeEqual(a, b);
}
```

Respond with **2xx** quickly. Non-2xx responses are retried with backoff (about 1m → 5m → 30m → 2h, up to 5 attempts).

***

## Delivery worker (ops)

Retries and backlog are drained by:

`POST /api/webhooks/dispatch`

Auth: header `x-campaign-automation-secret` must match `CAMPAIGN_AUTOMATION_SECRET` (same secret as the mail queue worker).

Optional JSON body: `{ "limit": 20 }` (1–100).

Schedule with pg\_cron → pg\_net every minute (same pattern as `/api/mail/process-mail-queue`). New deliveries are also kicked best-effort in-process right after enqueue.

***

## Related

* [Mail logs](https://docs.mailofly.com/guides/mail-logs)
* [API: Mail logs](https://docs.mailofly.com/api/mail-logs)
* [REST API automation](rest-api-automation.md)


## Related topics

- [Integrations](/integrations/index.md)
- [Retries and debugging](/webhooks/retries-and-debugging.md)
- [Delete Webhook](/api/webhooks/delete-webhook.md)
- [List Webhooks](/api/webhooks/list-webhooks.md)
- [Create Webhook](/api/webhooks/create-webhook.md)
