Mailpark
API reference

Webhooks

Mailpark POSTs events to your URL as they happen: deliveries, bounces, complaints, opens, clicks, unsubscribes, sequence entries and exits, held broadcasts. Each request is signed; see verifying webhooks.

Failed deliveries are retried for up to 24 hours. Deduplicate on the event id.

The Webhook object
type Webhook = {
  id: string; url: string;
  event_kinds: WebhookKind[];
  status: "active" | "failing" | "disabled";
  failing_since: string | null;
  signing_secret?: string;     // only in the create response
  created_at: string;
};

type WebhookKind = "email.sent" | "email.delivered" | "email.bounced" | "email.complained"
  | "email.opened" | "email.clicked" | "email.unsubscribed"
  | "sequence.entered" | "sequence.exited" | "broadcast.held" | "account.paused";

Add a webhook

POST/v1/webhooks

Starts sending the chosen event kinds to your URL. The response includes signing_secret, shown only once: store it as an environment variable.

scope webhooks:write

Body

  • urlstringrequired

    HTTPS endpoint that accepts POST.

  • event_kindsWebhookKind[]required

    e.g. email.bounced, email.complained.

curl -X POST https://api.mailpark.io/v1/webhooks \
  -H "Authorization: Bearer $MAILPARK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://acme.dev/api/mailpark-webhook",
    "event_kinds": [
      "email.bounced",
      "email.complained",
      "email.unsubscribed"
    ]
  }'
Response · 200
{
  "id": "wh_3Nd8",
  "url": "https://acme.dev/api/mailpark-webhook",
  "event_kinds": [
    "email.bounced",
    "email.complained",
    "email.unsubscribed"
  ],
  "status": "active",
  "failing_since": null,
  "created_at": "2026-10-22T10:02:11Z",
  "signing_secret": "whsec_9f8e7d6c5b4a"
}
▶ Try it in the playground

List webhooks

GET/v1/webhooks

All webhook endpoints and whether they're healthy.

curl https://api.mailpark.io/v1/webhooks \
  -H "Authorization: Bearer $MAILPARK_API_KEY"
Response · 200
{
  "data": [
    {
      "id": "wh_3Nd8",
      "url": "https://acme.dev/api/mailpark-webhook",
      "event_kinds": [
        "email.bounced",
        "email.complained",
        "email.unsubscribed"
      ],
      "status": "active",
      "failing_since": null,
      "created_at": "2026-10-22T10:02:11Z"
    }
  ],
  "next_cursor": null
}
▶ Try it in the playground

Get a webhook

GET/v1/webhooks/{id}

One webhook endpoint.

Path parameters

  • idstringrequired

    wh_…

curl https://api.mailpark.io/v1/webhooks/wh_3Nd8 \
  -H "Authorization: Bearer $MAILPARK_API_KEY"
Response · 200
{
  "id": "wh_3Nd8",
  "url": "https://acme.dev/api/mailpark-webhook",
  "event_kinds": [
    "email.bounced",
    "email.complained",
    "email.unsubscribed"
  ],
  "status": "active",
  "failing_since": null,
  "created_at": "2026-10-22T10:02:11Z"
}
▶ Try it in the playground

Delete a webhook

DELETE/v1/webhooks/{id}

Stops sending events to it.

scope webhooks:write

Path parameters

  • idstringrequired

    wh_…

curl -X DELETE https://api.mailpark.io/v1/webhooks/wh_3Nd8 \
  -H "Authorization: Bearer $MAILPARK_API_KEY"
Response · 200
{
  "deleted": true
}
▶ Try it in the playground

Send a test event

POST/v1/webhooks/{id}/test

Delivers a sample event to the endpoint now and returns the result, including the status code your server answered with.

Path parameters

  • idstringrequired

    wh_…

Body

  • kindWebhookKind

    Which event to send. Default: the first of the webhook's kinds.

curl -X POST https://api.mailpark.io/v1/webhooks/wh_3Nd8/test \
  -H "Authorization: Bearer $MAILPARK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "kind": "email.bounced"
  }'
Response · 200
{
  "id": "dlv_9Qa1",
  "webhook_id": "wh_3Nd8",
  "event_id": "evt_5Rc2",
  "kind": "email.bounced",
  "attempt": 1,
  "status": "succeeded",
  "status_code": 200,
  "response_ms": 84,
  "payload": {
    "id": "evt_5Rc2",
    "kind": "email.bounced",
    "created_at": "2026-10-22T10:02:11Z",
    "data": {
      "message_id": "msg_01JB4Q7Z2K",
      "type": "transactional",
      "to": "jane@example.com",
      "contact_id": "con_7Yt1",
      "template": "password-reset",
      "bounce_type": "hard",
      "environment": "test"
    }
  },
  "created_at": "2026-10-22T10:02:11Z"
}
▶ Try it in the playground

List deliveries

GET/v1/webhooks/{id}/deliveries

Recent delivery attempts with status codes and response times. retrying also covers "queued, first attempt not made yet".

Path parameters

  • idstringrequired

    wh_…

Query parameters

  • limitinteger

    How many to return, 1–100. Default 50.

  • cursorstring

    The next_cursor from the previous page.

curl https://api.mailpark.io/v1/webhooks/wh_3Nd8/deliveries \
  -H "Authorization: Bearer $MAILPARK_API_KEY"
Response · 200
{
  "data": [
    {
      "id": "dlv_9Qa1",
      "webhook_id": "wh_3Nd8",
      "event_id": "evt_5Rc2",
      "kind": "email.bounced",
      "attempt": 1,
      "status": "succeeded",
      "status_code": 200,
      "response_ms": 84,
      "payload": {
        "id": "evt_5Rc2",
        "kind": "email.bounced",
        "created_at": "2026-10-22T10:02:11Z",
        "data": {
          "message_id": "msg_01JB4Q7Z2K",
          "type": "transactional",
          "to": "jane@example.com",
          "contact_id": "con_7Yt1",
          "template": "password-reset",
          "bounce_type": "hard",
          "environment": "test"
        }
      },
      "created_at": "2026-10-22T10:02:11Z"
    }
  ],
  "next_cursor": null
}
▶ Try it in the playground

Resend a delivery

POST/v1/webhooks/{id}/deliveries/{delivery_id}/resend

Sends the same event again, as a new attempt.

Path parameters

  • idstringrequired

    wh_…

  • delivery_idstringrequired

    dlv_…

curl -X POST https://api.mailpark.io/v1/webhooks/wh_3Nd8/deliveries/dlv_9Qa1/resend \
  -H "Authorization: Bearer $MAILPARK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
Response · 200
{
  "id": "dlv_9Qa2",
  "webhook_id": "wh_3Nd8",
  "event_id": "evt_5Rc2",
  "kind": "email.bounced",
  "attempt": 2,
  "status": "succeeded",
  "status_code": 200,
  "response_ms": 84,
  "payload": {
    "id": "evt_5Rc2",
    "kind": "email.bounced",
    "created_at": "2026-10-22T10:02:11Z",
    "data": {
      "message_id": "msg_01JB4Q7Z2K",
      "type": "transactional",
      "to": "jane@example.com",
      "contact_id": "con_7Yt1",
      "template": "password-reset",
      "bounce_type": "hard",
      "environment": "test"
    }
  },
  "created_at": "2026-10-22T10:02:11Z"
}
▶ Try it in the playground