Message Webhook Format
Please enable webhooks from your Interakt Account’s Developer Settings: https://app.interakt.ai/settings/developer-setting.
- – You can use Webhooks only if you are subscribed to Interakt’s Growth / Advanced Plans.
- – While configuring the webhook, you will be required to provide us a Webhook URL & Secret Key.
- – You would also have to specify the type of webhooks you require for your account (read below to understand the different types)
Note that you can consume message webhooks for:
1. Delivery statuses (Sent / Delivered / Read / Failed) of Templates (HSMs) sent via the above Template Sending APIs
2. Delivery statuses (Sent / Delivered / Read / Failed) of Templates (HSMs) sent by setting Campaigns on Interakt
3. Incoming customer messages on your WhatsApp API number, connected with your Interakt account – Note that this webhook will only be available on higher plans.
When receiving the webhooks for Sent/Delivered/Read/Failed
1. Check for the type of webhook
• For delivery status webhooks of templates sent via APIs, the types will be as follows:
- “message_api_sent”
- “message_api_delivered”
- “message_api_read”
- “message_api_failed”
• For delivery status webhooks of templates sent via Interakt Campaigns, the types will be as follows:
- “message_campaign_sent”
- “message_campaign_delivered”
- “message_campaign_read”
- “message_campaign_failed”
• For incoming customer message webhooks, the type will be as follows:
- “message_received”
2. Read the data.customer object to see customer’s phone number & the values of all customer attributes stored in Interakt for that particular customer
3. Read the data.message object to identify which message is being referred to
4. Process the payload and return a success 200 within 3 seconds
– Any non-200 status will be considered as failure
– No response within the expected timeout will be considered as a failure
– 5 failures within a span of 10 minutes will disable the webhook and send an alert email. Post which the webhook will be re-enabled manually.
5. There won’t be any retries for failed webhooks
6. Events which triggered when the webhook was disabled will not be triggered later
Webhook Body – message_api_sent:
(note – data sent in the “traits” object depends on the customer traits present in your Interakt account. The traits given in the example below corresponds to a test account)
{
“version”: “1.0”,
“timestamp”: “2022-06-03T05:43:33.237499”,
“type”: “message_api_sent”,
“data”: {
“customer”: {
“id”: “52918eb3-bd00-4331-a51d-c4dcffee48d6”,
“channel_phone_number”: “917003705584”,
“traits”: {
“name”: “SKGG”,
“amount”: 7000,
“total_orders_count”: 0,
“last_order_id”: null,
“last_order_name”: null,
“total_spent”: “0.00”,
“whatsapp_opted_in”: false,
“created_at”: “2021-06-23T06:46:11”,
“User Id”: “111”,
“email”: “[email protected]”,
}
},
“message”: {
“id”: “dfc668a2-c06c-4e9a-a4fd-7b65bc1fdc84”,
“chat_message_type”: “PublicApiMessage”,
“channel_failure_reason”: null,
“message_status”: “Sent”,
“received_at_utc”: “2022-06-03T05:43:33.133000”,
“delivered_at_utc”: null,
“seen_at_utc”: null,
“campaign_id”: null,
“is_template_message”: true,
“raw_template”: “{\”id\”: \”281a5a78-f2b2-46c9-b9bb-d620d3b2894c\”, \”created_at_utc\”: \”2022-03-30T07:04:04.078\”, \”modified_at_utc\”: \”2022-03-31T05:41:09.61\”, \”created_by_user_id\”: \”37088e03-3633-4aa4-b4d8-99edbc56d4fc\”, \”is_deleted\”: false, \”name\”: \”test_template_lp\”, \”language\”: \”en\”, \”category\”: \”ALERT_UPDATE\”, \”header_format\”: null, \”header\”: null, \”header_handle\”: null, \”header_handle_file_url\”: null, \”header_handle_file_name\”: null, \”header_text\”: null, \”body\”: \”Hi {{1}} \\nWelcome to interakt, my name is {{2}} . I hope your 14 day free trial was helpful. For any queries please reach to us.\”, \”body_text\”: \”[\\\”Clients\\\”, \\\”Sender\\\”]\”, \”footer\”: \”Team interakt\”, \”buttons\”: \”[{\\\”type\\\”: \\\”QUICK_REPLY\\\”, \\\”text\\\”: \\\”Thank you\\\”}, {\\\”type\\\”: \\\”QUICK_REPLY\\\”, \\\”text\\\”: \\\”What is qralink?\\\”}, {\\\”type\\\”: \\\”QUICK_REPLY\\\”, \\\”text\\\”: \\\”Speak to an agent\\\”}]\”, \”button_text\”: null, \”display_name\”: \”Test template\”, \”organization_id\”: \”ba4308f1-a506-44d2-a8c3-17380216cf91\”, \”approval_status\”: \”APPROVED\”, \”wa_template_id\”: \”3224400424546364\”, \”is_archived\”: false}”,
“channel_error_code”: null,
“message_content_type”: “Template”,
“media_url”: null,
“message”: “[{\”type\”: \”body\”, \”parameters\”: [{\”type\”: \”text\”, \”text\”: \”Saandhy\”}, {\”type\”: \”text\”, \”text\”: \”Varun\”}]}]”,
“meta_data”: {
“source”: “PublicInterakt”,
“source_data”: {
“callback_data”: “some text here”
}
}
}
}
}
Webhook Body – message_api_delivered:
(note – data sent in the “traits” object depends on the customer traits present in your Interakt account. The traits given in the example below corresponds to a test account)
{
“version”: “1.0”,
“timestamp”: “2022-06-03T05:43:33.930227”,
“type”: “message_api_delivered”,
“data”: {
“customer”: {
“id”: “52918eb3-bd00-4331-a51d-c4dcffee48d6”,
“channel_phone_number”: “917003705584”,
“traits”: {
“name”: “SKGG”,
“amount”: 7000,
“total_orders_count”: 0,
“last_order_id”: null,
“last_order_name”: null,
“total_spent”: “0.00”,
“whatsapp_opted_in”: false,
“created_at”: “2021-06-23T06:46:11”,
“User Id”: “111”,
“email”: “[email protected]”,
}
},
“message”: {
“id”: “dfc668a2-c06c-4e9a-a4fd-7b65bc1fdc84”,
“chat_message_type”: “PublicApiMessage”,
“channel_failure_reason”: null,
“message_status”: “Delivered”,
“received_at_utc”: “2022-06-03T05:43:33.133000”,
“delivered_at_utc”: “2022-06-03T05:43:33.848000”,
“seen_at_utc”: null,
“campaign_id”: null,
“is_template_message”: true,
“raw_template”: “{\”id\”: \”281a5a78-f2b2-46c9-b9bb-d620d3b2894c\”, \”created_at_utc\”: \”2022-03-30T07:04:04.078\”, \”modified_at_utc\”: \”2022-03-31T05:41:09.61\”, \”created_by_user_id\”: \”37088e03-3633-4aa4-b4d8-99edbc56d4fc\”, \”is_deleted\”: false, \”name\”: \”test_template_lp\”, \”language\”: \”en\”, \”category\”: \”ALERT_UPDATE\”, \”header_format\”: null, \”header\”: null, \”header_handle\”: null, \”header_handle_file_url\”: null, \”header_handle_file_name\”: null, \”header_text\”: null, \”body\”: \”Hi {{1}} \\nWelcome to interakt, my name is {{2}} . I hope your 14 day free trial was helpful. For any queries please reach to us.\”, \”body_text\”: \”[\\\”Clients\\\”, \\\”Sender\\\”]\”, \”footer\”: \”Team interakt\”, \”buttons\”: \”[{\\\”type\\\”: \\\”QUICK_REPLY\\\”, \\\”text\\\”: \\\”Thank you\\\”}, {\\\”type\\\”: \\\”QUICK_REPLY\\\”, \\\”text\\\”: \\\”What is qralink?\\\”}, {\\\”type\\\”: \\\”QUICK_REPLY\\\”, \\\”text\\\”: \\\”Speak to an agent\\\”}]\”, \”button_text\”: null, \”display_name\”: \”Test template\”, \”organization_id\”: \”ba4308f1-a506-44d2-a8c3-17380216cf91\”, \”approval_status\”: \”APPROVED\”, \”wa_template_id\”: \”3224400424546364\”, \”is_archived\”: false}”,
“channel_error_code”: null,
“message_content_type”: “Template”,
“media_url”: null,
“message”: “[{\”type\”: \”body\”, \”parameters\”: [{\”type\”: \”text\”, \”text\”: \”Saandhy\”}, {\”type\”: \”text\”, \”text\”: \”Varun\”}]}]”,
“meta_data”: {
“source”: “PublicInterakt”,
“source_data”: {
“callback_data”: “some text here”
}
}
}
}
}
Webhook Body – message_api_read:
(note – data sent in the “traits” object depends on the customer traits present in your Interakt account. The traits given in the example below corresponds to a test account)
{
“version”: “1.0”,
“timestamp”: “2022-06-03T05:43:33.930227”,
“type”: “message_api_read”,
“data”: {
“customer”: {
“id”: “52918eb3-bd00-4331-a51d-c4dcffee48d6”,
“channel_phone_number”: “917003705584”,
“traits”: {
“name”: “SKGG”,
“amount”: 7000,
“total_orders_count”: 0,
“last_order_id”: null,
“last_order_name”: null,
“total_spent”: “0.00”,
“whatsapp_opted_in”: false,
“created_at”: “2021-06-23T06:46:11”,
“User Id”: “111”,
“email”: “[email protected]”,
}
},
“message”: {
“id”: “dfc668a2-c06c-4e9a-a4fd-7b65bc1fdc84”,
“chat_message_type”: “PublicApiMessage”,
“channel_failure_reason”: null,
“message_status”: “Read”,
“received_at_utc”: “2022-06-03T05:43:33.133000”,
“delivered_at_utc”: “2022-06-03T05:43:33.848000”,
“seen_at_utc”: “2022-06-03T05:43:34.257000”,
“campaign_id”: null,
“is_template_message”: true,
“raw_template”: “{\”id\”: \”281a5a78-f2b2-46c9-b9bb-d620d3b2894c\”, \”created_at_utc\”: \”2022-03-30T07:04:04.078\”, \”modified_at_utc\”: \”2022-03-31T05:41:09.61\”, \”created_by_user_id\”: \”37088e03-3633-4aa4-b4d8-99edbc56d4fc\”, \”is_deleted\”: false, \”name\”: \”test_template_lp\”, \”language\”: \”en\”, \”category\”: \”ALERT_UPDATE\”, \”header_format\”: null, \”header\”: null, \”header_handle\”: null, \”header_handle_file_url\”: null, \”header_handle_file_name\”: null, \”header_text\”: null, \”body\”: \”Hi {{1}} \\nWelcome to interakt, my name is {{2}} . I hope your 14 day free trial was helpful. For any queries please reach to us.\”, \”body_text\”: \”[\\\”Clients\\\”, \\\”Sender\\\”]\”, \”footer\”: \”Team interakt\”, \”buttons\”: \”[{\\\”type\\\”: \\\”QUICK_REPLY\\\”, \\\”text\\\”: \\\”Thank you\\\”}, {\\\”type\\\”: \\\”QUICK_REPLY\\\”, \\\”text\\\”: \\\”What is qralink?\\\”}, {\\\”type\\\”: \\\”QUICK_REPLY\\\”, \\\”text\\\”: \\\”Speak to an agent\\\”}]\”, \”button_text\”: null, \”display_name\”: \”Test template\”, \”organization_id\”: \”ba4308f1-a506-44d2-a8c3-17380216cf91\”, \”approval_status\”: \”APPROVED\”, \”wa_template_id\”: \”3224400424546364\”, \”is_archived\”: false}”,
“channel_error_code”: null,
“message_content_type”: “Template”,
“media_url”: null,
“message”: “[{\”type\”: \”body\”, \”parameters\”: [{\”type\”: \”text\”, \”text\”: \”Saandhy\”}, {\”type\”: \”text\”, \”text\”: \”Varun\”}]}]”,
“meta_data”: {
“source”: “PublicInterakt”,
“source_data”: {
“callback_data”: “some text here”
}
}
}
}
Webhook Body – message_api_failed:
(note – data sent in the “traits” object depends on the customer traits present in your Interakt account. The traits given in the example below corresponds to a test account)
{
“version”: “1.0”,
“timestamp”: “2022-06-03T05:56:10.699936”,
“type”: “message_api_failed”,
“data”: {
“customer”: {
“id”: “82a5b5bc-5509-4225-a9e9-bbe4c150516b”,
“channel_phone_number”: “919831”,
“traits”: {
“name”: “”,
“whatsapp_opted_in”: true
}
},
“message”: {
“id”: “80b4b1f1-dc39-46dc-a133-bf09a12c3d4e”,
“chat_message_type”: “PublicApiMessage”,
“channel_failure_reason”: “Recipient is not a valid WhatsApp user”,
“message_status”: “Failed”,
“received_at_utc”: “2022-06-03T05:56:10.502000”,
“delivered_at_utc”: null,
“seen_at_utc”: null,
“campaign_id”: null,
“is_template_message”: true,
“raw_template”: “{\”id\”: \”281a5a78-f2b2-46c9-b9bb-d620d3b2894c\”, \”created_at_utc\”: \”2022-03-30T07:04:04.078\”, \”modified_at_utc\”: \”2022-03-31T05:41:09.61\”, \”created_by_user_id\”: \”37088e03-3633-4aa4-b4d8-99edbc56d4fc\”, \”is_deleted\”: false, \”name\”: \”test_template_lp\”, \”language\”: \”en\”, \”category\”: \”ALERT_UPDATE\”, \”header_format\”: null, \”header\”: null, \”header_handle\”: null, \”header_handle_file_url\”: null, \”header_handle_file_name\”: null, \”header_text\”: null, \”body\”: \”Hi {{1}} \\nWelcome to interakt, my name is {{2}} . I hope your 14 day free trial was helpful. For any queries please reach to us.\”, \”body_text\”: \”[\\\”Clients\\\”, \\\”Sender\\\”]\”, \”footer\”: \”Team interakt\”, \”buttons\”: \”[{\\\”type\\\”: \\\”QUICK_REPLY\\\”, \\\”text\\\”: \\\”Thank you\\\”}, {\\\”type\\\”: \\\”QUICK_REPLY\\\”, \\\”text\\\”: \\\”What is qralink?\\\”}, {\\\”type\\\”: \\\”QUICK_REPLY\\\”, \\\”text\\\”: \\\”Speak to an agent\\\”}]\”, \”button_text\”: null, \”display_name\”: \”Test template\”, \”organization_id\”: \”ba4308f1-a506-44d2-a8c3-17380216cf91\”, \”approval_status\”: \”APPROVED\”, \”wa_template_id\”: \”3224400424546364\”, \”is_archived\”: false}”,
“channel_error_code”: “1013”,
“message_content_type”: “Template”,
“media_url”: null,
“message”: “[{\”type\”: \”body\”, \”parameters\”: [{\”type\”: \”text\”, \”text\”: \”Saandhy\”}, {\”type\”: \”text\”, \”text\”: \”Varun\”}]}]”,
“meta_data”: {
“source”: “PublicInterakt”,
“source_data”: {
“callback_data”: “some text here”
}
}
}
}
}
Webhook Body – message_received:
(note – data sent in the “traits” object depends on the customer traits present in your Interakt account. The traits given in the example below corresponds to a test account)
{
“version”: “1.0”,
“timestamp”: “2022-06-03T05:57:57.496889”,
“type”: “message_received”,
“data”: {
“customer”: {
“id”: “52918eb3-bd00-4331-a51d-c4dcffee48d6”,
“channel_phone_number”: “917003705584”,
“traits”: {
“name”: “SKGG”,
“amount”: 7000,
“total_orders_count”: 0,
“last_order_id”: null,
“last_order_name”: null,
“total_spent”: “0.00”,
“whatsapp_opted_in”: false,
“created_at”: “2021-06-23T06:46:11”,
“User Id”: “111”,
“email”: “[email protected]”,
}
},
“message”: {
“id”: “60076f05-da52-4dd1-b813-36223c1eded7”,
“chat_message_type”: “CustomerMessage”,
“channel_failure_reason”: null,
“message_status”: “Sent”,
“received_at_utc”: “2022-06-03T05:57:57.359000”,
“delivered_at_utc”: null,
“seen_at_utc”: null,
“campaign_id”: null,
“is_template_message”: false,
“raw_template”: null,
“channel_error_code”: null,
“message_content_type”: “Text”,
“media_url”: null,
“message”: “Thank you”,
“meta_data”: {}
}
}
}
Field & Description
type
Value will change depending on type of webhooks
Possible values:
1. For delivery status of templates (HSMs) sent via the above template sending APIs:
“message_api_sent”
“message_api_delivered”
“message_api_read”
“message_api_failed”
2. For delivery status of templates (HSMs) sent via campaigns on Interakt:
“message_campaign_sent”
“message_campaign_delivered”
“message_campaign_read”
“message_campaign_failed”
3. For incoming customer messages:
“message_received”
data.customer
The customer’s information.
channel_phone_number is the user’s complete phone number with ISD code.
traits are customer User Attributes that can be set via the User Track API. You can use this to log any Customer specific data.
data.message
This is the message payload.
id corresponds to the unique message identifier.
message_status indicates the current status of the message
received_at_utc = Timestamp for single tick (ie message getting sent)
delivered_at_utc = timestamp for double tick
seen_at_utc = timestamp for blue tick on WA
raw_template is a stringified JSON of template details.
channel_error_code and channel_failure_reason will contain details in case of Failed message
media_url will contain public link to media file
message will contain stringified raw message data
Meta_data will contain any callbackData that might have been sent in the Template Send API call
Webhook Requirements
Your webhook should meet the following minimum performance requirements
• Must be an HTTPS endpoint
• Respond to all webhook events with a 200 OK
• Respond to all webhook events in 3 seconds or less
Interakt Security Requirements
The HTTP request will contain an “Interakt-Signature” header which contains the Hex encoded SHA256 signature of the request payload computed using the HMAC algorithm and the secret_key shared in advance, and prefixed with sha256=.
Your callback endpoint should verify this signature to validate the integrity and origin of the payload.
For Eg: Sample Headers Received in Webhook:
Interakt-Signature:sha256=b84783d10ede5bd6ed771e8b16fbe5a7093340159d6e49ec4248350b6ec2c7b4
If your Payload is:
‘{“foo”:1,”bar”:2}’
And your Secret key is = examplekey
Sample Code given in Python and Node JS for your reference to verify webhooks
Sample Code For Verifying Webhooks
Python:
import hmac
from hashlib import sha256
from typing import Union
def generate_signature(secret_key: str, payload: Union[bytes, str]):
“””Generates SHA256 signature prepended with sha256=
Args:
secret_key [String] -> shared secret, known by your service
payload [String or bytes] -> received in request body (stringified JSON)
“””
if not payload:
payload = None
elif isinstance(payload, str):
payload = payload.encode(“utf-8”)
hash_value = hmac.new(secret_key.encode(“utf-8”), payload, sha256).hexdigest()
return “sha256=” + str(hash_value)
def verify_signature(secret_key: str, payload: Union[bytes, str], signature: str):
“””Verifies SHA256 signature prepended with sha256=
Args:
secret_key [String] -> shared secret, known by your service
payload [String or bytes] -> received in request body (stringified JSON)
signature [Signature] -> received in Interakt-Signature request header
“””
sha256_signature = generate_signature(secret_key=secret_key, payload=payload)
return sha256_signature == signature
# test the function
received_hmac = “sha256=b84783d10ede5bd6ed771e8b16fbe5a7093340159d6e49ec4248350b6ec2c7b4”
data_string = ‘{“foo”:1,”bar”:2}’
key = “examplekey”
if verify_signature(secret_key=key, payload=data_string, signature=received_hmac):
print(“Signature valid”)
else:
print(“Signature Invalid”)
Node JS:
We Can use crypto-js NPM Package
Ref: https://www.npmjs.com/package/crypto-js
const CryptoJS = require(‘crypto-js’);
function verifyHmac(
receivedHmac, // received in Interakt-Signature request header
dataString, // received in request body (stringified JSON)
key // shared secret, known by your service
) {
const generatedHmac = CryptoJS.HmacSHA256(dataString, key);
const generatedHmacBase64 = “sha256=” + CryptoJS.enc.Hex.stringify(generatedHmac);
return generatedHmacBase64 === receivedHmac;
}
// test the function
const receivedHmac = “sha256=b84783d10ede5bd6ed771e8b16fbe5a7093340159d6e49ec4248350b6ec2c7b4”;
const dataString = ‘{“foo”:1,”bar”:2}’;
const key = “examplekey”;
if (verifyHmac(receivedHmac, dataString, key)) {
console.log(“Signature Valid”);
} else {
console.log(“Signature Invalid”);
}
C#:
using System;
using System.Text;
using System.Security.Cryptography;
class Program
{
public static string ComputeHash(string secret, string payload)
{
byte[] bytes = Encoding.UTF8.GetBytes(secret);
HMAC hmac = new HMACSHA256(bytes);
bytes = Encoding.UTF8.GetBytes(payload);
return “sha256=” + BitConverter.ToString(hmac.ComputeHash(bytes)).Replace(“-“, “”).ToLower();
}
public static bool HashIsValid(string secret, string payload, string verify)
{
string hashString = ComputeHash(secret, payload);
return verify == hashString;
}
static void Main(string[] args)
{
// Testing our code
string receivedHmac = “sha256=b84783d10ede5bd6ed771e8b16fbe5a7093340159d6e49ec4248350b6ec2c7b4”;
string dataString = “{\”foo\”:1,\”bar\”:2}”;
string key = “examplekey”;
Console.WriteLine(HashIsValid(key, dataString, receivedHmac));
}
}
PHP:
<?php
$secret = “examplekey”;// your secret key
if (isset($_POST)) {
$payload = file_get_contents(‘php://input’);
$headers = getallheaders();
if (array_key_exists(“Interakt-Signature”, $headers)) {
$signature = $headers[“Interakt-Signature”];
$result = hash_is_valid($secret, $payload, $signature);
// if $result is true
// Hash is valid Api call is coming from interak
}
header(“HTTP/1.1 200 OK”);
}
function compute_hash($secret, $payload)
{
$prefix = “sha256=”;
$hexHash = hash_hmac(‘sha256’, $payload, utf8_encode($secret));
return $prefix.$hexHash;
}
function hash_is_valid($secret, $payload, $verify)
{
$computed_hash = compute_hash($secret, $payload);
return hash_equals($verify,$computed_hash);
}
?>
You can test your Endpoint Using Postman with a pre-request script:
var CryptoJS = require(“crypto-js”);
var keyString = ‘examplekey’;
function encrypt(data) {
var val = CryptoJS.HmacSHA256(data, keyString);
return “sha256=” + CryptoJS.enc.Hex.stringify(val);
}
// Set local variables to postman
pm.variables.set(
“hmac_sign”, encrypt(request.data)
);
This code will take your request body, create a HMAC signature using key “examplekey” (mentioned in line 2 of code) and set the env hmac_sign
Here is a Sample curl which is sending “Interakt-Signature” in headers
curl –location –request POST ‘<YOUR_ENDPOINT_HERE>’ \
–header ‘Interakt-Signature: {{hmac_sign}}’ \
–header ‘Content-Type: application/json’ \
–data-raw ‘{“foo”:1,”bar”:2}’
Instead of ‘{“foo”:1,”bar”:2}’ test with any request body.
Refer Screenshots :