Webhooks
Endpoints that receive events, their secrets and their deliveries.
All requests go to https://api.padimail.app with Authorization: Bearer <your key>. Try these in the interactive reference with a pm_test_ key.
Add a webhook endpoint
POST/v1/webhooks
Body
| Field | Type | Required | Notes |
|---|---|---|---|
url | string (uri) | Yes | An HTTPS URL that answers 2xx within 10 seconds. |
description | string | No | |
event_types | ("email.queued" | "email.scheduled" | "email.deferred" | "email.sent" | "email.delivered" | "email.delivery_delayed" | "email.bounced" | "email.complained" | "email.opened" | "email.clicked" | "email.suppressed" | "email.held" | "email.released" | "email.rejected" | "email.failed" | "email.canceled" | "domain.verified" | "domain.failed" | "account.paused" | "account.resumed" | "account.quota_reached" | "account.usage_threshold" | "account.usage_spike")[] | Yes | The events to send, such as email.delivered. |
format | "padimail" | "resend" | No | resend sends Resend's event names and svix-* headers. |
mode | "live" | "test" | No |
Send an Idempotency-Key header to make retries safe. The Node SDK adds one for you.
Example
import { PadiMail } from "@padimail/node";
const pm = new PadiMail(process.env.PADIMAIL_API_KEY);
const result = await pm.webhooks.create({
url: "https://acme.ng/webhooks/padimail",
event_types: ["email.delivered", "email.bounced", "email.complained"],
});Response 200
{
"id": "wh_01JBX7Q3F6ZK0Q9W1Y2R3T4V5S",
"object": "webhook",
"mode": "live",
"url": "https://acme.ng/webhooks/padimail",
"description": "string",
"event_types": ["email.queued"],
"format": "padimail",
"status": "enabled",
"failing_since": "2026-10-27T13:05:09Z",
"created_at": "2026-10-27T13:05:09Z",
"secret": "whsec_…"
}List webhook endpoints
GET/v1/webhooks
Query parameters
| Field | Type | Required | Notes |
|---|---|---|---|
limit | integer | No | Page size, 1 to 100. Default 50. |
after | string | No | Return items after this ID (the next value of the previous page). |
before | string | No | Return items before this ID. |
Example
import { PadiMail } from "@padimail/node";
const pm = new PadiMail(process.env.PADIMAIL_API_KEY);
const result = await pm.webhooks.list();Response 200
{
"data": [
{
"id": "wh_01JBX7Q3F6ZK0Q9W1Y2R3T4V5S",
"object": "webhook",
"mode": "live",
"url": "https://acme.ng/webhooks/padimail",
"description": "string",
"event_types": ["email.queued"],
"format": "padimail",
"status": "enabled",
"failing_since": "2026-10-27T13:05:09Z",
"created_at": "2026-10-27T13:05:09Z"
}
],
"has_more": false,
"next": "string"
}Get a webhook endpoint
GET/v1/webhooks/{id}
Path parameters
| Field | Type | Required | Notes |
|---|---|---|---|
id | string | Yes |
Example
import { PadiMail } from "@padimail/node";
const pm = new PadiMail(process.env.PADIMAIL_API_KEY);
const result = await pm.webhooks.get("wh_01JBX7Q3F6ZK0Q9W1Y2R3T4V5S");Response 200
{
"id": "wh_01JBX7Q3F6ZK0Q9W1Y2R3T4V5S",
"object": "webhook",
"mode": "live",
"url": "https://acme.ng/webhooks/padimail",
"description": "string",
"event_types": ["email.queued"],
"format": "padimail",
"status": "enabled",
"failing_since": "2026-10-27T13:05:09Z",
"created_at": "2026-10-27T13:05:09Z"
}Update a webhook endpoint
PATCH/v1/webhooks/{id}
Path parameters
| Field | Type | Required | Notes |
|---|---|---|---|
id | string | Yes |
Body
| Field | Type | Required | Notes |
|---|---|---|---|
url | string (uri) | No | |
description | string | null | No | |
event_types | ("email.queued" | "email.scheduled" | "email.deferred" | "email.sent" | "email.delivered" | "email.delivery_delayed" | "email.bounced" | "email.complained" | "email.opened" | "email.clicked" | "email.suppressed" | "email.held" | "email.released" | "email.rejected" | "email.failed" | "email.canceled" | "domain.verified" | "domain.failed" | "account.paused" | "account.resumed" | "account.quota_reached" | "account.usage_threshold" | "account.usage_spike")[] | No | |
format | "padimail" | "resend" | No | |
status | "enabled" | "disabled" | No |
Example
import { PadiMail } from "@padimail/node";
const pm = new PadiMail(process.env.PADIMAIL_API_KEY);
const result = await pm.webhooks.update("wh_01JBX7Q3F6ZK0Q9W1Y2R3T4V5S", { status: "disabled" });Response 200
{
"id": "wh_01JBX7Q3F6ZK0Q9W1Y2R3T4V5S",
"object": "webhook",
"mode": "live",
"url": "https://acme.ng/webhooks/padimail",
"description": "string",
"event_types": ["email.queued"],
"format": "padimail",
"status": "enabled",
"failing_since": "2026-10-27T13:05:09Z",
"created_at": "2026-10-27T13:05:09Z"
}Delete a webhook endpoint
DELETE/v1/webhooks/{id}
Path parameters
| Field | Type | Required | Notes |
|---|---|---|---|
id | string | Yes |
Example
import { PadiMail } from "@padimail/node";
const pm = new PadiMail(process.env.PADIMAIL_API_KEY);
const result = await pm.webhooks.remove("wh_01JBX7Q3F6ZK0Q9W1Y2R3T4V5S");Response 200
{ "id": "string", "object": "string", "deleted": true }Rotate the signing secret (the old one works for 24 h)
POST/v1/webhooks/{id}/rotate-secret
Path parameters
| Field | Type | Required | Notes |
|---|---|---|---|
id | string | Yes |
Example
import { PadiMail } from "@padimail/node";
const pm = new PadiMail(process.env.PADIMAIL_API_KEY);
const result = await pm.webhooks.rotateSecret("wh_01JBX7Q3F6ZK0Q9W1Y2R3T4V5S");Response 200
{
"id": "wh_01JBX7Q3F6ZK0Q9W1Y2R3T4V5S",
"object": "webhook",
"mode": "live",
"url": "https://acme.ng/webhooks/padimail",
"description": "string",
"event_types": ["email.queued"],
"format": "padimail",
"status": "enabled",
"failing_since": "2026-10-27T13:05:09Z",
"created_at": "2026-10-27T13:05:09Z",
"secret": "whsec_…"
}Send a test event
POST/v1/webhooks/{id}/test
Path parameters
| Field | Type | Required | Notes |
|---|---|---|---|
id | string | Yes |
Body
| Field | Type | Required | Notes |
|---|---|---|---|
event_type | "email.queued" | "email.scheduled" | "email.deferred" | "email.sent" | "email.delivered" | "email.delivery_delayed" | "email.bounced" | "email.complained" | "email.opened" | "email.clicked" | "email.suppressed" | "email.held" | "email.released" | "email.rejected" | "email.failed" | "email.canceled" | "domain.verified" | "domain.failed" | "account.paused" | "account.resumed" | "account.quota_reached" | "account.usage_threshold" | "account.usage_spike" | Yes |
Example
import { PadiMail } from "@padimail/node";
const pm = new PadiMail(process.env.PADIMAIL_API_KEY);
const result = await pm.webhooks.test("wh_01JBX7Q3F6ZK0Q9W1Y2R3T4V5S", { event_type: "email.delivered" });Response 200
{ "delivery_id": "whd_01JBX7Q3F6ZK0Q9W1Y2R3T4V5S" }List deliveries (kept 30 days)
GET/v1/webhooks/{id}/deliveries
Path parameters
| Field | Type | Required | Notes |
|---|---|---|---|
id | string | Yes |
Query parameters
| Field | Type | Required | Notes |
|---|---|---|---|
limit | integer | No | Page size, 1 to 100. Default 50. |
after | string | No | Return items after this ID (the next value of the previous page). |
before | string | No | Return items before this ID. |
status | "pending" | "succeeded" | "failed" | No |
Example
import { PadiMail } from "@padimail/node";
const pm = new PadiMail(process.env.PADIMAIL_API_KEY);
const result = await pm.webhooks.deliveries.list("wh_01JBX7Q3F6ZK0Q9W1Y2R3T4V5S", { status: "failed" });Response 200
{
"data": [
{
"id": "whd_01JBX7Q3F6ZK0Q9W1Y2R3T4V5S",
"webhook_id": "wh_01JBX7Q3F6ZK0Q9W1Y2R3T4V5S",
"event_id": "evt_01JBX7Q3F6ZK0Q9W1Y2R3T4V5S",
"event_type": "string",
"attempt": 0,
"status": "pending",
"response_status": 0,
"response_body_excerpt": "string",
"duration_ms": 0,
"next_attempt_at": "2026-10-27T13:05:09Z",
"created_at": "2026-10-27T13:05:09Z"
}
],
"has_more": false,
"next": "string"
}Retry a delivery now
POST/v1/webhooks/{id}/deliveries/{did}/retry
Path parameters
| Field | Type | Required | Notes |
|---|---|---|---|
id | string | Yes | |
did | string | Yes |
Example
import { PadiMail } from "@padimail/node";
const pm = new PadiMail(process.env.PADIMAIL_API_KEY);
const result = await pm.webhooks.deliveries.retry("wh_01JBX7Q3F6ZK0Q9W1Y2R3T4V5S", "whd_01JBX7Q3F6ZK0Q9W1Y2R3T4V5S");Response 200
{ "delivery_id": "whd_01JBX7Q3F6ZK0Q9W1Y2R3T4V5S" }