PlunkPlunk
Guides

Webhooks

Send real-time event data from Plunk to your own application using webhooks

Plunk can send real-time HTTP requests to your application when specific events occur, such as email bounces, spam complaints, or custom events. This is done by creating a workflow that uses the Webhook step to forward event data to your own endpoint.

How it works

Webhooks in Plunk are powered by the workflow system. The basic flow is:

  1. An event occurs in Plunk (e.g. an email bounces, a contact subscribes, or a custom event is tracked)
  2. A workflow is triggered by that event
  3. The workflow executes a Webhook step, sending an HTTP request to your URL with relevant data

This means you can receive notifications for any event Plunk tracks, including both system events and your own custom events.

Internal events

Plunk automatically tracks a set of internal events that you can use as workflow triggers. These events cannot be manually tracked via the API — they are generated by the system.

Email events

EventDescription
email.sentAn email was successfully sent
email.deliveryAn email was delivered to the recipient
email.openA contact opened an email for the first time
email.clickA contact clicked a link in an email for the first time
email.bounceAn email bounced (hard or soft bounce)
email.complaintA contact marked an email as spam
email.receivedAn email was received at your verified domain (requires inbound email setup)

Contact events

EventDescription
contact.subscribedA contact's subscription status changed to subscribed
contact.unsubscribedA contact's subscription status changed to unsubscribed

Segment events

EventDescription
segment.<name>.entryA contact entered a segment
segment.<name>.exitA contact exited a segment

Segment event names

Segment events use a slugified version of the segment name. For example, a segment called "VIP Users" would produce the events segment.vip-users.entry and segment.vip-users.exit.

Setting up a webhook

Create the workflow

Navigate to the Workflows section in the dashboard and create a new workflow. Choose the event you want to listen for as the trigger. For example, to receive notifications when an email bounces, use email.bounce as the trigger event.

Add a Webhook step

After the trigger, add a Webhook step and configure it:

  • URL: The endpoint on your server that will receive the webhook (e.g. https://api.example.com/webhooks/plunk)
  • Method: The HTTP method to use. Defaults to POST, which is recommended for most use cases.
  • Headers (optional): Custom headers to include in the request, provided as JSON. This is useful for authentication.
{
  "Authorization": "Bearer your-secret-token"
}

Enable the workflow

Once configured, enable the workflow. It will start sending webhook requests whenever the trigger event occurs.

Webhook payload

When using the default payload (no custom body configured), Plunk sends a JSON request with the following structure:

{
  "contact": {
    "email": "user@example.com",
    "subscribed": true,
    "data": {
      "name": "John",
      "plan": "pro"
    }
  },
  "workflow": {
    "id": "wf_abc123",
    "name": "Bounce Notifications"
  },
  "execution": {
    "id": "exec_xyz789",
    "startedAt": "2025-01-15T10:30:00.000Z"
  },
  "event": {
    "subject": "Welcome to Plunk",
    "from": "hello@example.com",
    "fromName": "Plunk Team",
    "messageId": "ses-message-id",
    "templateId": null,
    "campaignId": "camp_abc123",
    "sourceType": "CAMPAIGN",
    "bounceType": "Permanent",
    "bouncedAt": "2025-01-15T10:30:00.000Z"
  }
}

The event field contains the data associated with the event that triggered the workflow. The exact contents depend on the event type.

Event data by type

Email events

Most email events share a common set of base fields:

FieldDescription
subjectThe email subject line
fromThe sender email address
fromNameThe sender display name
messageIdThe AWS SES message ID
templateIdThe template ID, if the email was sent using a template (otherwise null)
campaignIdThe campaign ID, if the email was part of a campaign (otherwise null)
sourceTypeHow the email was triggered: TRANSACTIONAL, CAMPAIGN, WORKFLOW, or INBOUND

In addition to these base fields, each event includes the following event-specific fields:

{
  "subject": "Welcome to Plunk",
  "from": "hello@example.com",
  "fromName": "Plunk Team",
  "messageId": "ses-message-id",
  "templateId": null,
  "campaignId": null,
  "sourceType": "TRANSACTIONAL",
  "sentAt": "2025-01-15T10:30:00.000Z"
}
FieldDescription
sentAtWhen the email was sent
{
  "subject": "Welcome to Plunk",
  "from": "hello@example.com",
  "fromName": "Plunk Team",
  "messageId": "ses-message-id",
  "templateId": null,
  "campaignId": "camp_abc123",
  "sourceType": "CAMPAIGN",
  "deliveredAt": "2025-01-15T10:30:05.000Z"
}
FieldDescription
deliveredAtWhen the email was delivered
{
  "subject": "Welcome to Plunk",
  "from": "hello@example.com",
  "fromName": "Plunk Team",
  "messageId": "ses-message-id",
  "templateId": null,
  "campaignId": null,
  "sourceType": "TRANSACTIONAL",
  "openedAt": "2025-01-15T11:00:00.000Z",
  "opens": 1,
  "isFirstOpen": true
}
FieldDescription
openedAtWhen the email was first opened
opensTotal number of times this email has been opened
isFirstOpentrue if this is the first time the contact opened the email
{
  "subject": "Welcome to Plunk",
  "from": "hello@example.com",
  "fromName": "Plunk Team",
  "messageId": "ses-message-id",
  "templateId": null,
  "campaignId": null,
  "sourceType": "TRANSACTIONAL",
  "link": "https://example.com/pricing",
  "clickedAt": "2025-01-15T11:05:00.000Z",
  "clicks": 1,
  "isFirstClick": true
}
FieldDescription
linkThe URL that was clicked
clickedAtWhen the first click occurred
clicksTotal number of times links in this email have been clicked
isFirstClicktrue if this is the first click from this contact on this email

Permanent bounce:

{
  "subject": "Welcome to Plunk",
  "from": "hello@example.com",
  "fromName": "Plunk Team",
  "messageId": "ses-message-id",
  "templateId": null,
  "campaignId": null,
  "sourceType": "TRANSACTIONAL",
  "bounceType": "Permanent",
  "bouncedAt": "2025-01-15T10:31:00.000Z"
}

Transient (soft) bounce:

{
  "subject": "Welcome to Plunk",
  "from": "hello@example.com",
  "fromName": "Plunk Team",
  "messageId": "ses-message-id",
  "templateId": null,
  "campaignId": null,
  "sourceType": "TRANSACTIONAL",
  "bounceType": "Transient",
  "transientBounce": true
}
FieldDescription
bounceTypePermanent (hard bounce) or Transient (soft bounce, e.g. mailbox full or out-of-office)
bouncedAtWhen the bounce occurred (permanent bounces only)
transientBouncetrue for soft bounces — these do not count toward bounce rate and the contact stays subscribed

Bounce rate impact

Only Permanent bounces count toward your project's bounce rate and trigger automatic contact unsubscription. Transient bounces are tracked for visibility only.

{
  "subject": "Welcome to Plunk",
  "from": "hello@example.com",
  "fromName": "Plunk Team",
  "messageId": "ses-message-id",
  "templateId": null,
  "campaignId": null,
  "sourceType": "TRANSACTIONAL",
  "complainedAt": "2025-01-15T10:35:00.000Z"
}
FieldDescription
complainedAtWhen the spam complaint was received

This event fires when an email is received at your verified domain. See Receiving Emails for setup instructions.

{
  "messageId": "ses-message-id",
  "from": "sender@example.com",
  "fromHeader": "Jane Smith <sender@example.com>",
  "to": "support@yourdomain.com",
  "subject": "Re: Your question",
  "timestamp": "2025-01-15T10:30:00.000Z",
  "recipients": ["support@yourdomain.com"],
  "hasContent": true,
  "spamVerdict": "PASS",
  "virusVerdict": "PASS",
  "spfVerdict": "PASS",
  "dkimVerdict": "PASS",
  "dmarcVerdict": "PASS",
  "processingTimeMillis": 142
}
FieldDescription
messageIdThe AWS SES message ID
fromThe sender's email address
fromHeaderThe full From header, including display name if present
toThe recipient address at your verified domain
subjectThe email subject line
timestampWhen SES received the email
recipientsAll recipient addresses in the envelope
hasContentWhether the email body content is available
spamVerdictSES spam check result: PASS, FAIL, GRAY, or PROCESSING_FAILED
virusVerdictSES virus check result
spfVerdictSPF authentication result
dkimVerdictDKIM authentication result
dmarcVerdictDMARC authentication result
processingTimeMillisTime SES took to process the inbound email

Contact events

contact.subscribed and contact.unsubscribed carry no event data by default. The event field will be an empty object {}.

The exception is when an unsubscription is triggered automatically by an email bounce or complaint — in that case event includes a reason field:

{
  "reason": "bounce"
}
FieldValue
reason"bounce" or "complaint" (when system-triggered)

Segment events

Both segment.<name>.entry and segment.<name>.exit include:

{
  "segmentId": "seg_abc123",
  "segmentName": "VIP Users"
}
FieldDescription
segmentIdThe ID of the segment
segmentNameThe display name of the segment

Custom events

Custom events tracked via the API include whatever data you passed in the data field when calling track.

No event data

For events that carry no data, the event field will be an empty object {}.

Common use cases

Bounce and complaint monitoring

Create a workflow triggered by email.bounce or email.complaint to forward these events to your application. This allows you to keep your own database in sync with Plunk's contact statuses.

You can use additional workflow steps before the webhook to add logic:

  • Condition: Only send the webhook for hard bounces by checking the bounceType field
  • Delay: Add a short delay to batch-process related events
  • Update Contact: Mark the contact with metadata before sending the webhook

Syncing unsubscribes

Trigger a workflow on contact.unsubscribed to notify your application when a contact opts out. This is useful for keeping subscription status synchronized across multiple systems.

Custom event forwarding

If you track custom events in Plunk (e.g. user.signup, order.completed), you can forward those same events to other services via webhooks. This turns Plunk into an event router — track once, distribute to multiple endpoints.

Adding conditions and delays

Since webhooks are part of the workflow system, you can combine them with other step types for more advanced setups:

  • Use a Condition step to only fire the webhook when certain criteria are met (e.g. only notify for contacts on a specific plan)
  • Use a Wait for Event step to wait for a follow-up event before sending the webhook (e.g. wait to see if a bounced contact re-subscribes)
  • Use a Delay step to add a time buffer before the webhook fires