Skip to main content
Courier uses webhooks to notify your application when events occur in your account, such as message status changes, template publications, and audience updates.

Adding a New Webhook Destination

  1. Visit https://app.courier.com/settings/general
  2. Click the ”+ Outbound Webhook” button
  3. Enter the new webhook destination information (this should accept a POST request)
Webhooks are scoped to the environment where they are created. A webhook created in the test environment will only fire for test events; it will not receive production events, and vice versa. If you need webhooks in both environments, create separate webhook destinations in each.

Handling Requests from Courier

Read the Event Data

Courier sends the event data in the request body. Each event is structured as an object with a type property and related resource data nested under the data property.

Handle the Event

Courier currently supports the following event types:
  • message:updated
  • notification:submitted
  • notification:submission_canceled
  • notification:published
  • audiences:updated
  • audiences:user:matched
  • audiences:user:unmatched
  • audiences:calculated
Handle events based on the type property in the payload. Additional event types may be added in the future, so your handler should gracefully ignore unknown types.

Return a 200 Response

Send a successful 200 response to Courier as quickly as possible. Write any long-running processes as code that can run asynchronously outside the webhook endpoint.

Verifying Signatures

Verify the events that Courier sends to your webhook endpoints. Courier can optionally sign the webhook events it sends to your endpoints by including a signature in each event’s courier-signature header. This allows you to verify that the events were sent by Courier, not by a third party.
Courier generates signatures using a hash-based message authentication code (HMAC) with SHA-256.

Step 1: Extract the Timestamp and Signature from the Header

Split the header using the , character as the separator to get a list of elements. Then split each element using the = character as the separator to get a prefix and value pair. The value for the prefix t corresponds to the timestamp, and signature corresponds to the signature. Before you can verify signatures, you need to retrieve your endpoint’s secret from your Webhooks settings by clicking on a webhook configuration.

Step 2: Prepare the signed_payload String

The signed_payload string is created by concatenating:
  • The timestamp (as a string)
  • The actual JSON payload (i.e., the request body)

Step 3: Determine the Expected Signature

Compute an HMAC with the SHA256 hash function. Use the Courier webhook secret as the key and the payload string as the message.

Step 4: Compare the Signatures

Compare the signature (or signatures) in the header to the expected signature. For an equality match, compute the difference between the current timestamp and the received timestamp, then decide if the difference is within your tolerance. To protect against timing attacks, use constant-time string comparison to compare the expected signature to each of the received signatures.

Event Data

message:updated

Each message status change triggers a message:updated webhook event. Delivery statuses like DELIVERED depend on your email provider asynchronously confirming delivery, while engagement statuses like OPENED and CLICKED are tracked by Courier directly and fire as soon as the recipient acts. This means you may receive engagement events before delivery confirmation, or without it arriving at all. For the full status lifecycle diagram and definitions, see Message Statuses. The data property in the webhook response payload for the message:updated event is identical to the information returned from the GET /message/:message_id endpoint. Any metadata associated with the message is included in the data property. This includes:
  • trace_id
  • tags
  • event
  • utm
Here’s a rundown of how the payloads would look for each event: Example Payload for an ENQUEUED Event
Example payload for SENT event
Example payload for DELIVERED event
Example payload for OPENED event
Example payload for CLICKED event
Example payload for UNROUTABLE event
Example payload for UNDELIVERABLE event

For the notification template submission workflow, Courier emits notification:submitted, notification:submission_canceled, and notification:published events. These are useful for integrating with translation management systems (TMS) or custom approval workflows.
  • notification:submitted — Fired when a template is submitted for review. Indicates the template entered an approval workflow and has not yet been published.
  • notification:published — Fired when a template is published directly (no approval workflow) or when a submission is approved and auto-published. This is the event to listen for if you want to sync template content to an external system.
  • notification:submission_canceled — Fired when a pending submission is canceled before it is published.

notification:submitted

Example:

notification:submission_canceled

Example:

notification:published

Example

audiences:updated

This event is fired when your audience is created or updated. Example:

audiences:user:matched

This event is fired when a user is matched to an audience. This usually happens when a user is created or updated. If user’s profile matches any of the audience’s filters, the user is matched to the audience. Example:

audiences:user:unmatched

This event is fired when a user is unmatched to an audience. This usually happens when a user is removed or updated in such a way that it no longer matches any of the audience’s filters. Example:

audiences:calculated

This event is fired when Courier is done calculating audiences. This is a background process that runs every time you create or update an audience. It can take variable time depending on total number of users you have created in your Courier workspace. Example: