Event
trigger.postmark_event
TriggerEmailconnection requiredruns in-engine
Registers a webhook on one message stream of the tenant's Postmark server on publish and starts one run per delivered event.
Start a run when Postmark reports a bounce, delivery, open, click or spam complaint.
Connection
- Required
- Yes — the node will not save without one
- Auth type
- API key
- Providers
- Postmark
- Secret shape
- the server API token, or {"server_token": "…"}
- Resolved by
- config.connection_id, else node.connection_id
- Note
- A server token, not an account token — webhooks are server-scoped. Publishing also needs MANTLE_APP_PUBLIC_BASE_URL set to an https URL Postmark can reach and answer 200 on: Postmark verifies the endpoint before it will save the webhook.
Configuration
2 fields, none required. A dotted path is a nested object and name[] an array of objects — the editor renders the same tree.
| Field | Type | Required | Default | Constraints | Example |
|---|---|---|---|---|---|
events Which Postmark webhooks to turn on. Postmark accepts exactly these six; every one you leave out is explicitly disabled on the webhook. | array | No | ["Bounce"] | 1–6 characters; array of string | — |
message_stream The message stream to watch. Leave blank to use the stream on the connection, which defaults to Postmark's 'outbound' stream. Webhooks are per-stream: one on 'outbound' never sees a broadcast. | string | No | — | — | — |
Example configuration
Every value below is the contract’s own example or default — nothing invented.
{
"events": [
"Bounce"
]
}Output
One shape.
postmark event
The flattened Postmark delivery. payload's own keys depend on record_type, so the shape is open below the declared fields.
Extra keys beyond the ones listed can appear.
| Field | Type | Example |
|---|---|---|
record_type Which webhook fired: Bounce, Click, Delivery, Open, SpamComplaint or SubscriptionChange. Branch on this when the trigger subscribes to more than one. | string | Bounce |
message_id Postmark's id for the message the event is about — the same value the send that produced it returned, so this is what joins an event back to the send. | string | 883953f4-6105-42a2-a16a-77a8eac79483 |
message_stream The message stream the event came from, e.g. outbound or broadcast. | string | outbound |
recipient The address the event is about. Postmark calls it Recipient on a delivery, open, click or subscription change and Email on a bounce or spam complaint; both arrive here. | string | margareth@nasa.com |
tag The tag the message was sent with, or empty when it carried none. | string | welcome-email |
occurred_at When Postmark recorded the event (BouncedAt, DeliveredAt, ReceivedAt or ChangedAt, whichever this record type carries), as Postmark sent it. Empty when the record type carries none. | string | 2026-11-05T16:33:54.9070259Z |
record_id Postmark's id for the record itself — the bounce id on a Bounce or SpamComplaint, which is what postmark.get_bounce and postmark.activate_bounce take. Empty on record types that have no id. | string | 692560173 |
server_id The Postmark server the event came from, as a string so a large id cannot lose precision downstream. | string | 23 |
trace_id Postmark's X-PM-Webhook-Trace-Id header — stable across every retry of the same event, and the idempotency key this trigger dedupes on. | string | 7c1f0f2a-5f1e-4d2f-9d1a-2c5b8f0a41e9 |
metadata The custom metadata the message was sent with, or an empty object. | object | — |
payload The delivery exactly as Postmark sent it, for the per-record-type fields this contract does not lift out (Type, ClickLocation, Client, Geo, SuppressionReason…). | object | — |
{
"message_id": "883953f4-6105-42a2-a16a-77a8eac79483",
"message_stream": "outbound",
"metadata": {
"PropA": "some value"
},
"occurred_at": "2026-11-05T16:33:54.9070259Z",
"payload": {
"BouncedAt": "2026-11-05T16:33:54.9070259Z",
"CanActivate": true,
"Description": "The server was unable to deliver your message.",
"Email": "margareth@nasa.com",
"From": "alanturing@computers.com",
"ID": 692560173,
"Inactive": true,
"MessageID": "883953f4-6105-42a2-a16a-77a8eac79483",
"MessageStream": "outbound",
"Name": "Hard bounce",
"RecordType": "Bounce",
"Type": "HardBounce",
"TypeCode": 1
},
"recipient": "margareth@nasa.com",
"record_id": "692560173",
"record_type": "Bounce",
"server_id": "23",
"tag": "welcome-email",
"trace_id": "7c1f0f2a-5f1e-4d2f-9d1a-2c5b8f0a41e9"
}Notes
- Publishing creates the webhook on the stream; unpublishing, disabling or archiving deletes it. A workflow that is off is off at Postmark too.
- Postmark probes the callback URL once per enabled event inside the create call and refuses to save the webhook (422, ErrorCode 1364) unless every probe answers 200. Publishing therefore needs the ingress to answer while the webhook row is still being armed.
- Postmark does not sign its deliveries — its documentation says so in as many words. Each delivery is instead authenticated by a random token Mantle registers as an X-Mantle-Webhook-Token header and compares in constant time; anyone holding that token could have written the body.
- Webhooks are per message stream. Watching two streams means two workflows, or two triggers, not one webhook.
- A redelivery is recognised by Postmark's X-PM-Webhook-Trace-Id and joins the run it already started. The ingress remembers a key for 24 hours.
See Event run in a workflow.
In a technical demo we add the Postmark connection, drop the node on the canvas and let Workflow Health pre-flight it before the first real run.