Webhooks

Template Variables and Payloads

Use delivery context in URLs, headers, query parameters, and body templates.

Webhook destinations can render templates for the URL, headers, query parameters, and body. Template variables use double braces around a path.

{{ event.type }}
{{ workspace.uuid }}
{{ contact.attributes.email }}

Common template variables

VariableDescription
event.idUnique event id for the delivery event.
event.typeEvent type, such as contact.created.
event.occurred_atISO timestamp for when the event occurred.
event.testtrue for an explicit synthetic test; otherwise false.
event.duplicateWhether this is a repeated occurrence of the message event.
event.click_duplicateWhether this is a repeated click for the same tracked link.
event.sub_statusBounce subtype, such as soft_bounce or hard_bounce.
event.reasonFailure, bounce, rejection, or complaint reason.
event.urlClicked URL for message.clicked.
event.ip_addressRecorded IP for open and click events.
event.user_agentRecorded user agent for open and click events.
workspace.uuidWorkspace UUID.
workspace.nameWorkspace name.
contact._idContact id.
contact.workspace_uuidWorkspace UUID stored on the contact.
contact.subscribedContact subscription state.
contact.providerContact provider value when present.
contact.attributes.emailEmail attribute when present.
changes.beforePrevious values for changed fields when available.
changes.afterNew values for changed fields when available.
message.idLeadpush message id.
message.contact_idAssociated contact id when present.
message.channelMessage channel, currently email.
message.recipientRecipient email address.
message.fromRendered sender address.
message.subjectMessage subject.
message.statusCurrent Leadpush message status.
message.source.typesmtp, newsletter, or campaign.
message.source.idNewsletter or campaign id when present.
message.source.nameNewsletter or campaign name when available.
message.template_idTemplate id when present.
message.tagMessage tag when present.
message.providerResolved inbox provider when present.
message.simulatedWhether the payload describes a simulation. Live message webhooks are always false.
message.created_atMessage creation time.
delivery.uuidWebhook delivery UUID.
delivery.event_idEvent id stored on the delivery.
destination.uuidDestination UUID.
destination.nameDestination name.

If a path is missing, Leadpush renders it as an empty string.

Contact lifecycle payload

Contact lifecycle deliveries include the event, workspace, contact, changes, and campaign fields.

{
  "event": {
    "id": "495d190d-d423-4cf9-8f99-d1efd5cb8750",
    "type": "contact.updated",
    "occurred_at": "2026-04-22T18:30:00+00:00",
    "test": false,
    "duplicate": false,
    "click_duplicate": null,
    "sub_status": null,
    "reason": null,
    "url": null,
    "ip_address": null,
    "user_agent": null
  },
  "message": null,
  "workspace": {
    "uuid": "9a8b7c6d-1111-2222-3333-444455556666",
    "name": "Example Workspace"
  },
  "contact": {
    "_id": "contact_123",
    "workspace_uuid": "9a8b7c6d-1111-2222-3333-444455556666",
    "subscribed": true,
    "provider": null,
    "attributes": {
      "email": "person@example.com",
      "first_name": "Avery"
    },
    "created_at": "2026-04-20T14:15:00+00:00",
    "updated_at": "2026-04-22T18:30:00+00:00"
  },
  "changes": {
    "before": {
      "attributes.first_name": "Ava"
    },
    "after": {
      "attributes.first_name": "Avery"
    }
  },
  "campaign": null
}

Message event payload

Message deliveries include the event envelope, message, and the associated contact when one exists. Engagement and failure details are stored on event.

{
  "event": {
    "id": "6b3016ce-2d8f-46ca-ab1f-f56d01ef77b4",
    "type": "message.clicked",
    "occurred_at": "2026-04-22T18:42:00+00:00",
    "test": false,
    "duplicate": false,
    "click_duplicate": false,
    "sub_status": null,
    "reason": null,
    "url": "https://example.com/get-started",
    "ip_address": "203.0.113.10",
    "user_agent": "Example Browser"
  },
  "contact": {
    "_id": "contact_123",
    "workspace_uuid": "9a8b7c6d-1111-2222-3333-444455556666",
    "subscribed": true,
    "provider": null,
    "attributes": {
      "email": "person@example.com",
      "first_name": "Avery"
    },
    "created_at": "2026-04-20T14:15:00+00:00",
    "updated_at": "2026-04-22T18:30:00+00:00"
  },
  "message": {
    "id": "message_123",
    "contact_id": "contact_123",
    "channel": "email",
    "recipient": "person@example.com",
    "from": "Example <sender@example.com>",
    "subject": "Welcome to Example",
    "status": "delivered",
    "source": {
      "type": "campaign",
      "id": "campaign_123",
      "name": "Welcome Campaign"
    },
    "template_id": "template_123",
    "tag": "onboarding",
    "provider": null,
    "simulated": false,
    "created_at": "2026-04-22T18:30:00+00:00"
  }
}

For message.deferred and message.bounced, use event.sub_status and event.reason. For message.rejected and message.complained, use event.reason. A message without a Leadpush contact has contact: null.

Every stored open and click produces an event. Receivers should use event.id to deduplicate retries and can use the duplicate flags when they only need the first engagement.

Test payload

Manual tests can send webhook.test or a synthetic sample for any contact or message event. Synthetic samples never use real workspace contact or message data and always set event.test to true.

Synthetic message.* samples use the same lean message-event shape shown above and omit the top-level workspace, changes, and campaign fields. The generic webhook.test payload remains:

{
  "event": {
    "id": "15530cce-a0d9-4351-ada7-294b9ac87b01",
    "type": "webhook.test",
    "occurred_at": "2026-04-22T18:35:00+00:00",
    "test": true,
    "duplicate": false,
    "click_duplicate": null,
    "sub_status": null,
    "reason": null,
    "url": null,
    "ip_address": null,
    "user_agent": null
  },
  "workspace": {
    "uuid": "9a8b7c6d-1111-2222-3333-444455556666",
    "name": "Example Workspace"
  },
  "contact": null,
  "message": null,
  "changes": {
    "before": {},
    "after": {}
  },
  "campaign": null
}

Template examples

URL template:

https://example.com/hooks/{{ event.type }}/{{ contact._id }}

Query template:

KeyValue
workspace{{ workspace.uuid }}
event{{ event.type }}

Body template:

{
  "type": "{{ event.type }}",
  "contact_id": "{{ contact._id }}",
  "email": "{{ contact.attributes.email }}",
  "delivery": "{{ delivery.uuid }}"
}

Default request body

When no body template is configured, Leadpush sends the full event payload for HTTP methods that send a body by default. This includes POST, PUT, PATCH, and DELETE.

GET destinations do not send a request body unless a body template is configured.

Troubleshooting