Webhooks

Mars outbound integration for campaign output and nudges

Overview

Webhooks allow you to build or set up integrations which subscribe to certain events and predictions produced by Mars system. When one of those events is triggered, we'll send a HTTP POST payload to the webhook's configured URL. Webhooks can be used to create your own internal pipeline for processing predictions, managing push notification or updating your own internal coupon infra

Mars allows you to configure webhooks for following events

  • Campaign Outputs

  • Nudges

Campaign outputs

If you are subscribed to webhooks for campaign outputs, you would recieve HTTP payload whenever the mars system makes predictions for users in your campaign

You can subscribe to any of the following outputs

  • Product Discount Recommendation

Nudges

If you are subscribed to webhooks for nudges, you would receive HTTP payload whenever the mars system schedules a nudges for a user in your campaigns

Setting up a Webhook

To set up a webhook, you can go to Mars Dashboard and click Integrations > Outbound > Webhooks > Add Webhooks.

Following information is required for setting up a new webhook

  • Name

  • Payload Url

  • Content Type

  • Secret

Name

A descriptive name for your webhook. This is purely used for you to manage and identify the enabled webhooks

Payload URL

The payload URL is the URL of the server that will receive the webhook POST requests.

Example:

https://<your-domain-name>/payload

SSL Verification: Mars Webhooks only accepts HTTPS enabled endpoints for payload URL

Content Type

All Mars webhooks uses the default application/json content type. JSON payload will be part of the POST request

Secret

Setting a webhook secret allows you to ensure that POST requests sent to the payload URL are from Marax servers. When you set a secret, you'll receive the X-Mars-Signature header in the webhook POST request.

Setting your token

You'll need to set up your secret token in two places: Mars and your server.

To set your token on Mars:

  • On the dashboard, Fill out the Secret textbox. Use a random string with high entropy

JavaScript
ruby
JavaScript
const { Entropy } = require('entropy-string');
const entropy = new Entropy();
const token = entropy.string();
ruby
ruby -rsecurerandom -e 'puts SecureRandom.hex(20)'

Next, set up an environment variable on your server that stores this token. Typically, this is as simple as running:

export SECRET_TOKEN=your_token

Validating payloads from Marax

When your secret token is set, Marax uses it to create a hash signature with each payload.

This hash signature is passed along with each request in the headers as X-Mars-Signature.

The goal is to compute a hash using your SECRET_TOKEN, and ensure that the hash from Marax matches. Marax uses an HMAC hexdigest to compute the hash, so you could change your server to look a little like this:

JavaScript
JavaScript
const verifySignature = (reqBodyDigest, marsHeader) => {
return crypto.timingSafeEqual(Buffer.from(marsHeader), Buffer.from(`sha1=${reqBodyDigest}`));
}
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.post('/hook', (req, res) => {
const jsonString = JSON.stringify(req.body);
const reqBodyDigest = crypto.createHmac('sha1', token)
.update(jsonString)
.digest('hex');
const marsHeader = req.headers['x-mars-signature'];
const verify = verifySignature(reqDigest, marsHeader)
}

Obviously, your language and server implementations may differ than this code. There are a couple of very important things to point out, however:

  • No matter which implementation you use, the hash signature starts with sha1=, using the key of your secret token and your payload body.

  • Using a plain == operator is not advised. A method like timingSafeEqual performs a "constant time" string comparison, which renders it safe from certain timing attacks against regular equality operators.

Schemas

Detailed schema for campaign outputs can be found here

Examples

Following is a sample request body for Product Discount Recommendation

{
"predictionId": "a8a3b30a-f5f3-408e-b5b7-62fde7bb32a9",
"type": "product_discount_recommendation",
"campaignId": "36011017-0e00-4e29-a054-7a1fbb8b60a2",
"clientId": "b4aeba4e-a4c0-4896-866a-56f8bcb372fc",
"maraxId": "280b850d-c28d-4812-8ad9-a164acd96a62",
"userIdentities": {
"userId": "3594918"
},
"predictions": [
{
"product_id": "36011017-0e00-4e29-a054-7a1fbb8b60a2",
"name": "TEGO Tank Top for Women - Blue - L",
"sku": "T-WTTBL",
"type": "percentage",
"discount": 30,
"min": 10,
"max": 50,
"step": 1,
"explanations": [
{
"step": "product-recommendation",
"description": "Predicts preference of the user to all the
products in the inventory based on the user behavior and
aggregate behavior of other users. rankingScore is higher
for products which the user prefers.",
"score": 0.5
},
{
"step": "user-engagement-scoring",
"description": "Assigns an engagement score to the user based
on user behavior data. userEngagementScore is higher for
the users who have higher interaction with the platform.",
"score": 0.5
},
{
"step": "discount-allocation",
"description": "The allocated discount is based on
userEngagementScore, rankingScore and expensiveness of a discount.
discountExpensiveness is higher for higher allocated discount.",
"score": 0.1
}
]
}
]
}

Following is a sample request body for Nudge

{
"nudgeUserId": "a8a3b30a-f5f3-408e-b5b7-62fde7bb32a9",
"type": "nudge",
"campaignId": "36011017-0e00-4e29-a054-7a1fbb8b60a2",
"clientId": "b4aeba4e-a4c0-4896-866a-56f8bcb372fc",
"maraxId": "280b850d-c28d-4812-8ad9-a164acd96a62",
"userIdentities": {
"clevertapId": "3594918",
"userId": "a8a3b30a-f5f3-408e-b5b7-62fde7bb32a9",
"email": "testuser@marax.in"
},
"status": "pristine",
"trigger": "time",
"channel": "push",
"nudgeQueueDateTime": "2020-01-24T11:59:59.546+00:00",
"nudgeExpiryDateTime": "2020-01-24T13:59:59.546+00:00",
"content": {
"title": "Hey John, how are you?",
"body": "Buy Nike Tshirt at 46% off",
"image": "https://c.static-nike.com/a/images/t_PDP_1728_v1/f_auto,b_rgb:f5f5f5/yysp5aoja5owrccp87id/dri-fit-miler-running-top-nN6G1K.jpg",
"clickAction": "MainActivity",
"textColour": "#FFFFFF"
},
"event": {
"name": "product_viewed"
}
}