Manspof
Manspof

Reputation: 357

Whatsapp cloudapi webhook flow

I want to build an order system WhatsApp bot when the user sends a message to the bot and gets a list of items to order then each question the user answers he gets a new answer to the prev question he has answered. I read the documentation of cloud api and configured a webhook to get any message from the user.

const token = process.env.WHATSAPP_TOKEN;

// Imports dependencies and set up http server
const request = require("request"),
  express = require("express"),
  body_parser = require("body-parser"),
  axios = require("axios").default,
  app = express().use(body_parser.json()); // creates express http server

// Sets server port and logs message on success
app.listen(process.env.PORT || 1337, () => console.log("webhook is listening"));

// Accepts POST requests at /webhook endpoint
app.post("/webhook", (req, res) => {
  // Parse the request body from the POST
  let body = req.body;

  // Check the Incoming webhook message
  console.log(JSON.stringify(req.body, null, 2));

  // info on WhatsApp text message payload: https://developers.facebook.com/docs/whatsapp/cloud-api/webhooks/payload-examples#text-messages
  if (req.body.object) {
    if (
      req.body.entry &&
      req.body.entry[0].changes &&
      req.body.entry[0].changes[0] &&
      req.body.entry[0].changes[0].value.messages &&
      req.body.entry[0].changes[0].value.messages[0]
    ) {
      const entry = req.body.entry[0]
      const change = entry.changes[0]
      const { messages } = change.value
      // console.log('change value is',change.value)
      let phone_number_id =
        req.body.entry[0].changes[0].value.metadata.phone_number_id;
      let from = req.body.entry[0].changes[0].value.messages[0].from; // extract the phone number from the webhook payload
      let msg_body = req.body.entry[0].changes[0].value.messages[0].text.body; // extract the message text from the webhook payload
       // console.log({msg_body,from,phone_number_id,entry,field,messages})
      axios({
        method: "POST", // Required, HTTP method, a string, e.g. POST, GET
        url:
          "https://graph.facebook.com/v12.0/" +
          phone_number_id +
          "/messages?access_token=" +
          token,
        data: {
          messaging_product: "whatsapp",
          to: from,
          text: { body: "Ack: " + msg_body },
        },
        headers: { "Content-Type": "application/json" },
      });
    }
    res.sendStatus(200);
  } else {
    // Return a '404 Not Found' if event is not from a WhatsApp API
    res.sendStatus(404);
  }
});

// Accepts GET requests at the /webhook endpoint. You need this URL to setup webhook initially.
// info on verification request payload: https://developers.facebook.com/docs/graph-api/webhooks/getting-started#verification-requests 
app.get("/webhook", (req, res) => {
  /**
   * UPDATE YOUR VERIFY TOKEN
   *This will be the Verify Token value when you set up webhook
  **/
  const verify_token = process.env.VERIFY_TOKEN;

  // Parse params from the webhook verification request
  let mode = req.query["hub.mode"];
  let token = req.query["hub.verify_token"];
  let challenge = req.query["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
      console.log("WEBHOOK_VERIFIED");
      res.status(200).send(challenge);
    } else {
      // Responds with '403 Forbidden' if verify tokens do not match
      res.sendStatus(403);
    }
  }
});

I got the payload from the user but it's only the message, how do I know what the question the bot sent before and related it to the current answer from the user? as you can see in the post webhook I got the message from the user but now to sure how to know what the question asked by the bot was before. example of payload

{
  "object": "whatsapp_business_account",
  "entry": [
    {
      "id": "102487739205598",
      "changes": [
        {
          "value": {
            "messaging_product": "whatsapp",
            "metadata": {
              "display_phone_number": "1yyyyyyy",
              "phone_number_id": "1xxxxxxxx"
            },
            "contacts": [
              {
                "profile": {
                  "name": "James"
                },
                "wa_id": "+1xxxxxxxxxxxxx"
              }
            ],
            "messages": [
              {
                "from": "+1xxxxxxxxxxxxx",
                "id": "wamid.HBgMOTcyNTI2MzY2NjU1FQIAEhggQzVEMjY1QkNCMURGOEE2RkRFNzhGOTcyN0U3NDhBNzUA",
                "timestamp": "1657899618",
                "text": {
                  "body": "Hello, I want to order"
                },
                "type": "text"
              }
            ]
          },
          "field": "messages"
        }
      ]
    }
  ]
}

I want to build a full flow but I think I miss here something.

Upvotes: 1

Views: 2619

Answers (2)

prince_29
prince_29

Reputation: 101

First of all, you don't have to know the utterance the bot sent to the user to relate and process the response from the user.

What you can do is you can create an intent array globally and store the intents based on users' utterances.

For example: You are working on a ticket booking conversation flow. And you want to get the number of tickets from the customer. But without the customer asking to book a ticket you cannot ask the customer for the number of tickets. And if the customer is entering a number value for the number of tickets you should know that the customer is tried to book the ticket and the bot asked for number of tickets.

For this scenario

First when the user asks "book ticket", store the intent to a global array

let intentArray = [];

intentArray.push("ticketBooking");

so if the latest intent is "ticketBooking", then you can ask the user for the number of tickets.

Then when the user enters the number of tickets as a number value you can check your intent array whether the last intent was "ticketBooking" consider the current utterance as the number of ticket values and process the request as per your business logic.

Positive usecase 1:

users' utterances: ["Hi","book tickets","3","Yes"]

bot responses to the above utterances: ["hello there how can I help you?","How many tickets would you like to book?","Got it. You have booked 3 tickets. Can I confirm?"]

In this case the intentArray would be ["welcomeIntent","bookTickets","None","None"]

so when the user enter number of tickets after bookTickets,

if(intentArray[intentArray.length - 1] =="bookTickets" ){
  numberOfTickets = //currentUtterance of the user
}else{
  reply with "Sorry I didn't understand that"
}

then the user can type "Yes" at any time but we should make sure to process the "Yes" only for the confirmation message. So as per our intent array, we consider "Yes" if it comes second after the bookTickets intent.

That is:

if(intentArray[intentArray.length - 3] == "bookTickets" && currentUtterance == "Yes"){
//respond with "Thank you. your booking is confirmed"
}else{
//respond with "Sorry I didn't understand that"
}

I hope this will give you an idea to resolve your issue.

Upvotes: 0

turivishal
turivishal

Reputation: 36104

how do I know what the question the bot sent before and related it to the current answer from the user? as you can see in the post webhook I got the message from the user but now to sure how to know what the question asked by the bot was before.

  1. You can store that message content, and message-id for reference to keep track of who replied to this message.

    A successful response includes an object with an identifier prefixed with wamid. Use the ID listed after wamid to track your message status. For more details see cloud-api send message api.

    // send message api's response
    {
     "messaging_product": "whatsapp",
     "contacts": [{
         "input": "PHONE_NUMBER",
         "wa_id": "WHATSAPP_ID",
       }]
     "messages": [{
         "id": "wamid.ID",
       }]
    }
    
  2. Accessible properties in the webhook payload:

    Present in all payloads

    1. Access Your Business Account Details
      • Business Account ID: object.entry[0].id
      • Phone Number ID: object.entry[0].changes[0].value.metadata.phone_number_id
      • Phone Number: object.entry[0].changes[0].value.metadata.display_phone_number

    Present only when the User sends a message to a Business phone number

    1. Access User's Contact Details

      • Profile Name: object.entry[0].changes[0].value.contacts[0].profile.name
      • WhatsApp Phone ID: object.entry[0].changes[0].value.contacts[0].profile.wa_id
    2. Message

      • Message ID: object.entry[0].changes[0].value.messages[0].id
      • Message's All Fields: object.entry[0].changes[0].value.messages[0]

    Present only when a Business phone number sends a message to a User

    1. Status of Message sent from Business Phone (sent, delivered, read, failed)
      • Message ID: object.entry[0].changes[0].value.statuses[0].id
      • Status's All Fields: object.entry[0].changes[0].value.statuses[0]

For more details about webhook see,


I want to build an order system WhatsApp bot when the user sends a message to the bot and gets a list of items to order then each question the user answers he gets a new answer to the prev question he has answered

You need to use an interactive message type, there are 4 types,

  • list
  • button
  • product
  • product_list

Let's understand list and button interactive types, read more about both the types of object here,

  • list: you can set a id of the option in the section
  • button: you can set a id of the button

You will receive that id in webhook payload whenever user selects any option or click any reply button, and also it will return a message-id that user clicked/replied,

as per both the fields selection id and message-id you have to reply a new message to the user.

For more details see the referene webhook payloads list type and button type.

For product and product_list types need to setup products store in your business account see how, and see the api documentation.

Upvotes: 1

Related Questions