What is the benefit of a webhook?
Listrak's webhooks allow you to send data to a third party site or application in order to seamlessly pass information from your Listrak journeys to other sites. This ability allows you to ensure the same information is present in both systems and take action on this information in your third party systems.
Webhooks can pass custom information or be used to pass Listrak-specific data to third parties. Data from the cart abandonment and post purchase journeys can be passed to other systems to trigger additional messaging in channels, such as SMS or app push, outside of Listrak. In addition to the specifics about what was purchased or abandoned, Webhooks can also pass coupon information to keep information consistent across channels.
What are some common use cases for webhooks?
Webhooks can be used to pass many different types of information to your third party endpoint location. Use a webhook to easily send data to this location and keep records in sync to make record keeping even easier. This also allows you to utilize data from Listrak in custom reporting in your third party system or power additional marketing solutions, such as direct mail.
You can also use webhooks to send data, such as an order thank you message, to apps, such as Facebook messenger. You can also send data to these apps to trigger notifications or rewards after taking a specific action on your site.
Webhooks can also be used to send payload data captured in journeys that use the advanced cart abandonment, advanced product browse, and advanced page browse entry events, as well as data captured about purchases. Payload data includes all data captured for the event that triggers a contact into the journey. For example, the payload for an advanced cart abandonment journey could include the product, quantity, product category etc. that can then can be sent to third parties, such as a SMS or app push solution. This allows you to target users across multiple platforms.
How does a Listrak webhook work?
The webhook uses a POST function to push information from Listrak Journey Hub to an endpoint in your third party system. You configure the webhook inside the Listrak platform and then direct the webhook to the location of this endpoint with the information.
What happens inside Journey Hub?
When configuring a webhook action step in Journey Hub, you will configure a JSON schema to specify the specific fields that will be sent back to the third-party location specified when you integrate the webhook, send a coupon, or send the payload data about a cart or purchase. You can use the preview JSON feature to ensure the desired data is being passed in your webhook.
A contact's email address and phone number are automatically appended to the JSON schema or payload configured. Only the data points associated with the contact will be appended.
You can also determine what occurs if your webhook fails and is not able to reach the third-party location. By default, a contact will be removed from journeys so the data in Listrak and your third-party stays in sync. You can change this setting to move to the next step in the journey. Errors in the webhook will also be logged in Listrak. At this time it is not possible to re-initiate the webhook action for contacts where it failed.
Configuring a Webhook Integration
Before adding a webhook action step in Journey Hub, you will first create the webhook in Listrak's Integration Manager.
The Integration Manager is found under Integrations. This can be accessed anywhere in the platform.
From the integrations list, select Integrate in the Webhook section.
Click Setup Integration.
Provide a name for your webhook.
Provide the URL where the information captured in Journey Hub should be sent
⚠️ The URL must contain the https protocol
Click Save.
Save the HMAC Secret for future reference.
Using a Webhook Action Step in Journey Hub
The webhook action step is available in all journey types except Shopify Transactional journeys. The option to send data via JSON is available in all journeys. The option to send payload data is available in the journeys in the Purchase, Abandonment, and Alerts categories.
Place the action step in the desired location.
In the properties panel, name the step, if desired.
Select the configured webhook.
To use the webhook with JSON:
⚠️ The JSON must use standard JSON formatting.
Select the JSON radio button
Click Edit JSON
In the popup, define your JSON schema to specify what information should be passed via the webhook
💡 Learn more about testing your JSON schema in the testing section below
Click Apply
To use the webhook with the Journey Payload:
Select the Payload Radio Button
If desired, check the Include Coupon Code checkbox
⚠️ A coupon action must be configured in the path prior to the webhook step. If multiple coupons are included in the path all coupon codes will be sent via the webhook
Use View JSON button to preview the data that is included in the JSON about a contact's purchase or cart. All possible fields are included in the JSON, but a specific contact's cart or purchase information will fill in the fields that contain values.
In the properties panel, select what action should occur if a webhook fails and is not able to post the information.
You can now continue configuring your journey properties and the webhook action step will begin sending the information after the journey is activated.
Testing a Webhook
A webhook testing service can often help ensure the data is being passed correctly before connecting to your third-party site and activating a journey. These services allow you to create a webhook that points to a testing location and then simulate the JSON schema that would appear in the action step. You can use this simulation to confirm that the data is being formatted and sent correctly.
Check out the following testing services to get started:
Authenticating a Webhook
Authenticating a webhook provides a way to validate the requests that are being received by your endpoint. This can prevent malicious requests from a third party from being received by your webhook.
The following process can help authenticate your webhook request.
Gather your HMAC and Secret (saved during the setup of your integration).
Read the payload from the request (the body).
Read the request headers to gather:
LTK-Timestamp
LTK-HmacSignature
Add the LTK-Timestamp to the end of the payload
Run the combined timestamp and payload through a SHA256 HMAC algorithm with your secret as the HMAC secret key
Verify your result matches LTK-HmacSignature
When the results match the request to your webhook originated from Listrak.
The second component is to verify the timestamp to prevent potential replay attacks from malicious third party:
Verify LTK-Timestamp is within your allowed tolerance (for example: 15 minutes)
If both of these components are match your expected values your webhook is authenticated.
Authenticating in Python
import base64
import hashlib
import hmac
import datetime
from flask import Flask
from flask import request, abort
app = Flask(__name__)
SECRET = 'YOUR-SECRET-HERE'
BYTE_SECRET = SECRET.encode('UTF-8')
@app.route('/', methods=['POST'])
def webhook_endpoint():
request_data = request.get_data().decode('utf-8')
request_timestamp = str(request.headers['LTK-Timestamp'])
request_hmac = request.headers['LTK-HmacSignature'].encode('utf-8')
# Check that the HMAC is signed correctly to verify that request came from someone who knows the HMAC secret.
my_hmac = compute_hmac(request_data, request_timestamp)
hmac_verified = hmac.compare_digest(my_hmac, request_hmac)
# Check that timestamp is recent to avoid replay attacks.
timestamp_verified = verify_timestamp(request_timestamp)
# If either check fails then exit early.
if not hmac_verified or not timestamp_verified:
abort(401)
# Now you can be sure this request was sent by Listrak in the last 15 minutes!
# ... your code goes here ...
return "Webhook verified", 200
def compute_hmac(data, timestamp):
combined_data = (data + timestamp).encode('utf-8')
digest = hmac.new(BYTE_SECRET, combined_data, hashlib.sha256).digest()
return base64.b64encode(digest)
def verify_timestamp(request_timestamp):
request_datetime = datetime.datetime.fromtimestamp(int(request_timestamp))
fifteen_minutes_ago_datetime = datetime.datetime.now() - datetime.timedelta(minutes=15)
if request_datetime < fifteen_minutes_ago_datetime:
return False
return True
if __name__ == '__main__':
app.run()
Authenticating in C#
using System;
using System.Text;
using System.Security.Cryptography;
// Endpoint read the following headers to compare the computed signature
var hmacSecret = "YOUR-SECRET-HERE";
var timestamp = Request.Headers["LTK-Timestamp"];
var signature = Request.Headers["LTK-HmacSignature"];
var payloadJson = Request.Body;
// Compute the Hmac secret (using GetHmacSignature below) to compare against the extracted signature.
// Ensure the timestamp is within the allowed time.
// Request is verified!
// .. your code goes here ..
private static string GetHmacSignature(string hmacSecret, string payloadJson, string timestamp)
{
var hmacBytes = Encoding.UTF8.GetBytes(hmacSecret);
using HMACSHA256 hmac = new HMACSHA256(hmacBytes);
var combinedBytes = Encoding.UTF8.GetBytes(payloadJson + timestamp);
return Convert.ToBase64String(hmac.ComputeHash(combinedBytes.ToArray()));
}
Authenticating in JavaScript
// Simple Node Express webhook example
// Requires installing express: 'npm install --save express body-parser'
const express = require('express');
const bodyParser = require('body-parser')
const crypto = require('crypto');
const app = express();
app.use('/webhooks/path', bodyParser.text({ type: '*/*' }), (req, res, next) => {
const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET
const timeStamp = req.header('LTK-Timestamp')
const webhook_payload = req.body
const hmac = crypto.createHmac('sha256', WEBHOOK_SECRET)
const webhookDigest = hmac.update(webhook_payload + timeStamp).digest('hex')
const computedSignature = `${webhookDigest}`
const requestSignature = req.header('LTK-HmacSignature')
// if requestSignature and computedSignature do not match, you have an invalid request.
// if timeStamp is not within the allowed time, you have an invalid request.
// Request is verified!
// .. your code goes here .
});