Private WSP

Deliver highly personalize WhatsApp messages to encrypted phone numbers with great ease!

Many businesses are averse to sharing contact details of their users with third-party platforms like WebEngage.

We understand your concerns.

This is why, we've made it possible for you to leverage a user's PII (Personally Identifiable Information) for sending WhatsApp campaigns without actually sharing their phone numbers! This can be achieved by setting up a Private WSP API endpoint at your end.

Private WhatsApp Service Provider Basics

You can think of Private WSP as a proxy layer that decrypts phone numbers of a WhatsApp campaign's target audience before sending it to your WSP for delivery to your users. All you need to do is:

Step 1: Pass hashed PII data to WebEngage from your servers.

Step 2: Set up a Private WSP API endpoint to decrypt hashed phone numbers and integrate with WebEngage.

Step 3: Configure Webhooks to ensure that the delivery status notifications (Sent, Delivered, Read, Failed) are relayed for each message from your WSP --> Decryption Layer --> WebEngage dashboard.

Step 4: Select Private WSP as the preferred WSP while creating the WhatsApp campaign.

PII Hashing


At WebEngage, we refer to User Attributes such as phone and email as PII (Personally Identifiable Information), which can be encrypted to safeguard your user's privacy.

Thus, the term PII Hashing refers to the encryption of these details. If you opt to do so, then instead of passing actual data against the attributes mentioned above, you will need to pass the hashed values against the attributes, hashed_phone and hashed_email, respectively.

Passing Hashed PII Values

All our platform integration SDKs enable you to pass hashed phone numbers and email addresses for each user. Here are a few examples to help you get started:

webengage.user.setAttribute({
  'we_hashed_phone': 'e0ec043b3f9e198ec09041687e4d4e8d',
  'we_hashed_email': '144e0424883546e07dcd727057fd3b62'
});
weUser.setHashedEmail(String hashedEmail)
weUser.setHashedPhoneNumber(String hashedPhoneNumber)
-(void) setHashedEmail:(NSString*)hasdhedemail;
-(void) setHashedPhone:(NSString*)hashedphone;

Please Note:

  • The values passed against hashed_phone must be encrypted in a format that you can decrypt later through the Private SSP.
  • The encrypted value can be a maximum of 512 characters. Additional characters will be truncated.
  • Please ensure that the actual phone number is never passed through this method.

🚧

Start Here!

How to Configure Private WSP

Now that you're sending us encrypted user data, let's show you how you can leverage it to engage users (while keeping their identity a top-secret!)

Click to enlarge

As shown above:

Step 1: Access Integrations > Channels > WhatsApp

  • Click on Add WhatsApp Service Provider to get started.

  • In doing so, you will be prompted by a pop-up. Click the first dropdown and select Private WSP.

Step 2: Add Business Number

Step 3: Add URL

  • As shown above, Add the endpoint URL of your Private WSP layer.

  • Each time you launch a campaign, where Private WSP is selected as the preferred WSP, we will POST an API call to this URL in JSON.

Step 4: Specify Request Type

Before configuring this field, please check with your WSP about the type of data they are willing to ingest from your Private WSP endpoint. While some WSPs prefer to ingest the entire message (containing the whitelisted template's text and values of personalization variables) in the message payload, others prefer to receive only the personalization tokens.

Click to enlarge

As shown above:

  • Select Send Entire Message to pass the template's text and personalization variables from WebEngage to your Private WSP layer.

  • Select Send Personalization Variables to pass only values of the personalization variables from WebEngage to your Private WSP layer. This way, your WSP will simply populate the selected message template (that has been whitelisted by them) with the personalization variables for each user before delivery.

đź‘Ť

Understanding Request Type

For example, let's assume that your template is:

Hey {{1}}, we're delighted to have you aboard! Here's your code, {{2}} to help you get started!

Where,

Variable {{1}} = Name

Variable {{2}} = Unique Password

Then the WhatsApp message received by the user, Sophie would be:

Hey Sophie, we're delighted to have you aboard! Here's your code, Sph512X to help you get started!

Thus, if you've selected Send Entire Message against Request Type, then you will receive the above message in the payload.

However, if you select Send Personalization Variables against Request Type, then you will receive only values of the template variables - [Sophie, Sph512X] in the message payload.

Step 5 (Optional): Add Custom Headers

Click to enlarge

  • You can choose to pass custom data as key-value pairs by adding them here in JSON. This field can also be used to pass Authorization Headers.

  • Click Add Headers to continue adding custom data.

  • Click Add WSP to complete the integration, and you're good to go!

You can test the integration by creating a campaign targeting opted-in internal users (aka your teammates) to ensure everything's running smoothly.

Request

🚧

About Link Wrapping/Shortening in Message

If your Private WSP is performing additional link wrapping on the links already wrapped by WebEngage (original URL) anywhere in the request payload, then the wrapped domain must ask the caller to follow the original URL-encoded location.

For example, let's assume that the message has the following hyperlink:

<a href=“https://google.co.in/?param=%3D%3D%2B%20%20abcd”> Link </a>

We have a parameter named param with a value of ==+ abcd here.

Thus, if you are further wrapping this link, then the wrapped domain must ask the caller to follow the URL-encoded location (https://google.co.in/?param=%3D%3D%2B%20%20abcd), and not the decoded one (https://google.co.in/?param===+ abcd).

  • WebEngage will add “Content-Type”: “application/json” by default to the Custom Headers in the POST call.

  • A unique ID, UUID will also be passed as custom data by default. This helps uniquely identify each WhatsApp message.

Here's a sample snippet to help you understand the format in which you will receive the payload from WebEngage:

{
    "version": "1.0",
    "whatsAppData": {
        "toNumber": "ENCODEDXYZ123PHONENUMBER",
        "fromNumber": "44000000099",
        "templateData": {
            "templateName": "templatexyz",
            "message": "hello john, welcome to new world",
            "templateVariables": ["john", "world"],
            "language": "en"
        }
    },
    "metadata": {
        "campaignType": "PROMOTIONAL",
        "timestamp": "2018-01-25T10:24:16+0000",
        "messageId": "webengage-message-id"
    }
}

Let's break down each line of the above code:

Key

Description

version

Indicates the payload contract. If there is any change in the payload structure in future, the version will be updated.

toNumber

The recipient’s encoded phone number along with prefixed country code.

fromNumber

The WhatsApp Business Number you are using to send the campaign.

templateName

Name of the whitelisted template being used by you.

message

message to be delivered to user (generalised message as per template and template variables). It will be provided if you accept this in place of templateVariables.

templateVariables

List of string values of template variables in exact sequence as per template. It will be provided if you accept this in place of message

language

Message template language supported by WhatsApp

campaignType

The value this key in the payload can be either PROMOTIONAL or TRANSACTIONAL as selected by the user creating campaign on WebEngage dashboard.

timestamp

The time when the message was triggered from the WebEngage system. This follows the ISO date format: yyyy-MM-ddTHH:mm:ss±hhmm.

messageId

Unique ID assigned to the message which should be used in further Delivery Status Notifications to identify a message uniquely.

Example curl Request for Request Type: Send Personalization Variables

curl --location --request POST '<PRIVATE-WSP-API-END-POINT>' \
--header '<HEADERS-PROVIDED-BY-YOU-IN-CONFIGURATION>' \
--header 'Content-Type: application/json' \
--data-raw '{
    "version": "1.0",
    "whatsAppData": {
        "toNumber": "ENCODEDXYZ123PHONENUMBER",
        "fromNumber": "44000000099",
        "templateData": {
            "templateName": "templatexyz",
            "templateVariables": ["john", "world"],
            "language": "en"
        }
    },
    "metadata": {
        "campaignType": "PROMOTIONAL",
        "timestamp": "2018-01-25T10:24:16+0000",
        "messageId": "webengage-message-id"
    }
}'

Example curl Request for Request Type: Send Entire Message

curl --location --request POST '<PRIVATE-WSP-API-END-POINT>' \
--header '<HEADERS-PROVIDED-BY-YOU-IN-CONFIGURATION>' \
--header 'Content-Type: application/json' \
--data-raw '{
    "version": "1.0",
    "whatsAppData": {
        "toNumber": "ENCODEDXYZ123PHONENUMBER",
        "fromNumber": "44000000099",
        "templateData": {
            "templateName": "templatexyz",
            "message": "hello john, welcome to new world",
            "language": "en"
        }
    },
    "metadata": {
        "campaignType": "PROMOTIONAL",
        "timestamp": "2018-01-25T10:24:16+0000",
        "messageId": "webengage-message-id"
    }
}'

Response

For each message forwarded to your Private WSP, we expect a response containing a Delivery Status Notification (DSN). These are asynchronous updates like message delivered, expired, rejected and so on, that can be sent to your dashboard by configuring Webhooks. Doing so enables you to analyze your campaign's performance against several metrics in your dashboard.

Delivery Status Notification

DSNs can be sent as POST API requests to the static endpoint which can be found in your dashboard. As shown below:

Click to enlarge

Step 1: Click on the Actions overflow buttons nested against the Private WSP configured by you.

Step 2: Click on View Webhook URL.
In doing so, a pop-up containing the static endpoint URL will appear on the screen.

Step 3: Copy the URL as shown above and use it to configure your Private WSP layer.

  • You will be provided with a security token (Auth token) that needs to be which needs to be included as an authorization header in the DSN request.

    • For example: Authorization: Bearer <Security Token>. This token will remain the same and should not be shared to ensure security. Please feel free to reach out to us at [email protected] in case you need a new authorization token.
  • DSN parameters must include the previously passed UUID specifying a delivery report for a particular message.

  • WebEngage will respond to the delivery status notification with an HTTP 2XX response code and will enqueue the event to process it.

Here's a sample DSN request snippet for your reference:

{
    "version": "1.0",
    "messageId" : "webengage-message-id",
    "toNumber": "ENCODEDXYZ123PHONENUMBER",
    "status": "whatsapp_sent",
    "statusCode" : 0,
    "reason": "sent successfully to user",
    "timestamp": "2018-01-25T10:24:16+0000"
}

Let's break down each line of the above code:

Key

Description

version

This indicates the payload contract of the request. If there is any change in the payload structure in future, the version will be updated.

messageId

This is the unique ID assigned to the message which is used to identify a message uniquely.

This is received by the service provider in the request body. The length of this string can be up to 500 characters. The messageId provided in DSNs must be the same as that received from WebEngage in the request. You must not modify it.

toNumber

The message recipient’s phone number along with prefixed country code.

status

The message status being reported by this DSN. This can be either whatsapp_sent,whatsapp_failed or whatsapp_read.

statusCode

Status code of this DSN. This must be one of the status codes described below.

reason

It is an optional field (must be given when statusCode doesn’t fulfill failed reason, or when statusCode is 9988).

timestamp

The time when the message was triggered from the WebEngage system. This follows the ISO date format: yyyy-MM-ddTHH:mm:ss±hhmm.

Example curl Request of DSN with Auth token Passed as Header for Authorization

curl --location --request POST '<STATIC-DSN-END-POINT-OF-WEBENGAGE>' \
--header 'Authorization: Bearer <AUTH-TOKEN-PROVIDED-BY-WEBENGAGE>' \
--header 'Content-Type: application/json' \
--data-raw '{
    "version": "1.0",
    "messageId" : "webengage-message-id",
    "toNumber" : "ENCODEDXYZ123PHONENUMBER",
    "status": "whatsapp_sent",
    "statusCode" : 0,
    "reason": "sent successfully to user",
    "timestamp": "2018-01-25T10:24:16+0000"
}'

Status Codes

These status codes are to be used for both, synchronous responses and Delivery Status Notifications (DSN). Please ensure that you send the appropriate HTTP status corresponding to the status codes.

Status Code

Description

HTTP Status

0

Message delivery is successful!

200

2000

Insufficient credit balance

200

2001

The IP has not been whitelisted

401

2002

Empty message body

400

2003

Invalid mobile number

400

2004

Invalid Business Number

400

2005

Authorization failure

403

2006

User blocked the Business Number

200

2007

Maximum length of the message body has been exceeded

413

2008

The message has expired

200

2009

The message was not delivered by the operator

200

2010

Payload version unsupported.

In this case the supportedVersion is to be sent mandatorily, i.e., the version supported by the service provider. For example:

HTTP 400 BAD REQUEST
{
    "status" : "sms_rejected",
    "statusCode" : 2010,
    "message" : "Version not supported",
    "supportedVersion" : "2.0"
}

400

2011

Authentication failure (e.g. mobile number might be unverified)

401

2014

Maximum number of retries to send the message have been exhausted.

200

2015

Throttling error.

To handle the loads with increasing customer base, WebEngage has introduced autoscaling which can occasionally result in higher call rates. WebEngage supports throttling from SSP end to handle such cases. Sending this status code will activate throttling for that request and WebEngage will send that request at later time.

Note:

  1. WebEngage will retry sending the message 10 times if this status is received.
  2. Time interval between retries follows binary exponential backoff: 0ms, 200ms, 400ms, 800ms...

429

2019

The message format is invalid

400

2021

Template Missing

400

2022

Template Parameter Format Mismatch

400

2023

Template did not match

400

2024

User isn't opted in for template message

200

2025

User is not Opted in and is inactive

200

9988

Unknown or other failures

200

Response Examples

Here are a few sample snippets of synchronous responses:

Example 1: Message Accepted Successfully

HTTP 200 OK
{
    "status" : "whatsapp_accepted",
    "statusCode": 0
}

Example 2: Message Cannot Be Sent Further

NOTE: If the status code is not 0, then please send the message property too.

HTTP 200 OK
{
    "status": "whatsapp_rejected",
    "statusCode": 2000,
    "message": "Not enough credit to send message"
}

Example 3: Payload Not Acceptable

The following snippet depicts a scenario where there is a mismatch in the payload version of the API contract (currently we're using v1.0).

HTTP 400 BAD REQUEST
{
    "status" : "whatsapp_rejected",
    "statusCode" : 2010,
    "message" : "Version not supported",
    "supportedVersion" : "2.0" // Mandatory in case of statusCode 2010
}

We hope this has enabled you to set up a decryption layer for sending WhatsApp campaigns to encrypted phone numbers. Please feel free to drop in a few lines at [email protected] in case you have further queries. We're always just an email away!

Updated about a month ago


Private WSP


Deliver highly personalize WhatsApp messages to encrypted phone numbers with great ease!

Suggested Edits are limited on API Reference Pages

You can only suggest edits to Markdown body content, but not to the API spec.