API reference
Webhooks
Get a signed POST to your server when a bulk job finishes, instead of polling.
Payload
Pass webhook_url when you create a job. When it completes we send:
POST your-webhook-url
{
"event": "job.completed",
"job": {
"id": "79f348c5-…",
"name": "October newsletter",
"status": "completed",
"total": 5000,
"processed": 5000,
"counts": { "deliverable": 3120, "undeliverable": 911, "risky": 802, "unknown": 167 },
"created_at": "…",
"completed_at": "…"
}
}Respond with any 2xx status. We make up to 4 attempts over about seven minutes before giving up.
Verifying signatures
Each request has an X-Webhook-Signature header: sha256= followed by the hex HMAC-SHA256 of the raw body, keyed with your workspace's signing secret. Find the secret on the Webhooks page of the dashboard. Always check it before trusting the payload.
import crypto from "node:crypto";
// Use the raw request body, before JSON parsing.
export function verifySignature(rawBody: Buffer, header: string | undefined) {
const expected = "sha256=" + crypto
.createHmac("sha256", process.env.WEBHOOK_SECRET!)
.update(rawBody)
.digest("hex");
return !!header && header.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(header));
}