WhatsApp Client

The IWhatsApp interface is for working with a WhatsApp Connector to a companies' WhatsApp Business Account.

To create an IWhatsApp instance, the static Create() function needs to be called. Two existing ISocketProvider (TCP and TLS) as well as an IDns instance must be passed to Create(). These instances must not be deleted before releasing the IWhatsApp instance!

File information

Filecommon/interface/whatsapp.h

Classes IWhatsAppClient
UWhatsAppClient
IWhatsAppOnboarding
UWhatsAppOnboarding

Classes

IWhatsAppClient


    class IWhatsAppClient {
    public:
    static IWhatsAppClient * Create(class IIoMux * const iomux,
    class UWhatsAppClient * const user,
    class ISocketProvider * const tcpSocketProvider,
    class ISocketProvider * const tlsSocketProvider,
    class IInstanceLog * const log,
    class IDns * const dns,
    class ISocketContext const socketContext = nullptr
    );

    virtual ~IWhatsAppClient() {}
    virtual void Close() = 0;
    virtual void SetConfig(const char * token, const char * secret) = 0;
    virtual void SetWebhookToken(const char* webhookToken) = 0;
    virtual void SendMessage(UWhatsAppClient * context, json_io value, word base, const char * tel, const char * type, const char * channel, const char * callback_info=0, const char * refersToID = 0) = 0;
    virtual void Subscribe(UWhatsAppClient * subscriber, const char * tel = 0) = 0;
    virtual void Unsubscribe(UWhatsAppClient * unsubscriber, const char * tel = 0) = 0;
    virtual void SetChannels(const char* channels) = 0;
    virtual char* GetChannelsConfig() = 0;
    virtual const char* GetVersion() = 0;
    };

Overview

This is the interface to establish a WhatsApp for Business connection. The interface is quite simple and straight forward to use.

Public functions

Create (static function)
This static function creates the IWhatsAppClient Instance. The returned instance must be released if no longer needed by using the C++ delete operator.

Parameters

class IIoMux * const iomuxThe IIoMux instance the IWhatsAppClient instance will be registered to.
class UWhatsAppClient * const userThe UWhatsAppClient instance that will receive the callbacks of IWhatsAppClient.
class IWebserverPlugin * const webserverinstance that can create a Webserver Plugin.
class ISocketProvider * const tcpSocketProviderA ISocketProvider instance that can create a TCP ISocket.
class ISocketProvider * const tlsSocketProviderA ISocketProvider instance that can create a TLS ISocket.
class IInstanceLog * const logThe IInstanceLog instance used for logging purposes.
class IDns * const dnsThe IDns instance used to resolve the server name if needed.
class ISocketContext * const socketContext dnsThe ISocketContext Socket context if needed

Return value

The IWhatsAppClient Instance created. It must be freed by the C++ operator delete, if no longer be used.

Remarks

Note that the two ISocketProvider instances as well as the IDns instance must not be freed before the IWhatsAppClient instance had been deleted.
Close
Closes the WhatsAppClient. Will usually be called from a corresponding app.

Callbacks

Once the close is completed, UWhatsAppClient::WhatsAppClientCloseComplete() will be called. The WhatsAppClient-Object can thus be deleted then.
SetConfig
Sets certain configurations that are necessary to send or receive messages to/from WhatsApp. The App-Secret can be found in the Meta-Appdashboard. It is necessary for accepting incoming messages.

Parameters

const char * tokenA token used for authentication with WhatsApp
const char * secretThe App-Secret from Meta
SetWebhookToken
Sets a token that will be used for validation at registering webhooks (like receiving incoming messages) from WhatsApp at onboarding or at changing webhooks.

Parameters

const char * webhookTokenA token used for validating webhook registration
SendMessage
Sends the given data to the (private) WhatsApp Messenger Account identified by the phone number. A message to a private Account will only be delivered if a message from that private Account had been received within 24 hours before. Template-Messages are an exception an can be sent without preceding initiation from the private Account. If the data could not be send right now, it will be cached and sent later. The context will be informed if the data had been finally send or any errors that occur instead.

Parameters

UWhatsAppClient * contextThe user to receive callbacks for the given message
json_io valuejson_io of the message
word baseThe jsons base
const char * telThe phone number of the recipients Whatsapp-Account
const char * typeType of the message (text, reaction, location, media, contact)
const char *channelThe channel used for sending aka whatsapp phone_id
const char * callback_infoOptional: additional information for the callback as src from frontend sendSrc
const char *refersToIDOptional: Whatsapp-Message-ID of previous message that is referred to (if any)

Callbacks

After the data had been send, UWhatsAppClient::WhatsAppClientSendMessageResult() will be called.
Subscribe
Subscribing a user for receiving incoming WhatsApp-Messages for a given phone number. If no phone number is given, the user will receive all incoming messages.

Parameters

UWhatsAppClient * subscriberThe user to receive incoming messages
const char * telThe phone number to subscribe. If 0 all incoming messages are received
Unsubscribe
Unsubscribes a user for receiving WhatsApp-Messages for a given phone number. If no phone number is given, all subscriptions will be deleted and hence no messages will be received anymore.

Parameters

UWhatsAppClient * unsubscriberThe user to unsubscribe
const char * telThe phone number to unsubscribe. If 0 all subscriptions are cancelled
SetChannels
Updates the available channels for the connector.

Parameters

const char * channelsThe available channels for the client
GetChannelsConfig()
Retrieves the available channels for the connector from its configuration.
GetVersion()
Retrieves the version of the WhatsApp cloud API implemented.

UWhatsAppClient


    class UWhatsAppClient {
    public:
    virtual ~UWhatsAppClient() {};
    virtual void WhatsAppClientCloseComplete(IWhatsAppClient * const whatsappClient) = 0;
    virtual void WhatsAppClientSendMessageResult(IWhatsAppClient * const whatsappClient, whatsapp_error_t error, const char * callback_info = 0, const char * content = 0) = 0;
    virtual void WhatsAppClientRecvMessage(IWhatsAppClient* const whatsappClient, const char* msg, const char* tel, const char * channel, const char * type, const char * id, const char * refersToID = 0) = 0;
    virtual void WhatsAppClientRecvMedia(IWhatsAppClient* const whatsAppClient, const char* sender, const char* channel, const char* wamid, const char* mediaid, const char* mimeType) = 0;
    virtual void WhatsAppClientForwardMessage(IWhatsAppClient* const whatsappClient, const char* msg, const char* tel, const char* channel, const char* type, const char* id, const char * refersToID = 0) = 0;
    };

Overview

The UWhatsAppClient class is used to receive callbacks from an IWhatsAppClient instance. An application must subclass UWhatsAppClient, implement the functions that must be implemented and pass that class as user to IWhatsAppClient::Create(). The instance of that subclass must not be freed before the IWhatsAppClient instance assigned to. One UWhatsAppClient instance can be assigned to multiple IWhatsAppClient instances, because the calling IWhatsAppClient will be passed as parameter to the callback functions.

Public functions

WhatsAppClientCloseComplete
Will be called after calling IWhatsAppClient::Close(). After receiving that callback, the IWhatsAppClient-Object can be deleted.

Parameters

class IWhatsAppClient * const whatsappClientThe calling IWhatsAppClient instance
WhatsAppClientSendMessageResult
Will be called after calling IWhatsAppClient::SendMessage(). After receiving that callback, the IWhatsAppClient instance can be used to send data and receive reactions.

Parameters

class IWhatsAppClient * const whatsappClientThe calling IWhatsAppClient instance
whatsapp_error_t errorThe error status after sending.
const char * callback_infoOpitional: additional information for the callback as src from frontend sendSrc
const char * contentOptional: additional content as Whatsapp-message-id
WhatsAppClientRecvMessage
Passes an incoming message from whatsapp to a user who has subscribed for receiving Messages for the phone number (or all Messages).

Parameters

class IWhatsAppClient * const whatsappClientThe calling IWhatsAppClient instance
const char * msgThe received message
const char * telThe sending telephone number
const char * channelThe channel used for sending aka whatsapp phone_id
const char * typeThe type of the received message (may be "text|image|status|reaction|location|contact")
const char * idThe Whatsapp-Message-ID of the message (necessary to refer to the message later)
const char *refersToIDWhatsapp-Message-ID of previous message that is referred to (if any)
virtual void WhatsAppClientRecvMedia(IWhatsAppClient* const whatsAppClient, const char* sender, const char* channel, const char* wamid, const char* mediaid, const char* mimeType) = 0;
WhatsAppClientRecvMedia
Informs the using app about incoming media. For the app to receive the media, a request to fetch it via GET-Request to /client/getMedia with Parameter id=mediaid is required.

Parameters

class IWhatsAppClient * const whatsappClientThe calling IWhatsAppClient instance
const char * senderThe sending telephone number
const char * channelThe channel used for sending aka whatsapp phone_id
const char * wamidThe Whatsapp-Message-ID of the message (necessary to refer to the message later)
const char * mediaidThe id of the media (necessary to retrieve the actual data)
const char * mimeTypeThe mime-type of the media
WhatsAppClientForwardMessage
Forwards a message from one app that subscribed for a channel to another app that subscribed to the same channel to avoid multiple answers to the same original post from a whatsapp user.

Parameters

class IWhatsAppClient * const whatsappClientThe calling IWhatsAppClient instance
const char * msgThe forwarded message
const char * telThe target telephone number from the forwarded message
const char * channelThe channel that originally sent the message
const char * typeThe type of the received message (may be "text|image|status|reaction|location|contact")
const char * idThe Whatsapp-Message-ID of the original message (necessary to refer to the message later)
const char *refersToIDWhatsapp-Message-ID of previous message that is referred to (if any)

IWhatsAppOnboarding


    class IWhatsAppOnboarding {
    public:
    static IWhatsAppClient * Create(class IIoMux * const iomux,
    class UWhatsAppOnboarding * const user,
    class ISocketProvider * const tcpSocketProvider,
    class ISocketProvider * const tlsSocketProvider,
    class IInstanceLog * const log,
    class IDns * const dns,
    class ISocketContext const socketContext = nullptr
    );

    virtual ~IWhatsAppOnboarding() {}
    virtual void Close() = 0;
    virtual void Onboard(UWhatsAppOnbaording * context, const char* src, const char* vrsion, const char* code, const char* webhookToken, const char* wabaID, const char* callbackUri, const char* phoneID, const char* phonePin) = 0;
    };

Overview

This is the interface to start all necessary actions to onboard a new customer, which means retrieving a token, registering all necessary webhooks and registering the main phone number. For onboarding, the WhatsAppClient needs be running too.

Public functions

Create (static function)
This static function creates the IWhatsAppOnboarding Instance. The returned instance must be released if no longer needed by using the C++ delete operator.

Parameters

class IIoMux * const iomuxThe IIoMux instance the IWhatsAppClient instance will be registered to.
class UWhatsAppClient * const userThe UWhatsAppClient instance that will receive the callbacks of IWhatsAppClient.
class IWebserverPlugin * const webserverinstance that can create a Webserver Plugin.
class ISocketProvider * const tcpSocketProviderA ISocketProvider instance that can create a TCP ISocket.
class ISocketProvider * const tlsSocketProviderA ISocketProvider instance that can create a TLS ISocket.
class IInstanceLog * const logThe IInstanceLog instance used for logging purposes.
class IDns * const dnsThe IDns instance used to resolve the server name if needed.
class ISocketContext * const socketContext dnsThe ISocketContext Socket context if needed

Return value

The IWhatsAppOnboarding Instance created. It must be freed by the C++ operator delete, if no longer be used.

Remarks

Note that the two ISocketProvider instances as well as the IDns instance must not be freed before the IWhatsAppClient instance had been deleted.
Close
Closes the WhatsAppOnboarding. Will usually be called from a corresponding app once the onboarding is complete.

Callbacks

Once the close is completed, UWhatsAppOnboarding::WhatsAppOnboardingCloseComplete() will be called. The WhatsAppOnboarding-Object can thus be deleted then.

UWhatsAppOnboarding


    class UWhatsAppOnboarding {
    public:

    virtual ~UWhatsAppOnboarding() {}
    virtual void WhatsAppOnboardingCloseComplete(IWhatsAppOnboarding * const onboarding) = 0;
    virtual void WhatsAppOnboardingOnboardResult(IWhatsAppOnbaording * const onboarding, const char* callback_info, onboardingStatus status, const char* token = 0) = 0;
    };

Overview

This is the interface to start all necessary actions to onboard a new customer, which means retrieving a token, registering all necessary webhooks and registering the main phone number. For onboarding, the WhatsAppClient needs be running too.

Public functions

WhatsAppOnboardingCloseComplete
Callback from calling IWhatsAppOnboarding::Close(), signaling the Object stopped all current processes and is ready for deletion.
WhatsAppOnboardingOnboardResult
Callback from calling IWhatsAppOnboarding::Onboard(), providing the result of the onboarding.

Parameters

class IWhatsAppOnboarding * const onboardingThe onboarding instance that executed the onboarding.
const char * callback_infoInformation containing the src from the call, allowing to transmit the result back to frontend
onboardingStatus statusThe status of the onboarding. If completely successfull, the status is FINISHED. Otherwise it shows the last stage of the onboarding that was executed and failed.
const char* tokenIn case of success with at least the first stage (retrieving a token), the token is returned. The token is also saved to config and will be used for further authorization agains WhatsApp.

Data types

whatsapp_error_t


    typedef enum {
    WHATSAPP_ERR_OK = 0,
    WHATSAPP_ERR_MISSING_TOKEN,
    WHATSAPP_ERR_MISSING_VERSION,
    WHATSAPP_ERR_NOT_FOUND,
    WHATSAPP_ERR_BAD_REQUEST,
    WHATSAPP_ERR_AUTHENTICATION_FAILED,
    WHATSAPP_ERR_OTHER_HTTP,
    WHATSAPP_ERR_CLOSING
    } whatsapp_error_t;

This enum defines the possible outcomes for sending a message via the connector. One of them will be returned at UWhatsAppClient::WhatsAppClientSendMessageResult.

onboardingStatus


    typedef enum {
    UNSTARTED,
    FETCH_TOKEN,
    REGISTER_WEBHOOKS,
    REGISTER_PHONE,
    FINISHED
    } onboardingStatus;

This enum defines the possible outcomes for an onboarding. Stages are passed from Top to Bottom, signaling the failing stage if onboarding could not completely finished, allowing further follow-up for only the unfinished stages.

API

Overview

Below is the description of the API messages that are sent or accepted by the whatsapp-client if used with the class whatsapp.cpp. Note that any optional value is marked by =0.

Subscribing for incoming Messages

This message can be sent in order to subscribe for incoming messages from a specific channel (whatsapp phone_number_id) or all registered channels (if no specific channel is given).

{
    "mt": "Subscribe",
    "api": "com.innovaphone.whatsapp",
    "channel": string
}
    

Unsubscribing

This message can be sent in order to unsubscribe for incoming messages from a specific channel (whatsapp phone_number_id) or all subscribed channels (if no specific channel is given).

{
    "mt": "Unsubscribe",
    "api": "com.innovaphone.whatsapp",
    "channel": string
}
    

Get List of Available Channels

This message can be sent in order to retrieve a list of available channels for the business account (as defined in config). Call before subscribe for selection.

{
    "mt": "GetChannels",
    "api": "com.innovaphone.whatsapp"
}
    

Sending to WhatsApp

This message can be sent in order to sent a message to a customer via WhatsApp. As there exist many different types of message that can be sent, there is a basic part of the message and additional parts. remoteNum defines the customers phone-number, channel the phone-id that will be used as sender-number.
Please note that currently only text is supported!

{
    "mt": "SendMessage",
    "api": "com.innovaphone.whatsapp",
    "remoteNum": string,
    "channel": string,
    "type": string,
    "value": JsonObject
}

The JsonObject "value" can be one of the following and aligns with the type of the message.

text
reaction
location
media
template
contact

type = "text"

{
    "text": string
}

type = "reaction"

{
    "reaction": string
}

type = "location"

{
    "lat": string,
    "lon": string,
    "name": string = 0,
    "address": string = 0
}

type = "media"

{
    "path": string,
    "mediatype": string,
    "caption": string,
    "filename": string
}

Mediatype can be "audio", "document", "image", "sticker", or "video".

type = "template"

{
    "name": string,
    "language": string,
    "components": [{"text": string}],
}

Components are optional and represent text to fill in specific spaces in the template if any.

type = "contact"

{
    "name":         {
                    "fullName": string,
                    "firstName": string = 0,
                    "lastName": string = 0,
                    "middleName": string = 0,
                    "suffix": string = 0,
                    "prefix": string = 0
                    },
    "addresses":    [{
                    "street": string = 0,
                    "city": string = 0,
                    "state": string = 0,
                    "zip": string = 0,
                    "country": string = 0,
                    "countryCode": string = 0,
                    "type": string = 0
                    }] = 0,
    "birthday": string = 0,
    "emails":       [{
                    "email": string = 0,
                    "type": string = 0
                    }] = 0,
    "organisation": {
                    "company": string = 0,
                    "department": string = 0,
                    "title": string = 0
                    } = 0,
    "phones":       [{
                    "phone": string = 0,
                    "type": string = 0,
                    "waUID": string = 0
                    }] = 0
}

For addresses and emails type may be "WORK" or "HOME". Accepted types for phones are "CELL", "MAIN", "IPHONE", "HOME", "WORK". Birthday is to be given in format: "YYYY-MM-DD". waUID means Whatsapp User-ID. Beside the fullName, at least one more field of name must be filled (as decided by whatsapp)

Possible Results from Sending to WhatsApp

{
    "mt": "SendMessageResult",
    "api": "com.innovaphone.whatsapp",
    "status": string,
    "wamid": string = 0,
    "error": boolean = 0,
    "errorText": string = 0
}

Status will be "Transmitted", "Sent" or any of whatsapp_error_t.

Incoming Messages from Connector

If incoming messages are received at the connector, after processing them the connector is expected to send out one of the following messages.

{
    "mt": "RecvMessage",
    "api": "com.innovaphone.whatsapp",
    "remoteNum": string,
    "channel": string,
    "wamid": string,
    "type": string,
    "value": JsonObject
}

"value" can take the same values as in SendMessage.

{
    "mt": "ForwardMessage",
    "api": "com.innovaphone.whatsapp",
    "remoteNum": string,
    "channel": string,
    "wamid": string,
    "type": string,
    "value": JsonObject
}

"value" can take the same values as in SendMessage.

Code Example

IWhatsAppClient


    app::app(class IIoMux * iomux,
    ISocketProvider * tcpSocketProvider,
    ISocketProvider * tlsSocketProvider,
    IDns * dns,
    IInstanceLog * log)
    : iomux(iomux)
    {
        this->client = IWhatsAppClient::Create(iomux,
                                                this,
                                                webserverPlugin,
                                                tcpSocketProvider,
                                                tlsSocketProvider,
                                                this,
                                                dns);
    isTerminating = false;
    }

    void WhatsApp::Stop(){
    if (!isTerminating) {
        isTerminating = true;
        if (client != nullptr) client->Close();
        TryStop();
        }
    }

    void WhatsApp::TryStop(){
        if (isTerminating && client == nullptr) appService->AppStopped(this);
    }



    void app::WhatsAppClientCloseComplete(IWhatsAppClient* const whatsappClient){
        delete client;
        client = nullptr;
        TryStop();
    }

    void app::WhatsAppClientSendMessageResult(IWhatsAppClient* const whatsappClient, whatsapp_error_t error){
        //can ignore the result or act according to it
    }