Mailpro

Developer Portal

Webhooks — three directions, one logic

At Mailpro the word “webhook” covers three different mechanisms. They serve different needs and are configured in different places — the direction of the arrow makes all the difference.

A
Mailpro → your tool

Event webhooks

Be notified in real time when something happens in your account: email delivered, bounce, new contact, SMS delivered, low credits… Signed JSON POST to your URL, with automatic retries.

Where: Settings → Webhooks in the app, or POST /Webhook (CRM API v3), POST /webhooks (Email / SMS API v2).
Reference in the CRM API docs →
B
Your automation → a tool

Webhook targets

At a given step of a workflow, push information to Slack, your ERP, a Google Sheet, Zapier… JSON body with variables, custom headers, optional HMAC signing key (X-Mailpro-Automation-Signature). No extra credit.

Where: Automations → Webhook targets, then the “Send a webhook” action in the workflow editor.
How to use the action →
C
A tool → Mailpro

Incoming webhook (trigger)

Start a Mailpro automation from outside: a Stripe payment, a Typeform answer, a sign-up on your website. A secret URL, shown once when the workflow is activated; any JSON body up to 256 KB; answers 202 Accepted.

Where: in the automation, the “Incoming webhook” trigger.
How to set up the trigger →

Which events can you receive? (A)

Up to 50 events per webhook, 20 webhooks per account. The technical name is what arrives in the type field of the envelope. The data payload of each type is documented in the API reference.

contact.createdcontact.updatedcontact.deleted list.contact_addedlist.contact_removed tag.appliedtag.removedsegment.matched email.processedemail.deliveredemail.openedemail.clicked email.bouncedemail.droppedemail.unsubscribedemail.spam_report campaign.startedcampaign.finished sms.queuedsms.sentsms.deliveredsms.failed import.startedimport.progressimport.completedimport.failed credits.email.lowcredits.sms.lowapi.limit.lowapi.limit.reached

The envelope

Every event shares the same JSON envelope. Use id as an idempotency key: a retried delivery carries the same id.

{
  "id": "evt_5f2c…",
  "type": "email.delivered",
  "created": 1758000000,
  "apiVersion": "v3",
  "account": { "id": 12345, "name": "ACME" },
  "data": {
    "email": "[email protected]",
    "idSending": 987654,
    "sendingType": 3,
    "diagCode": "250 2.0.0 OK",
    "deliveredAt": "2026-09-16T08:03:41Z"
  }
}

Verify the signature

Each call carries X-Mailpro-Signature: t=<unix>,v1=<hex>. v1 is the HMAC-SHA256 of t + "." + raw body with the secret shown once at creation. Reject stale timestamps, answer 2xx within 10 seconds, process asynchronously.

On failure Mailpro retries 10 s → 1 min → 5 min → 30 min → 2 h → 6 h → 24 h, then disables the webhook after 10 consecutive failures (one click to reactivate).

// Node.js
const crypto = require("crypto");
function verify(rawBody, header, secret) {
  const t  = header.match(/t=([0-9]+)/)[1];
  const v1 = header.match(/v1=([0-9a-f]+)/)[1];
  const expected = crypto.createHmac("sha256", secret)
                         .update(t + "." + rawBody).digest("hex");
  const fresh = Math.abs(Date.now() / 1000 - Number(t)) < 300;
  return fresh && crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
}

Delivery tracking of transactional emails

Every single send (API v2, API v3, SMTP relay, automation — not campaigns) returns an identifier. Poll GET /Send/{id}/Status (v3) or GET /send/{id}/status.json (v2), or subscribe to email.delivered / email.bounced. The delivered status appears about 5 minutes after the handover and is kept for 365 days.

statusMeaning
queuedAccepted, waiting to be sent.
scheduledPlanned for a later date.
sentHanded over by our servers, no answer from the recipient server yet.
deferredThe recipient server asked us to retry later — we do.
deliveredAccepted by the recipient server (diag_code = its SMTP reply).
bouncedRejected — bounce_type tells permanent from temporary.
not_foundUnknown id, or an id that does not belong to your account.