Inbound email

Webhooks

Get real-time inbound email events pushed to your endpoint. Register webhooks per sender ID, verify HMAC signatures, inspect deliveries, and handle retries.

Webhooks push the moment email arrives — no polling required. You register one or more webhook URLs per sender ID; MailAfrica delivers events with HMAC-SHA256 signatures you can verify.

Register a webhook

bash
curl -X POST https://api.mailafrica.online/api/webhook/webhooks \
  -H "X-API-Key: MAIL_<your_api_key_here>" \
  -H "Content-Type: application/json" \
  -d '{
    "address_id": 42,
    "url": "https://your-app.example.com/hooks/mailafrica",
    "secret": "your-own-secret"  // optional
  }'

Fields: address_id (required, must be an address you own), url (required, http/https), secret (optional — if omitted, a whsec_ + 32 hex secret is generated and returned once).

Store the returned secret securely — you need it to verify every delivery. It is only returned at creation time.

Event payloads

Real inbound events look like this (delivered with Content-Type: application/json and User-Agent: MailAfrica-Webhook/1.0):

json
{
  "event": "inbound.message_received",
  "webhook_id": 12,
  "address_id": 42,
  "message_id": 9001,
  "timestamp": "2026-08-15T09:30:00Z"
}

Fetch the full message with GET /api/inbound/messages/{message_id}. Test events use event: "webhook.test" and include a friendly message field.

Verify the signature

Every delivery carries the same HMAC-SHA256 hex signature in both X-Signature and X-Webhook-Signature headers. Compute it over the raw request body with your secret and compare (constant-time).

nodejs
import crypto from "node:crypto";

const secret = "whsec_..."; // from webhook creation

export function verifySignature(req, secret) {
  const signature = req.headers["x-webhook-signature"];
  const body = await readRawBody(req); // raw string, before JSON.parse
  const expected = crypto
    .createHmac("sha256", secret)
    .update(body)
    .digest("hex");
  return crypto.timingSafeEqual(
    Buffer.from(signature, "hex"),
    Buffer.from(expected, "hex"),
  );
}
Always verify before acting on the payload. Signature check protects you from forged deliveries.

Retries & deliveries

MailAfrica retries failed deliveries up to 3 attempts with 1s / 3s / 9s backoff and a 10s timeout. Inspect delivery history per webhook:

bash
curl https://api.mailafrica.online/api/webhook/webhooks/12/deliveries \
  -H "X-API-Key: MAIL_<your_api_key_here>"
json
[
  {
    "id": 501,
    "webhook_id": 12,
    "message_id": 9001,
    "status_code": 200,
    "attempt": 1,
    "delivered_at": "2026-08-15T09:30:01Z",
    "status": "delivered",
    "next_retry_at": null,
    "last_error": null,
    "created_at": "2026-08-15T09:30:00Z"
  }
]

Status is one of pending | retrying | delivered | failed. Return 2xx quickly from your handler so we stop at one attempt.

Test & manual trigger

curl -X POST https://api.mailafrica.online/api/webhook/webhooks/12/test \
  -H "X-API-Key: MAIL_<your_api_key_here>"

Manage webhooks

bash
# List webhooks for an address (address_id required)
curl "https://api.mailafrica.online/api/webhook/webhooks?address_id=42" \
  -H "X-API-Key: MAIL_<your_api_key_here>"

# Delete a webhook
curl -X DELETE https://api.mailafrica.online/api/webhook/webhooks/12 \
  -H "X-API-Key: MAIL_<your_api_key_here>"