Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save ofarras/c130e7ce84d526ec2f54ca7fbd03ac72 to your computer and use it in GitHub Desktop.
Save ofarras/c130e7ce84d526ec2f54ca7fbd03ac72 to your computer and use it in GitHub Desktop.

Revisions

  1. @amitastreait amitastreait created this gist Jul 6, 2023.
    5 changes: 5 additions & 0 deletions WhatsAppChatComponent.css
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,5 @@
    .btnIconOverlay {
    position: absolute;
    z-index: 1;
    margin: 0% 0px 0px 88%;
    }
    81 changes: 81 additions & 0 deletions WhatsAppChatComponent.html
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,81 @@
    <template>
    <lightning-card variant="Narrow" >

    <lightning-button if:true={messageList} variant="border-filled"
    label="Chat with another customer" onclick={handleAnOtherChat} slot="actions">
    </lightning-button>

    <lightning-spinner alternative-text="Loading" size="small" if:true={isSpinner}></lightning-spinner>
    <div class="slds-p-horizontal_small">

    <section role="log" class="slds-chat" if:false={messageList}>
    <lightning-input type="tel"
    message-when-value-missing="Please provide a valid contact no to chat with"
    required variant="label-hidden" name="Phone"
    onchange={handlePhoneChange}
    placeholder="Enter Customer Phone Number and click next">
    </lightning-input>
    <br/>
    <lightning-button variant="brand" label="Chat with Customer" title="Chat with Customer" onclick={handlelistAllMessageByCustomer}></lightning-button>
    </section>

    <section role="log" class="messageContent slds-chat slds-scrollable" if:true={messageList} style="height: 350px;">
    <ul class="slds-chat-list">
    <template if:true={messageList} for:each={messageList} for:item="message" for:index="index">
    <!-- Message From Customer -->
    <li class="slds-chat-listitem slds-chat-listitem_inbound" key={message.Id} if:false={message.Outgoing__c}>
    <div class="slds-chat-message" if:true={message.MessageContent__c}>
    <span aria-hidden="true" class="slds-avatar slds-avatar_circle slds-chat-avatar">
    <abbr class="slds-avatar__initials slds-avatar__initials_inverse" title={message.CustomerName__c}>AM</abbr>
    </span>
    <div class="slds-chat-message__body">
    <div class="slds-chat-message__text slds-chat-message__text_inbound">
    <span>
    <lightning-formatted-rich-text value={message.MessageContent__c}></lightning-formatted-rich-text>
    </span>
    </div>
    <div class="slds-chat-message__meta" aria-label={message.areaLabel}>{message.CustomerName__c} • <lightning-formatted-date-time value={message.CreatedDate} hour="2-digit"></lightning-formatted-date-time></div>
    </div>
    </div>
    </li>
    <!-- Message From Salesforce -->
    <li class="slds-chat-listitem slds-chat-listitem_outbound" key={message.Id} if:true={message.Outgoing__c}>
    <div class="slds-chat-message" if:true={message.MessageContent__c}>
    <!-- <span aria-hidden="true" class="slds-avatar slds-avatar_circle slds-chat-avatar">
    <abbr class="slds-avatar__initials slds-avatar__initials_inverse" title={message.AgentName__c}>AM</abbr>
    </span> -->
    <div class="slds-chat-message__body">
    <div class="slds-chat-message__text slds-chat-message__text_outbound">
    <span>
    <lightning-formatted-rich-text value={message.MessageContent__c}></lightning-formatted-rich-text>
    </span>
    </div>
    <div class="slds-chat-message__meta" aria-label={message.areaLabel}>{message.AgentName__c} • <lightning-formatted-date-time value={message.CreatedDate} hour="2-digit"></lightning-formatted-date-time></div>
    </div>
    </div>
    </li>
    </template>
    </ul>
    </section>
    <div if:true={chatEnabled}>
    <span class="slds-icon_container slds-icon-utility-end_chat slds-chat-icon">
    <svg class="slds-icon slds-icon_x-small slds-icon-text-default" aria-hidden="true">
    <use xlink:href="/apexpages/slds/latest/assets/icons/utility-sprite/svg/symbols.svg#chat"></use>
    </svg>
    </span>
    <p>
    <lightning-button-icon onclick={handleSendMessage} class="btnIconOverlay" icon-name="utility:send">
    </lightning-button-icon>
    <lightning-input message-when-value-missing="Please type a valid messgae before sending it"
    required value={chatMessage} type="text" class="chat-input"
    variant="label-hidden" onchange={handleChatChange} name="Message"
    placeholder="type here...">
    </lightning-input>
    </p>
    </div>
    </div>
    <div slot="footer">
    Powered by <a href="https://www.pantherschools.com/" target="_blank" aria-label="Panther Schools">@PantherSchools.com</a>
    </div>
    </lightning-card>
    </template>
    171 changes: 171 additions & 0 deletions WhatsAppChatComponent.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,171 @@
    import { api, LightningElement, track } from 'lwc';

    import listAllMessageByCustomer from '@salesforce/apex/WhatsAppLWCService.listAllMessageByCustomer';
    import sendTextMessage from '@salesforce/apex/WhatsAppLWCService.sendTextMessage';
    import getSingleMessage from '@salesforce/apex/WhatsAppLWCService.getSingleMessage';
    import { subscribe, onError } from 'lightning/empApi';

    export default class WhatsAppChatComponent extends LightningElement {

    @api recordId;

    @track messageList;
    @track errors;

    channelName = '/event/WAMessageEvent__e';

    subscription = {};

    chatMessage
    customerNo;
    isSpinner = false;
    chatEnabled = false;

    handleChatChange(event){
    event.preventDefault();
    this.chatMessage = event.target.value;
    }

    connectedCallback(){
    this.registerErrorListener();
    this.handleSubscribe();
    }

    handlelistAllMessageByCustomer(event){
    event.preventDefault();
    if(!this.handleValidate()){
    return;
    }
    this.isSpinner = true;
    listAllMessageByCustomer({
    customerPhone : this.customerNo
    })
    .then(result => {
    this.messageList = result.map(item => {
    return {
    ...item,
    areaLabel: item.Outgoing__c ? `${item.AgentName__c} said at ${item.CreatedDate}` : `${item.CustomerName__c} said at ${item.CreatedDate}`
    }
    });
    this.chatEnabled = true;
    })
    .catch(error => {
    console.error('Error:', error);
    this.errors = error;
    })
    .finally(()=>{
    this.chatEnabled = true;
    console.log('turing off the spinner');
    const chatArea = this.template.querySelector('.messageContent');
    if(chatArea){
    chatArea.scrollTop = chatArea.scrollHeight
    }
    this.isSpinner = false;

    this.setUpChatMessage();
    })
    }

    setUpChatMessage(){
    let chatInput = this.template.querySelector(".chat-input");
    if(chatInput){
    chatInput.addEventListener("keydown", (event) => {
    console.log(`Enent handler added`)
    if (event.key === "Enter") {
    this.handleSendMessage();
    }
    });
    }
    }

    handleSendMessage(){

    console.log('Enter Clicked ', this.chatMessage );
    if(!this.handleValidate()){
    return;
    }
    this.isSpinner = true;
    console.log(this.customerNo);
    sendTextMessage({
    messageContent : this.chatMessage,
    toPhone : this.customerNo
    })
    .then(result => {
    console.log(' message list ', result );
    this.chatMessage = '';
    this.messageList = [...this.messageList, result];
    console.log(' Updated Message from ', this.messageList );
    })
    .catch(error => {
    // TODO Error handling
    })
    .finally(()=>{
    console.log('turing off the spinner');
    this.isSpinner = false;
    })
    }

    handlePhoneChange(event){
    this.customerNo = event.target.value;
    }

    handleAnOtherChat(event){
    event.preventDefault();
    this.messageList = undefined;
    this.chatEnabled = false;
    }

    handleValidate(){
    const allValid = [
    ...this.template.querySelectorAll('lightning-input'),
    ].reduce((validSoFar, inputCmp) => {
    inputCmp.reportValidity();
    return validSoFar && inputCmp.checkValidity();
    }, true);
    return allValid;
    }

    registerErrorListener() {
    // Invoke onError empApi method
    onError((error) => {
    console.log('Received error from server: ', JSON.stringify(error));
    // Error contains the server-side error
    });
    }

    handleSubscribe() {
    // Callback invoked whenever a new event message is received
    const messageCallback = this.handleEventResponse.bind(this);

    // Invoke subscribe method of empApi. Pass reference to messageCallback
    subscribe(this.channelName, -1, messageCallback).then((response) => {
    this.subscription = response;
    });
    }

    handleEventResponse(response) {
    console.log('New message received: ', JSON.stringify(response));
    let payload = response.data.payload;
    let MessageId = payload.MessageId__c;
    let CustomerPhone = payload.CustomerPhone__c;

    if(this.customerNo === CustomerPhone){
    getSingleMessage({
    recordId : MessageId,
    customerPhone : CustomerPhone
    })
    .then(result => {
    this.messageList = [...this.messageList, result];
    const chatArea = this.template.querySelector('.messageContent');
    if(chatArea){
    chatArea.scrollTop = chatArea.scrollHeight
    }
    })
    .catch(error => {
    // TODO Error handling
    console.error(error);

    });
    }
    }
    }
    49 changes: 49 additions & 0 deletions WhatsAppLWCService.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,49 @@
    public class WhatsAppLWCService {

    @AuraEnabled
    public static sObject getCustomerPhone(String Query){
    return Database.query(Query);
    }

    @AuraEnabled//(cacheable=true)
    public static List<WAMessage__c> listAllMessages(String customerPhone){
    List<WAMessage__c> messages = new List<WAMessage__c>();
    messages = [SELECT Id, Name, MessageContent__c, MessageType__c, CustomerName__c, AgentName__c, Outgoing__c, CreatedDate
    FROM WAMessage__c
    WHERE CustomerPhone__c =: customerPhone
    Order By CreatedDate ASC
    ];
    return messages;
    }

    @AuraEnabled
    public static WAMessage__c getSingleMessage(String recordId, String customerPhone){
    return [SELECT Id, Name, MessageContent__c, MessageType__c, CustomerName__c, AgentName__c, Outgoing__c, CreatedDate
    FROM WAMessage__c
    WHERE Id =: recordId AND
    CustomerPhone__c =: customerPhone
    Order By CreatedDate ASC
    ];
    }

    @AuraEnabled
    public static WAMessage__c sendTextMessage(String messageContent, String toPhone){
    WAMessage__c message = WhatsAppUtils.sendTextMessage(messageContent, toPhone);
    return [SELECT Id, Name, MessageContent__c, MessageType__c, CustomerName__c, AgentName__c, Outgoing__c, CreatedDate
    FROM WAMessage__c
    WHERE Id =: message.Id
    Order By CreatedDate ASC
    ];
    }

    @AuraEnabled(cacheable=true)
    public static List<WAMessage__c> listAllMessageByCustomer(String customerPhone){
    List<WAMessage__c> messages = new List<WAMessage__c>();
    messages = [SELECT Id, Name, MessageContent__c, MessageType__c, CustomerName__c, AgentName__c, Outgoing__c, CreatedDate
    FROM WAMessage__c
    WHERE CustomerPhone__c =: customerPhone
    Order By CreatedDate ASC
    ];
    return messages;
    }
    }
    71 changes: 71 additions & 0 deletions WhatsAppMessage.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,71 @@
    public class WhatsAppMessage {

    public entry[] entry;
    public class entry {
    public String id;
    public changes[] changes;
    }
    public class changes {
    public value value;
    public String field;
    }
    public class value {
    public String messaging_product;
    public metadata metadata;
    public contacts[] contacts;
    public messages[] messages;
    }
    public class metadata {
    public String display_phone_number;
    public String phone_number_id;
    }
    public class contacts {
    public profile profile;
    public String wa_id;
    }
    public class profile {
    public String name;
    }
    public class messages {
    public context context;
    public String fromx;
    public String id;
    public String timestamp;
    public text text;
    public String typex;
    public reaction reaction;
    public image image;
    public image video;
    }
    public class context {
    public String fromx;
    public String id;
    }
    public class text {
    public String body;
    }
    public class reaction{
    public String emoji;
    public String message_id;
    }
    public class image{
    public String mime_type;
    public String id;
    public String sha256;
    public String caption;
    }

    /* Class for the Document Message */
    public class document{
    public String mime_type;
    public String filename;
    public String sha256;
    public String id;
    }

    /* Check if the user has clicked on any button */
    public class button {
    public String payload;
    public String text;
    }
    }
    233 changes: 233 additions & 0 deletions WhatsAppUtils.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,233 @@
    public class WhatsAppUtils {

    public static List<WAMessage__c> listAllMessageByCustomer(String customerPhone){
    List<WAMessage__c> messages = new List<WAMessage__c>();
    messages = [SELECT Id, Name, MessageContent__c, MessageType__c, Outgoing__c FROM WAMessage__c WHERE CustomerPhone__c =: customerPhone];
    return messages;
    }
    public static WAMessage__c sendTextMessage(String messageContent, String toPhone){

    HttpRequest httpReq = new HttpRequest();
    httpReq.setEndpoint('https://graph.facebook.com/v13.0/YOUR_ACCOUNT_ID/messages');
    httpReq.setMethod('POST');
    httpReq.setHeader('Content-Type', 'application/json');
    httpReq.setHeader('Authorization', 'Bearer '+System.Label.WHATSAPPACCESSTOKEN);

    String messageBody = '{'+
    ' "messaging_product": "whatsapp",'+
    ' "recipient_type": "individual",'+
    ' "to": "'+toPhone+'",'+
    ' "type": "text",'+
    ' "text": {'+
    ' "preview_url": false,'+
    ' "body": "'+messageContent+'"'+
    ' }'+
    '}';

    httpReq.setBody(messageBody);

    Http http = new Http();
    WAMessage__c salesforceMessage = new WAMessage__c();
    try{
    HttpResponse response = http.send(httpReq);
    if( response.getStatusCode() == 200 ){
    // Parse & Create Message Record
    System.debug('Successful!');
    WhatsAppUtils responseFromWA = (WhatsAppUtils) JSON.deserialize( response.getBody() , WhatsAppUtils.class);

    salesforceMessage.MessageContent__c = messageContent;
    salesforceMessage.CustomerPhone__c = toPhone;
    salesforceMessage.MessageID__c = responseFromWA.messages.get(0).id;
    salesforceMessage.MessageType__c = 'text';
    salesforceMessage.Outgoing__c = True;
    salesforceMessage.AgentName__c = UserInfo.getFirstName()+' '+ UserInfo.getLastName();
    upsert salesforceMessage MessageID__c;
    }
    }catch(System.CalloutException ex){
    System.debug(' CalloutException Executed '+ ex.getStackTraceString() );
    System.debug(' CalloutException Executed '+ ex.getMessage() );
    }catch(System.Exception ex){
    System.debug(' System.Exception Executed '+ ex.getStackTraceString() );
    }
    return salesforceMessage;
    }


    public static WAMessage__c sendFlightBookingConfirmationMessage(String toPhone, String name, String source, String destination){
    String body = '{'+
    ' "messaging_product": "whatsapp",'+
    ' "recipient_type": "individual",'+
    ' "to": "'+toPhone+'",'+
    ' "type": "template",'+
    ' "template": {'+
    ' "name": "flight_booking_confirm_template",'+
    ' "language": {'+
    ' "code": "en"'+
    ' },'+
    ' "components": ['+
    ' {'+
    ' "type": "header",'+
    ' "parameters": ['+
    ' {'+
    ' "type": "image",'+
    ' "image": {'+
    ' "link": "https://bit.ly/3AWkh2p"'+
    ' }'+
    ' }'+
    ' ]'+
    ' },'+
    ' {'+
    ' "type": "body",'+
    ' "parameters": ['+
    ' {'+
    ' "type": "text",'+
    ' "text": "'+Name+'"'+
    ' },'+
    ' {'+
    ' "type": "text",'+
    ' "text": "'+source+'"'+
    ' },'+
    ' {'+
    ' "type": "text",'+
    ' "text": "'+destination+'"'+
    ' },'+
    ' {'+
    ' "type": "date_time",'+
    ' "date_time" : {'+
    ' "fallback_value": "October 25, 2023 22:34 PM",'+
    ' "day_of_week": 6,'+
    ' "day_of_month": 25,'+
    ' "year": 2023,'+
    ' "month": 10,'+
    ' "hour": 12,'+
    ' "minute": 34'+
    ' }'+
    ' },'+
    ' {'+
    ' "type": "text",'+
    ' "text": "999-999-9999"'+
    ' }'+
    ' ]'+
    ' },'+
    ' {'+
    ' "type": "button",'+
    ' "sub_type": "quick_reply",'+
    ' "index": "0",'+
    ' "parameters": ['+
    ' {'+
    ' "type": "payload",'+
    ' "payload": "Contact to Support"'+
    ' }'+
    ' ]'+
    ' },'+
    ' {'+
    ' "type": "button",'+
    ' "sub_type": "quick_reply",'+
    ' "index": "1",'+
    ' "parameters": ['+
    ' {'+
    ' "type": "payload",'+
    ' "payload": "Check PNR Status"'+
    ' }'+
    ' ]'+
    ' }'+
    ' ]'+
    ' }'+
    '}';

    HttpRequest httpReq = new HttpRequest();
    httpReq.setEndpoint('https://graph.facebook.com/v13.0/YOUR_ACCOUNT_ID/messages');
    httpReq.setMethod('POST');
    httpReq.setHeader('Content-Type', 'application/json');
    httpReq.setHeader('Authorization', 'Bearer '+System.Label.WHATSAPPACCESSTOKEN);

    httpReq.setBody(body);

    Http http = new Http();
    WAMessage__c salesforceMessage = new WAMessage__c();
    try{
    HttpResponse response = http.send(httpReq);
    if( response.getStatusCode() == 200 ){
    // Parse & Create Message Record
    System.debug('Successful!');
    WhatsAppUtils responseFromWA = (WhatsAppUtils) JSON.deserialize( response.getBody() , WhatsAppUtils.class);

    salesforceMessage.MessageContent__c = body;
    salesforceMessage.CustomerPhone__c = toPhone;
    salesforceMessage.MessageID__c = responseFromWA.messages.get(0).id;
    salesforceMessage.MessageType__c = 'template';
    salesforceMessage.Outgoing__c = True;
    salesforceMessage.AgentName__c = UserInfo.getFirstName()+' '+ UserInfo.getLastName();
    upsert salesforceMessage MessageID__c;
    }
    }catch(System.CalloutException ex){
    System.debug(' CalloutException Executed '+ ex.getStackTraceString() );
    System.debug(' CalloutException Executed '+ ex.getMessage() );
    }catch(System.Exception ex){
    System.debug(' System.Exception Executed '+ ex.getStackTraceString() );
    }
    return salesforceMessage;
    }

    public static WAMessage__c sendMediaMessages(String toPhone, String url){
    HttpRequest httpReq = new HttpRequest();
    httpReq.setEndpoint('https://graph.facebook.com/v13.0/YOUR_ACCOUNT_ID/messages');
    httpReq.setMethod('POST');
    httpReq.setHeader('Content-Type', 'application/json');
    httpReq.setHeader('Authorization', 'Bearer '+System.Label.WHATSAPPACCESSTOKEN);

    if(String.isBlank(url)){
    url = '';
    }

    String body = '{'+
    ' "messaging_product": "whatsapp",'+
    ' "recipient_type": "individual",'+
    ' "to": "'+toPhone+'",'+
    ' "type": "document",'+
    ' "document": {'+
    ' "link": "'+url+'",'+
    ' "caption" : "Field Service Lightning Topics.pdf",'+
    ' "filename" : "Field Service Lightning Topics.pdf"'+
    ' }'+
    '}';

    httpReq.setBody(body);

    Http http = new Http();
    WAMessage__c salesforceMessage = new WAMessage__c();
    try{
    HttpResponse response = http.send(httpReq);
    if( response.getStatusCode() == 200 ){
    // Parse & Create Message Record
    System.debug('Successful!');
    WhatsAppUtils responseFromWA = (WhatsAppUtils) JSON.deserialize( response.getBody() , WhatsAppUtils.class);

    salesforceMessage.MessageContent__c = body;
    salesforceMessage.CustomerPhone__c = toPhone;
    salesforceMessage.MessageID__c = responseFromWA.messages.get(0).id;
    salesforceMessage.MessageType__c = 'media';
    salesforceMessage.Outgoing__c = True;
    salesforceMessage.AgentName__c = UserInfo.getFirstName()+' '+ UserInfo.getLastName();
    upsert salesforceMessage MessageID__c;
    }
    }catch(System.CalloutException ex){
    System.debug(' CalloutException Executed '+ ex.getStackTraceString() );
    System.debug(' CalloutException Executed '+ ex.getMessage() );
    }catch(System.Exception ex){
    System.debug(' System.Exception Executed '+ ex.getStackTraceString() );
    }
    return salesforceMessage;
    }

    public String messaging_product;
    public contacts[] contacts;
    public messages[] messages;
    public class contacts {
    public String input;
    public String wa_id;
    }
    public class messages {
    public String id;
    }
    }
    117 changes: 117 additions & 0 deletions WhatsAppWebhook.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,117 @@
    @RestResource(urlMapping='/whatsapp/webhooks/v1/*')
    global without sharing class WhatsAppWebhook {

    private static Final String SIGNATURE_VALID_MESSAGE = 'Signature Verified';
    private static Final String SIGNATURE_NOT_VALID_MESSAGE = 'Signature could not be verified';

    @HttpGet // GET
    global static void doGet() {
    RestResponse response = RestContext.response;
    RestRequest request = RestContext.request;
    if(request.params.get('hub.verify_token') == 'WHATSAPPTOKEN'){
    response.responseBody = Blob.valueOf( request.params.get('hub.challenge') );
    }
    }

    @HttpPost // POST
    global static void doPost() {

    RestResponse response = RestContext.response;
    response.addHeader('Content-type','application/json');
    String responseString = RestContext.request.requestBody.toString();
    Map<String, String> headers = RestContext.request.headers;
    String responseValid = validateWhatsAppSignature(RestContext.request, responseString);

    if(responseValid == SIGNATURE_VALID_MESSAGE){
    System.debug(System.LoggingLevel.DEBUG, ' Headers Response From WhatsApp \n '+ JSON.serialize(headers) );
    System.debug(System.LoggingLevel.DEBUG, ' Response From WhatsApp \n '+ responseString);
    String finalResponseString = responseString.replace('type', 'typex');
    WhatsAppMessage parentMessage = (WhatsAppMessage)JSON.deserialize( finalResponseString, WhatsAppMessage.class);
    List<WhatsAppMessage.entry> messageEntries = parentMessage.entry;
    if(messageEntries != null && messageEntries.size() > 0){
    WhatsAppMessage.entry entryMessage = messageEntries.get(0);
    List<WhatsAppMessage.changes> changeMessages = entryMessage.changes;
    if(changeMessages != null && changeMessages.size() > 0){
    WhatsAppMessage.changes changeMessage = changeMessages.get(0);
    List<WhatsAppMessage.contacts> contactList = changeMessage.value.contacts;
    List<WhatsAppMessage.messages> messageList = changeMessage.value.messages;
    WhatsAppMessage.metadata metadata = changeMessage.value.metadata;
    /* Create record into Salesforce */
    WAMessage__c salesforceMessage = new WAMessage__c();
    salesforceMessage.BusinessPhoneNumber__c = metadata != null ? metadata.display_phone_number : null;

    if(contactList != null && contactList.size() > 0){
    WhatsAppMessage.contacts contact = contactList.get(0);
    salesforceMessage.CustomerPhone__c = contact.wa_id;
    salesforceMessage.CustomerName__c = contact.profile.name;
    }

    if(messageList != null && messageList.size() > 0){
    /* Simple Message */
    WhatsAppMessage.messages message = messageList.get(0);
    salesforceMessage.MessageID__c = message.id;
    salesforceMessage.MessageType__c = message.typex;
    salesforceMessage.MessageSentTime__c = System.now();
    salesforceMessage.MessageContent__c = message.text != null? message.text.body : null;

    /* If message is reaction */
    salesforceMessage.Reaction__c = message.reaction != null ? message.reaction.emoji : null;
    salesforceMessage.ParentMessageID__c = message.reaction != null ? message.reaction.message_id : null;

    /* If message is Image */
    salesforceMessage.ImageID__c = message.image != null ? message.image.id : null;
    salesforceMessage.ImageType__c = message.image != null ? message.image.mime_type : null;
    salesforceMessage.ImageSHA256__c = message.image != null ? message.image.sha256 : null;

    /* If message is Video */
    salesforceMessage.VideoId__c = message.video != null ? message.video.id : null;
    salesforceMessage.VideoType__c = message.video != null ? message.video.mime_type : null;
    salesforceMessage.VideoSHA256__c = message.video != null ? message.video.sha256 : null;

    /* If message is Document */

    /* If the message is reply to another message */
    salesforceMessage.ParentMessageID__c = message.context != null ? message.context.id : null;

    upsert salesforceMessage MessageID__c;

    /* Publish the Platform Event to be listened by LWC */
    WA_Message_Event__e platformEvent = new WA_Message_Event__e();
    platformEvent.Message_Id__c = salesforceMessage.Id;
    platformEvent.Customer_Phone__c = salesforceMessage.CustomerPhone__c;
    Eventbus.publish( platformEvent );

    }

    }
    }
    }else{
    response.responseBody = Blob.valueOf('{success:false, event:"Unknown","message:"'+responseValid+'"}');
    response.statusCode = 401;
    return;
    }

    response.statusCode = 200;
    response.responseBody = Blob.valueOf('{success:true, event:"success"}');
    }

    private static String validateWhatsAppSignature(RestRequest request, String responseString) {
    // Validate Stripe signature Start
    Map<String, String> headers = request.headers;

    String whatsAppSignature = headers.get('X-Hub-Signature-256');

    String whatsAppPayload = RestContext.request.requestBody.toString();

    // Verify the signature using 'hmacSHA256'. I have the Webhook key stored in a Custom Label
    String whatsAppSecret = System.Label.WHATSAPPSECRET; // Facebook Application Secret Key
    Blob signedPayload = Crypto.generateMac('hmacSHA256', Blob.valueOf(whatsAppPayload), Blob.valueOf( whatsAppSecret ));

    String encodedPayload = 'sha256='+EncodingUtil.convertToHex(signedPayload);
    // Return status code based on whether signed payload matches or not

    String response = (encodedPayload == whatsAppSignature)? SIGNATURE_VALID_MESSAGE : SIGNATURE_NOT_VALID_MESSAGE;
    return response;
    // Validate Stripe signature End
    }
    }