Courier
Courier routes notifications across email, SMS, push, chat and in-app. Datafly Signal calls the Courier Send API (POST /send) so an event such as a sign-up or an order sends a Courier template to the visitor, with the event properties as template data.
Why route Courier through Datafly Signal
- Events come from your server, not the browser. They reach Courier even when a tracker blocker or a failed page unload would have dropped a client-side call.
- Delivery is queued and retried. Signal buffers to Kafka and retries on 429 or a transient failure rather than dropping the event; a permanent rejection goes to the dead-letter queue with the vendor’s reason.
- One consent decision governs every destination. Courier is gated by the same consent state as the rest of your stack, so a withdrawal applies everywhere at once.
Get your Courier credentials
Create an API key
In Courier open Settings > API Keys (app.courier.com/settings/api-keys) and copy a production key.
Create the templates
Create a template for each event you send and give it the alias shown under Presets (signed_up, order_completed, order_refunded …). Or set Default Template ID to send one template for every event.
Configuration
| Field | Required | Description |
|---|---|---|
api_key | Yes | Your Courier server-side API key, sent as a Bearer token. Find it in Courier under Settings > API Keys (app.courier.com/settings/api-keys). Never expose this in client-side code. |
template_id | No | Optional. A Courier template (notification) id or alias that every event sends. Leave blank to send each event to the template whose alias is the event name (signed_up, order_completed, order_refunded …): create those aliases in Courier. |
Management UI setup
- Go to Integrations in the sidebar and open the Integration Library tab.
- Find Courier under Marketing Automation and click Install.
- Choose a preset, enter the fields above and click Install Integration.
Management API setup
curl -X POST http://localhost:8084/v1/admin/integration-catalog/courier/install \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Courier",
"variant": "default",
"config": {
"api_key": "your_api_key"
},
"delivery_mode": "server_side"
}'What Signal sends
An example request, rendered from the default preset for purchase:
POST https://api.courier.com/send
Idempotency-Key: 3f1c2a90-7d4e-4b8a-9c61-2f0e5d7a1b22
{
"message": {
"data": {
"amount": 279.98,
"coupon": "AUTUMN10",
"currency": "GBP",
"items": [
{
"item_brand": "NorthEdge",
"item_category": "Jackets",
"item_id": "SKU-1",
"item_name": "Parka Jacket",
"item_variant": "Blue",
"price": 129.99,
"quantity": 2
},
{
"item_category": "Hats",
"item_id": "SKU-2",
"item_name": "Wool Hat",
"price": 20,
"quantity": 1
}
],
"order_id": "ORD-1001",
"shipping": 4.99,
"tax": 46.66
},
"template": "order_completed",
"to": {
"data": {
"first_name": "Neill",
"last_name": "Mcfixture"
},
"email": "neill@example.com",
"locale": "en-GB",
"phone_number": "+447700900123",
"user_id": "crm-user-7"
}
}
}| Field | Source |
|---|---|
message.template | The Default Template ID when set, else the template alias named after the event. |
message.to.user_id | The signed-in user ID (not the anonymous ID). |
message.to.email, message.to.phone_number | From identify() traits; email trimmed and lower-cased, phone in E.164. |
message.to.locale, message.to.data | The visitor’s locale; first and last name. |
message.data | The event’s properties (order id, amount, currency upper-cased, items, carrier and tracking number …). |
Idempotency-Key header | The Signal event ID. Courier returns the stored response for a repeated key, so a retried delivery never sends the message twice. |
Courier delivers to the email address and phone number, so they are sent in plain text; it has no hashed identifier. An event with no user ID, email or phone is dropped.
Presets
| Preset | Signal event → vendor event |
|---|---|
| Default | sign_up → signed_up, purchase → order_completed, refund → order_refunded, generate_lead → lead_received |
| Retail | sign_up → signed_up, purchase → order_completed, order_shipped, refund → order_refunded |
| B2B / SaaS | sign_up → signed_up, trial_started, trial_expired, subscription_started, subscription_cancelled, invitation_accepted |
| Travel | sign_up → signed_up, purchase → booking_confirmed, booking_modified, booking_cancelled |
Events not listed are not sent. Each preset is a starting point: add, rename or remove mappings on the installed integration.
Notes and limits
- Page views are not sent: every mapped event sends a notification.
Consent
Marketing-automation integrations have no consent category by default. Assign the marketing category when you install Courier, so an event is delivered only when the visitor has granted it. Cookie-banner consent is not email or SMS opt-in: keep messaging opt-in in Courier.
Verify it’s working
- Open the integration in the Signal Management UI and watch Live Events while you trigger a mapped event.
- Confirm a 2xx response from Courier.
- Find the contact in Courier and check the event or record arrived.
Troubleshooting
| Symptom | Resolution |
|---|---|
400 “template not found” or 404 | Create a template with the alias the event uses, or set Default Template ID. |
401 | The API key is wrong. |
402 | The Courier plan’s quota is used up. |