requests.js

/**
 * GET helper, must be called inside the get function of your code.
 * Used once at the first webhook setup.
 * 
 * @param {Object} params The GET request parameters in object format
 * @param {String} verify_token The verification token
 * @returns {String} The challenge string, it must be the http response body
 * @throws {Number} 500 if verify_token is not specified
 * @throws {Number} 400 if the request is missing data
 * @throws {Number} 403 if the verification tokens don't match
 */
function get(params, verify_token) {
    // verify_token is required
    if (!verify_token) throw 500;

    // Parse params from the webhook verification request
    let mode = params["hub.mode"];
    let token = params["hub.verify_token"];
    let challenge = params["hub.challenge"];

    // Check if a token and mode were sent
    if (mode && token) {
        // Check the mode and token sent are correct
        if (mode === "subscribe" && token === verify_token) {
            // Respond with 200 OK and challenge token from the request
            return challenge;
        } else {
            // Responds with "403 Forbidden" if verify tokens do not match
            throw 403;
        }
    }

    // Responds with "400 Bad Request" if it's missing data
    throw 400;
}

/**
 * POST helper callback for messages
 *
 * @callback onMessage
 * @param {String} phoneID The bot's phoneID
 * @param {String} phone The user's phone number
 * @param {Object} message The messages object
 * @param {String} name The username
 * @param {Object} raw The raw data from the API
 */

/**
 * POST helper callback for statuses
 *
 * @callback onStatus
 * @param {String} phoneID The bot's phoneID
 * @param {String} phone The user's phone number
 * @param {String} status The message status
 * @param {String} messageID The message ID
 * @param {Object} conversation The conversation object
 * @param {Object} pricing The pricing object
 * @param {Object} raw The raw data from the API
 */

/**
 * POST helper, must be called inside the post function of your code.
 * When setting up the webhook, only subscribe to messages. Other subscritions support might be added later.
 * 
 * @param {Object} data The post data sent by Whatsapp, already parsed to object
 * @param {onMessage} onMessage The function to be called if the post request is a valid message
 * @param {onStatus} [onStatus] The function to be called if the post request is a valid status update
 * @returns {Number} 200, it's the expected http/s response code
 * @throws {Number} 400 if the POST request isn't valid
 */
function post(data, onMessage, onStatus) {
    // Validate the webhook
    if (data.object) {
        const value = data.entry[0].changes[0].value;
        const phoneID = value.metadata.phone_number_id;

        // Check if the message is a message or a status update
        if (value.messages) {
            const contact = value.contacts[0];

            const phone = contact.wa_id;
            const name = contact.profile.name;

            const message = value.messages[0];

            onMessage(phoneID, phone, message, name, data);
        } else if (value.statuses && onStatus) {
            const statuses = value.statuses[0];
            
            const phone = statuses.recipient_id;
            const status = statuses.status;
            const messageID = statuses.id;
            const conversation = statuses.conversation;
            const pricing = statuses.pricing;
            
            onStatus(phoneID, phone, status, messageID, conversation, pricing, data);
        }

        return 200;
    } else {
        // Throw "400 Bad Request" if data is not a valid WhatsApp API request
        throw 400;
    }
}

module.exports = { get, post };