WhatsApp Service Provider

How a WhatsApp Service Provider can integrate its platform with WebEngage

Adding your WhatsApp Service Provider (WSP) to WebEngage enables you to extend your services to over 40,000 global users and makes it easier for your existing clients to start using your services through their WebEngage dashboard.

How to Initiate WSP Integration

We'd love to add you to our Service Partner Network! Please feel free to initiate a conversation by dropping an email at [email protected] with the following details:

  1. Your test credentials. For example, you could share a username-password OR API Key and an API endpoint where we can POST requests.

  2. A logo of the service provider with a minimum width of 370 px in PNG/JPEG format.

  3. A static endpoint URL that listens to incoming HTTPS POST requests and adheres to the specified schema for sending WhatsApp messages.

    • Please note that this needs to be a single static endpoint. If you have multiple endpoints dedicated to various geographies and so on, then you will need to accept WebEngage requests on a single endpoint and route them accordingly for delivery.
  4. The request authentication method (Basic authentication or Bearer authentication).

  5. Input fields to be shown to the client on WebEngage dashboard. For example: API Key or Username and Password.

    • In case of API Key, the POST request will contain the header Authorization: Bearer API_KEY.

    • In case of Username and Password, the POST request will contain the header Authorization: Basic BASE_64(USERNAME:PASSWORD).

      • For example, if your username is 'webengage' and password is 'admin' then the Authorization header will be Basic d2ViZW5nYWdlOmFkbWlu. The string d2ViZW5nYWdlOmFkbWlu is the Base64 encoded version of the string webengage:admin.
  6. WebEngage comes with three servers: Indian, Saudi Arabia and US servers, and it is necessary that the DSN is configured for both servers.

You can find the DSN tracking link below. The DSN Token will be provided once the integration and testing are done by the WebEngage team.

Our support team will process your request if a mutual client agrees to test your WSP in private beta mode on our dashboard before we make it available for all our clients.

SECTION 1: The flow of the message will be as follows:

WebEngage will send message to the WhatsApp Service Provider (WSP) and WSP will reply synchronously to the message received with respective Status Codes given in the last section of this documentation.

WSP will reply back to WebEngage webhook (i.e. static endpoint which can be found on WebEngage dashboard following: Data Platform > Integrations > WhatsApp Setup (Configure) > ACTIONS (WSP) > View Webhook URL.) for the delivery report (i.e. Delivery Status Notification (DSN)) asynchronously.

1. WebEngage WhatsApp Request to WSP

As depicted in SECTION 1 point 1, WebEngage will send WhatsApp messages to WSP in the following given payload format and WSP needs to reply synchronously to the message with Status Codes provided in the last section of this documentation.

Key points for API request from WebEngage to WSP:

  1. At the time of integration, WebEngage allows WSP to either accept message or templateVariables in the payload request from WebEngage to WSP. templateVariables is a list of string of template variables provided by user as per template and message is the actual generalization of the user’s template with the given template variables.

e.g. if the template is: hello {{1}}, welcome to new {{2}} and template variables i.e. {{1}} and {{2}} are john and world, then the actual generalized message will be: hello john, welcome to the new world and templateVariables will be: ["john", "world"].

  1. templateData provided in the given below payload will only contain either message or templateVariables as per WSP’s choice at the time of integration. WSP will never receive both messages as well as templateVariables.

  2. The Content-Type header will always be application/json. We’ll also provide support for adding custom headers (specific to individual WSP) while the user creates WhatsApp WSP configuration on WebEngage dashboard.

Request format of payload from WebEngage to WSP

{
	"version": "1.0",
	"whatsAppData": {
		"toNumber": "919999999999",
		"fromNumber": "44000000099",
		"templateData": {
			"templateName": "templatexyz",
			"message": "hello john, welcome to new world",
			"templateVariables": ["john", "world"],
                        "type" : "TEXT",
      "buttonUrlParam" : "XYZ.pdf", // In the case of dynamic CallToAction  
			"language": "en"
		},
     "customData": {
      "key1": "value1",
      "key": "value"
    }
	},
	"metadata": {
		"campaignType": "PROMOTIONAL",
		"timestamp": "2018-01-25T10:24:16+0000",
		"messageId": "webengage-message-id"
	}
}
{
  "version": "1.0",
  "whatsAppData": {
    "toNumber": "919999999999",
    "fromNumber": "44000000099",
    "templateData": {
      "templateName": "templatexyzVIDEO",
 	 		"message": "hello john, welcome to new world",
      "templateVariables": ["john", "world"],
      "type" : "VIDEO",
      "mediaUrl":"https://www.webenagege.com/webengage-logo.png",
      "buttonUrlParam" : "XYZ.pdf", // In the case of dynamic CallToAction
      "language": "en"
    },
     "customData": {
      "key1": "value1",
      "key": "value"
    }
  },
  "metadata": {
    "campaignType": "PROMOTIONAL",
    "timestamp": "2018-01-25T10:24:16+0000",
    "messageId": "webengage-message-id"
  }
}
{
  "version": "1.0",
  "whatsAppData": {
    "toNumber": "919999999999",
    "fromNumber": "44000000099",
    "templateData": {
    	"templateName": "templatexyzIMAGE",
 	 		"message": "hello john, welcome to new world",
      "templateVariables": ["john", "world"],
      "type" : "IMAGE",
      "mediaUrl":"https://www.webenagege.com/webengage-logo.png",
      "buttonUrlParam" : "XYZ.pdf", // In the case of dynamic CallToAction
      "language": "en"
    },
    "customData": {
      "key1": "value1",
      "key": "value"
    }
  },
  "metadata": {
    "campaignType": "PROMOTIONAL",
    "timestamp": "2018-01-25T10:24:16+0000",
    "messageId": "webengage-message-id"
  }
}
{
  "version": "1.0",
  "whatsAppData": {
    "toNumber": "919999999999",
    "fromNumber": "44000000099",
    "templateData": {
      "templateName": "templatexyzDOC",
 	 		"message": "hello john, welcome to new world",
      "templateVariables": ["john", "world"],
      "type" : "DOCUMENT",
      "mediaUrl":"https://www.webenagege.com/webengage-logo.png",
			"fileName": "<file-name if added>",
      "buttonUrlParam" : "XYZ.pdf", // In the case of dynamic CallToAction
      "language": "en"
    },
     "customData": {
      "key1": "value1",
      "key": "value"
    }
  },
  "metadata": {
    "campaignType": "PROMOTIONAL",
    "timestamp": "2018-01-25T10:24:16+0000",
    "messageId": "webengage-message-id"
  }
}
{ 
  "version": "1.0",
  "whatsAppData": {
    "toNumber": "919999999999",
    "fromNumber": "44000000099",
    "templateData": {
			"templateName": "templatexyzDOC",
 			"message": "hello john, welcome to new world",
     	"templateVariables": ["john", "world"],
      "type" : "LOCATION",
      "longitude":15.946519,
      "latitude":45.946519,
      "locationName":"Name of the location",       
      "locationAddress":"Address",
      "buttonUrlParam" : "XYZ.pdf", // In the case of dynamic CallToAction
      "language": "en"
    }
  },
  "metadata": {
    "campaignType": "PROMOTIONAL",
    "timestamp": "2018-01-25T10:24:16+0000",
    "messageId": "webengage-message-id"
  }
}
KeyDescription
versionIndicates the payload contract. If there is any change in the payload structure in future, the version will be updated.
toNumberThe recipient’s encoded phone number along with prefixed country code.
fromNumberThe WhatsApp Business Number you are using to send the campaign.
templateNameName of the whitelisted template being used by you.
messagemessage 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.
templateVariablesList of string values of template variables in exact sequence as per template. It will be provided if you accept this in place of message

This key is included in the payload only if you select Send Personalization Variables against Request Type during configuration.
languageMessage template language supported by WhatsApp
buttonUrlParamIndicates the Dynamic call to Action placeholder value

This key is included in the payload only if Dynamic CTA buttons are added in the WhatsApp template
typeIndicates the WhatsApp media template type

This key is included in the payload only for media templates: TEXT, VIDEO, IMAGE, DOCUMENT, LOCATION
mediaUrlResource URL link which is to be sent

This key is included for VIDEO, IMAGE, DOCUMENT media templates
customData
(Optional)
In this section , you can pass extra data (in Key-value pair format from the dashboard) in the payload.

This is mainly used by partners if they require some custom integrations to be done for their internal systems or for particular clients.
longitudeLongitude value

This key is included for LOCATION template only
latitudeLatitude value

This key is included for LOCATION template only
locationNameName of the location

This key is included for LOCATION template only
locationAddressAddress of the location

This key is included for LOCATION template only

Here's what each parameter included in the metadata container denotes:

KeysDescription
campaignTypeThe value this key in the payload can be either PROMOTIONAL or TRANSACTIONAL as selected by the user creating campaign on WebEngage dashboard.
timestampThe time when the message was triggered from the WebEngage system. This follows the ISO date format: yyyy-MM-ddTHH:mm:ss±hhmm.
messageIdUnique 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 '<WSP-API-END-POINT>' \
--header '<HEADERS-PROVIDED-BY-YOU-IN-CONFIGURATION>' \
--header 'Content-Type: application/json' \
--data-raw '{
	"version": "1.0",
	"whatsAppData": {
		"toNumber": "919999999999",
		"fromNumber": "44000000099",
		"templateData": {
			"templateName": "templatexyz",
			"templateVariables": ["john", "world"],
                        "type" : "TEXT",
      "buttonUrlParam" : "XYZ.pdf", // In the case of dynamic CallToAction  
			"language": "en"
		}
	},
	"metadata": {
		"campaignType": "PROMOTIONAL",
		"timestamp": "2018-01-25T10:24:16+0000",
		"messageId": "webengage-message-id"
	}
}
curl --location --request POST '<WSP-API-END-POINT>' \
--header '<HEADERS-PROVIDED-BY-YOU-IN-CONFIGURATION>' \
--header 'Content-Type: application/json' \
--data-raw '{
  "version": "1.0",
  "whatsAppData": {
    "toNumber": "919999999999",
    "fromNumber": "44000000099",
    "templateData": {
      "templateName": "templatexyzVIDEO",
      "templateVariables": ["john", "world"],
      "type" : "VIDEO",
      "mediaUrl":"https://www.webenagege.com/webengage-logo.png",
      "buttonUrlParam" : "XYZ.pdf", // In the case of dynamic CallToAction
      "language": "en"
    }
  },
  "metadata": {
    "campaignType": "PROMOTIONAL",
    "timestamp": "2018-01-25T10:24:16+0000",
    "messageId": "webengage-message-id"
  }
}
curl --location --request POST '<WSP-API-END-POINT>' \
--header '<HEADERS-PROVIDED-BY-YOU-IN-CONFIGURATION>' \
--header 'Content-Type: application/json' \
--data-raw '{
  "version": "1.0",
  "whatsAppData": {
    "toNumber": "919999999999",
    "fromNumber": "44000000099",
    "templateData": {
    	"templateName": "templatexyzIMAGE",
      "templateVariables": ["john", "world"],
      "type" : "IMAGE",
      "mediaUrl":"https://www.webenagege.com/webengage-logo.png",
      "buttonUrlParam" : "XYZ.pdf", // In the case of dynamic CallToAction
      "language": "en"
    }
  },
  "metadata": {
    "campaignType": "PROMOTIONAL",
    "timestamp": "2018-01-25T10:24:16+0000",
    "messageId": "webengage-message-id"
  }
}
curl --location --request POST '<WSP-API-END-POINT>' \
--header '<HEADERS-PROVIDED-BY-YOU-IN-CONFIGURATION>' \
--header 'Content-Type: application/json' \
--data-raw '{
  "version": "1.0",
  "whatsAppData": {
    "toNumber": "919999999999",
    "fromNumber": "44000000099",
    "templateData": {
      "templateName": "templatexyzDOC",
      "templateVariables": ["john", "world"],
      "type" : "DOCUMENT",
      "mediaUrl":"https://www.webenagege.com/webengage-logo.png",
			"fileName": "<file-name if added>",
      "buttonUrlParam" : "XYZ.pdf", // In the case of dynamic CallToAction
      "language": "en"
    }
  },
  "metadata": {
    "campaignType": "PROMOTIONAL",
    "timestamp": "2018-01-25T10:24:16+0000",
    "messageId": "webengage-message-id"
  }
}
curl --location --request POST '<WSP-API-END-POINT>' \
--header '<HEADERS-PROVIDED-BY-YOU-IN-CONFIGURATION>' \
--header 'Content-Type: application/json' \
--data-raw '{ 
  "version": "1.0",
  "whatsAppData": {
    "toNumber": "919999999999",
    "fromNumber": "44000000099",
    "templateData": {
			"templateName": "templatexyzDOC",
     	"templateVariables": ["john", "world"],
      "type" : "LOCATION",
      "longitude":15.946519,
      "latitude":45.946519,
      "locationName":"Name of the location",       
      "locationAddress":"Address",
      "buttonUrlParam" : "XYZ.pdf", // In the case of dynamic CallToAction
      "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 '<WSP-API-END-POINT>' \
--header '<HEADERS-PROVIDED-BY-YOU-IN-CONFIGURATION>' \
--header 'Content-Type: application/json' \
--data-raw '{
	"version": "1.0",
	"whatsAppData": {
		"toNumber": "919999999999",
		"fromNumber": "44000000099",
		"templateData": {
			"templateName": "templatexyz",
			"message": "hello john, welcome to new world",
			"templateVariables": ["john", "world"],
                        "type" : "TEXT",
      "buttonUrlParam" : "XYZ.pdf", // In the case of dynamic CallToAction  
			"language": "en"
		}
	},
	"metadata": {
		"campaignType": "PROMOTIONAL",
		"timestamp": "2018-01-25T10:24:16+0000",
		"messageId": "webengage-message-id"
	}
}
curl --location --request POST '<WSP-API-END-POINT>' \
--header '<HEADERS-PROVIDED-BY-YOU-IN-CONFIGURATION>' \
--header 'Content-Type: application/json' \
--data-raw '{
  "version": "1.0",
  "whatsAppData": {
    "toNumber": "919999999999",
    "fromNumber": "44000000099",
    "templateData": {
      "templateName": "templatexyzVIDEO",
 	 		"message": "hello john, welcome to new world",
      "templateVariables": ["john", "world"],
      "type" : "VIDEO",
      "mediaUrl":"https://www.webenagege.com/webengage-logo.png",
      "buttonUrlParam" : "XYZ.pdf", // In the case of dynamic CallToAction
      "language": "en"
    }
  },
  "metadata": {
    "campaignType": "PROMOTIONAL",
    "timestamp": "2018-01-25T10:24:16+0000",
    "messageId": "webengage-message-id"
  }
}
curl --location --request POST '<WSP-API-END-POINT>' \
--header '<HEADERS-PROVIDED-BY-YOU-IN-CONFIGURATION>' \
--header 'Content-Type: application/json' \
--data-raw '{
  "version": "1.0",
  "whatsAppData": {
    "toNumber": "919999999999",
    "fromNumber": "44000000099",
    "templateData": {
    	"templateName": "templatexyzIMAGE",
 	 		"message": "hello john, welcome to new world",
      "templateVariables": ["john", "world"],
      "type" : "IMAGE",
      "mediaUrl":"https://www.webenagege.com/webengage-logo.png",
      "buttonUrlParam" : "XYZ.pdf", // In the case of dynamic CallToAction
      "language": "en"
    }
  },
  "metadata": {
    "campaignType": "PROMOTIONAL",
    "timestamp": "2018-01-25T10:24:16+0000",
    "messageId": "webengage-message-id"
  }
}
curl --location --request POST '<WSP-API-END-POINT>' \
--header '<HEADERS-PROVIDED-BY-YOU-IN-CONFIGURATION>' \
--header 'Content-Type: application/json' \
--data-raw '{
  "version": "1.0",
  "whatsAppData": {
    "toNumber": "919999999999",
    "fromNumber": "44000000099",
    "templateData": {
      "templateName": "templatexyzDOC",
 	 		"message": "hello john, welcome to new world",
      "templateVariables": ["john", "world"],
      "type" : "DOCUMENT",
      "mediaUrl":"https://www.webenagege.com/webengage-logo.png",
			"fileName": "<file-name if added>",
      "buttonUrlParam" : "XYZ.pdf", // In the case of dynamic CallToAction
      "language": "en"
    }
  },
  "metadata": {
    "campaignType": "PROMOTIONAL",
    "timestamp": "2018-01-25T10:24:16+0000",
    "messageId": "webengage-message-id"
  }
}
curl --location --request POST '<WSP-API-END-POINT>' \
--header '<HEADERS-PROVIDED-BY-YOU-IN-CONFIGURATION>' \
--header 'Content-Type: application/json' \
--data-raw '{
 { 
  "version": "1.0",
  "whatsAppData": {
    "toNumber": "919999999999",
    "fromNumber": "44000000099",
    "templateData": {
			"templateName": "templatexyzDOC",
 			"message": "hello john, welcome to new world",
     	"templateVariables": ["john", "world"],
      "type" : "LOCATION",
      "longitude":15.946519,
      "latitude":45.946519,
      "locationName":"Name of the location",       
      "locationAddress":"Address",
      "buttonUrlParam" : "XYZ.pdf", // In the case of dynamic CallToAction
      "language": "en"
    }
  },
  "metadata": {
    "campaignType": "PROMOTIONAL",
    "timestamp": "2018-01-25T10:24:16+0000",
    "messageId": "webengage-message-id"
  }
}

Examples for synchronous response for above payloads from WSP to WebEngage:

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, send message property too.

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

Example 3: Payload Not Acceptable

NOTE: In case there is mismatch in payload version of API contract (current is 1.0).

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

2. Delivery Status Notification (DSN) from WSP to WebEngage

Delivery report of each message forwarded by WSP to WebEngage is called as Delivery Status Notification (DSN). It helps our clients to track their campaign's performance in their WebEngage dashboard.

As depicted in SECTION 1 point 2, DSNs are asynchronous updates to messages (e.g. WhatsApp message delivered, expired, rejected etc.) that WSP sends to WebEngage webhook.

Key points for DSN from WSP to WebEngage:

  1. WSP is required to POST DSN i.e. WhatsApp message sent, failed, etc. on the static endpoint which can be found on WebEngage dashboard following: Data Platform > Integrations > WhatsApp Setup (Configure) > ACTIONS (WSP) > View Webhook URL.

WebEngage comes with three servers: Saudi Arabia, India and US servers, and it is necessary that the DSN is configured for both servers.

You can find the DSN tracking link below. The DSN Token will be provided once the integration and testing are done by the WebEngage team.

The service provider is required to POST Delivery Status Notifications (DSNs) i.e. WhatsApp Message sent, failed, etc. on the static endpoint.

For US Server http://wt.webengage.com/tracking/events
For IN Server http://wt.in.webengage.com/tracking/events
For KSA Server http://wt.ksa.webengage.com/tracking/events

  1. WSP will be provided with:

Auth token - which needs to be included as an Authorization header in the POST request of DSNs.

e.g. Authorization: Bearer . This token will remain the same and should not be shared to ensure security. In case there is a need to change the token, WSP should reach out to WebEngage Support to get a new token.

  1. Content-Type Header for the DSN request should be application/json.

  2. WebEngage will respond to the DSN request with an HTTP 2XX response code.

Request format of DSN payload from WSP to WebEngage

{
    "version": "1.0",
    "messageId" : "webengage-message-id",
    "toNumber" : "919999999999",
    "status": "whatsapp_sent",
    "statusCode" : 0,
    "reason": "FAILED WHILE TRANSMISSION",
    "timestamp": "2018-01-25T10:24:16+0000"
}
KeyDescription
versionThis indicates the payload contract of the request. If there is any change in the payload structure in future, the version will be updated.
messageIdThis 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.
toNumberThe message recipient’s phone number along with prefixed country code.
statusThe message status being reported by this DSN. This can be either whatsapp_sent,whatsapp_failed or whatsapp_read.
statusCodeStatus code of this DSN. This must be one of the status codes described below.
reasonIt is an optional field (must be given when statusCode doesn’t fulfill failed reason, or when statusCode is 9988).
timestampThe 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" : "919999999999",
    "status": "whatsapp_sent",
    "statusCode" : 0,
    "reason": "sent successfully to user",
    "timestamp": "2018-01-25T10:24:16+0000"
}'

Status Code

These status codes are to be used both for synchronous responses and DSN. Refer to the Description column below for more details about the respective status. Make sure that you send the appropriate HTTP status corresponding to the status codes.

Status CodeDescriptionHTTP Status
0Message delivery is successful!200
2000Insufficient credit balance200
2001The IP has not been whitelisted401
2002Empty message body400
2003Invalid mobile number400
2004Invalid Business Number400
2005Authorization failure403
2006User blocked the Business Number200
2007Maximum length of the message body has been exceeded413
2008The message has expired200
2009The message was not delivered by the operator200
2010Payload 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
2011Authentication failure (e.g. mobile number might be unverified)401
2014Maximum number of retries to send the message have been exhausted.200
2015Throttling 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. The time intervals between retries would be in the following order (in mins): 3 + 6 + 9 + 12 + 15 + 15 + 15 + 15 + 15
429
2019The message format is invalid400
2021Template Missing400
2022Template Parameter Format Mismatch400
2023Template did not match400
2024User isn't opted in for template message200
2025User is not Opted in and is inactive200
9988Unknown or other failures200