1. Feedback Actions
  2. Update From Whatsapp

Feedback Actions

Update From Whatsapp Feedback Action

Explains the WhatsApp feedback action that runs when a WhatsApp message or call is received. Useful for conversational workflows, reply routing, media handling, answering WhatsApp calls with a voice assistant, and stubsession continuity.

Overview

When a Whatsapp message is received by the Stubber Platform the stubsession is derived to intelligently route the message to the correct stub.
Then the _update_from_whatsapp feedback action is triggered on the stub.

The _update_from_whatsapp feedback action is used to then further automate anything in the stub that needs to be done when a WhatsApp is received.

The message body of the Whatsapp message will be set to the message of the stubpost. i.e. stubpost.message.
If a contact can be derived from the mobile number of the sender, the posted_by => on_behalf_of will be set to the contact.
All the details of the Whatsapp message will be available in the stubpost.data._incoming_whatsapp_data data path.

WhatsApp calls to the number also trigger _update_from_whatsapp, see WhatsApp calls.

WhatsApp calls

When WhatsApp calling is enabled on the number, a call is routed to the stub the same way as a message, including the stubsession's feedback action, and triggers _update_from_whatsapp. Two flags on stubpost.data._incoming_whatsapp_data tell calls and messages apart:

Flag Incoming call Missed call Message
is_call_event true true not set
is_incoming_call true false not set

The details of the call are in stubpost.data._incoming_whatsapp_data.call_data. Only two call events are posted: incoming and missed. Once a call is answered, the call reports back like any live voice call, with the _update_from_voice feedback action, including when it ends.

WARNING

Add stubpost.data._incoming_whatsapp_data.is_call_event != true to the conditions of tasks that handle messages, eg a GPT Chat Task that replies to the user. Otherwise they also run for calls, and treat "Incoming WhatsApp call" as something the user typed.

Answering a call

Run Start Voice Chat with the whatsapp channel, then Answer WhatsApp Call with the call and the new voice session. Use is_incoming_call as the condition on both:

loading...

answer_whatsapp_call returns once the caller hears the assistant, usually within 2 seconds, or with an error when answering failed:

Result Meaning
success The call is live. payload.status is answered
call_not_ringing The call isn't ringing anymore, eg the caller hung up first or the call was already answered or rejected
unknown_call No call with this comwhatsappcalluuid
technical error Answering failed. error.details.step says where. The caller's call ends and the voice call ends as abandoned by itself
NOTE

The call must be answered within 25 seconds of the incoming event, otherwise it's rejected automatically and a missed event follows.

To end an answered call, end the voice call as usual, eg with a hangup voice notification.

Rejecting a call

To not take the call, run Reject WhatsApp Call:

loading...

It only works while the call is ringing. A missed event with the reason rejected follows.

Missed calls

A call that was never answered triggers _update_from_whatsapp a second time, with call_data.event set to missed and is_incoming_call set to false. Use it to follow up, eg send a WhatsApp message saying you missed the call:

        "conditions": ["stubpost.data._incoming_whatsapp_data.call_data.event = 'missed'"]

      

call_data.reason says why the call was missed:

reason Meaning
caller_hangup The caller hung up while it was ringing, or while it was being answered
rejected The template rejected the call with reject_whatsapp_call
answer_timeout The call wasn't answered within 25 seconds

Call data

Example data for an incoming call:

        "_incoming_whatsapp_data": {
  "message": "Incoming WhatsApp call",
  "from": "XXXXXXXXXXXX",
  "from_name": "Joe Soap",
  "to": "14153121456",
  "whatsapp_profile_name": "stubber_public",
  "is_call_event": true,
  "is_incoming_call": true,
  "call_data": {
    "event": "incoming",
    "comwhatsappcalluuid": "9377503e-62bc-440c-a6f2-668a9be1fccb",
    "call_id": "wacid.HBgLMjc3MTU5MzYxNzIVAgASGCA...",
    "from_user_id": "ZA.1668707664316330",
    "direction": "USER_INITIATED",
    "cta_payload": null,
    "deeplink_payload": null,
    "timestamp": "1790771071",
    "answer_deadline": "2026-10-07T10:00:25.000Z"
  }
},

      

Example data for a missed call:

        "_incoming_whatsapp_data": {
  "message": "Missed WhatsApp call",
  "from": "XXXXXXXXXXXX",
  "from_name": "Joe Soap",
  "to": "14153121456",
  "whatsapp_profile_name": "stubber_public",
  "is_call_event": true,
  "is_incoming_call": false,
  "call_data": {
    "event": "missed",
    "reason": "caller_hangup",
    "comwhatsappcalluuid": "9377503e-62bc-440c-a6f2-668a9be1fccb",
    "call_id": "wacid.HBgLMjc3MTU5MzYxNzIVAgASGCA...",
    "from_user_id": "ZA.1668707664316330",
    "direction": "USER_INITIATED",
    "cta_payload": null,
    "deeplink_payload": null,
    "timestamp": "1790771091"
  }
},

      

Call properties

is_call_event
boolean

true for every call event. Not set for messages.


is_incoming_call
boolean

true for a ringing call to answer or reject, false for a missed call. Not set for messages.


call_data.event
string

incoming or missed.


call_data.comwhatsappcalluuid
string

The id of the call. Pass it to answer_whatsapp_call or reject_whatsapp_call.


call_data.call_id
string

WhatsApp's id for the call.


call_data.from_user_id
string

WhatsApp's business-scoped id for the caller. Always set, even when from is missing because the caller uses a WhatsApp username.


call_data.direction
string

USER_INITIATED: the WhatsApp user called the business.


call_data.cta_payload
string

The payload of the call button the caller used, if the call came from a call button in a message. Otherwise null.


The payload of the call link the caller used, if the call came from a call deeplink. Otherwise null.


call_data.timestamp
string

Unix timestamp of the call event.


call_data.answer_deadline
string

incoming only. The ISO 8601 date-time by which the call must be answered.


call_data.reason
string

missed only. Why the call was missed: caller_hangup, rejected or answer_timeout.

Data Structure

Feedback Action Data

Example data that is passed to the _update_from_whatsapp feedback action:

        "_incoming_whatsapp_data": {
  "message": "Hi",
  "from": "XXXXXXXXXXXX",
  "from_name": "Joe Soap",
  "to": "14153121456",
  "whatsapp_profile_name": "stubber_public",
  "whatsapp_body": {
    "from": "XXXXXXXXXXXX",
    "id": "wamid.HBgLMjc3MjYwNTAwMzUVAgASGCAwRTlGMzVBQTJDMDY1NzgyRkVCMEM2N0NENzlCNjc5MAA=",
    "timestamp": "1734531943",
    "text": {
      "body": "Hi"
    },
    "type": "text",
    "received_date_time": "2024-12-18T14:25:44.836Z",
    "phone_number_id": "XXXXXXXXXXXX",
    "to": "14153121456",
    "orguuid": "XXXXXXXXXXXXXXX"
  }
},

      

JSONSchema

The JSONSchema of the stubpost.data._incoming_whatsapp_data is :

        {
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "Incoming WhatsApp Data",
  "type": "object",
  "properties": {
    "_incoming_whatsapp_data": {
      "type": "object",
      "properties": {
        "message": {
          "type": "string",
          "description": "The content or description of the WhatsApp message."
        },
        "whatsapp_attachments": {
          "type": "array",
          "description": "List of attachments included in the WhatsApp message.",
          "items": {
            "type": "object",
            "properties": {
              "filename": {
                "type": "string",
                "description": "The name of the file."
              },
              "originalname": {
                "type": "string",
                "description": "The original name of the file as uploaded."
              },
              "fileuuid": {
                "type": "string",
                "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$",
                "description": "UUID of the file."
              },
              "contentType": {
                "type": "string",
                "description": "The MIME type of the file."
              }
            },
            "required": ["filename", "originalname", "fileuuid", "contentType"],
            "additionalProperties": false
          }
        },
        "from": {
          "type": "string",
          "pattern": "^[0-9]{11,15}$",
          "description": "The sender's phone number in international format."
        },
        "from_name": {
          "type": "string",
          "description": "The name of the sender."
        },
        "to": {
          "type": "string",
          "pattern": "^[0-9]{11,15}$",
          "description": "The recipient's phone number in international format."
        },
        "whatsapp_profile_name": {
          "type": "string",
          "description": "The WhatsApp profile name of the sender."
        },
        "is_call_event": {
          "type": "boolean",
          "description": "True for WhatsApp call events. Not set for messages."
        },
        "is_incoming_call": {
          "type": "boolean",
          "description": "True for a ringing call to answer or reject, false for a missed call. Not set for messages."
        },
        "call_data": {
          "type": "object",
          "description": "Call events only. The details of the WhatsApp call.",
          "properties": {
            "event": {
              "type": "string",
              "enum": ["incoming", "missed"],
              "description": "The call event."
            },
            "comwhatsappcalluuid": {
              "type": "string",
              "description": "The id of the call, for answer_whatsapp_call and reject_whatsapp_call."
            },
            "call_id": {
              "type": "string",
              "description": "WhatsApp's id for the call."
            },
            "from_user_id": {
              "type": "string",
              "description": "WhatsApp's business-scoped id for the caller."
            },
            "direction": {
              "type": "string",
              "enum": ["USER_INITIATED"],
              "description": "Who started the call."
            },
            "cta_payload": {
              "type": ["string", "null"],
              "description": "Payload of the call button the call came from."
            },
            "deeplink_payload": {
              "type": ["string", "null"],
              "description": "Payload of the call deeplink the call came from."
            },
            "timestamp": {
              "type": "string",
              "pattern": "^[0-9]+$",
              "description": "Unix timestamp of the call event."
            },
            "answer_deadline": {
              "type": "string",
              "format": "date-time",
              "description": "incoming only. The time by which the call must be answered."
            },
            "reason": {
              "type": "string",
              "enum": ["caller_hangup", "rejected", "answer_timeout"],
              "description": "missed only. Why the call was missed."
            }
          },
          "required": ["event", "comwhatsappcalluuid", "call_id"]
        },
        "whatsapp_body": {
          "type": "object",
          "properties": {
            "from": {
              "type": "string",
              "pattern": "^[0-9]{11,15}$",
              "description": "The sender's phone number in international format."
            },
            "id": {
              "type": "string",
              "description": "Unique identifier for the WhatsApp message."
            },
            "timestamp": {
              "type": "string",
              "pattern": "^[0-9]+$",
              "description": "Unix timestamp when the message was sent."
            },
            "type": {
              "type": "string",
              "enum": [
                "text",
                "image",
                "audio",
                "video",
                "document",
                "location",
                "contact",
                "sticker"
              ],
              "description": "The type of the WhatsApp message."
            },
            "received_date_time": {
              "type": "string",
              "format": "date-time",
              "description": "The ISO 8601 date-time when the message was received."
            },
            "phone_number_id": {
              "type": "string",
              "description": "The ID of the phone number associated with the WhatsApp Business account."
            },
            "to": {
              "type": "string",
              "pattern": "^[0-9]{11,15}$",
              "description": "The recipient's phone number in international format."
            },
            "orguuid": {
              "type": "string",
              "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$",
              "description": "The UUID of the organization."
            },
            "text": {
              "type": "object",
              "properties": {
                "body": {
                  "type": "string",
                  "description": "The text content of the message."
                }
              },
              "required": ["body"],
              "additionalProperties": false
            },
            "image": {
              "type": "object",
              "properties": {
                "mime_type": {
                  "type": "string",
                  "description": "The MIME type of the image."
                },
                "sha256": {
                  "type": "string",
                  "description": "SHA-256 hash of the image."
                },
                "id": {
                  "type": "string",
                  "description": "Identifier for the image."
                }
              },
              "required": ["mime_type", "sha256", "id"],
              "additionalProperties": false
            },
            "audio": {
              "type": "object",
              "properties": {
                "mime_type": {
                  "type": "string",
                  "description": "The MIME type of the audio."
                },
                "sha256": {
                  "type": "string",
                  "description": "SHA-256 hash of the audio."
                },
                "id": {
                  "type": "string",
                  "description": "Identifier for the audio."
                },
                "voice": {
                  "type": "boolean",
                  "description": "Indicates if the audio is a voice message."
                }
              },
              "required": ["mime_type", "sha256", "id", "voice"],
              "additionalProperties": false
            },
            "contacts": {
              "type": "array",
              "description": "List of contact information included in the message.",
              "items": {
                "type": "object",
                "properties": {
                  "emails": {
                    "type": "array",
                    "description": "List of email addresses for the contact.",
                    "items": {
                      "type": "object",
                      "properties": {
                        "email": {
                          "type": "string",
                          "format": "email",
                          "description": "Email address of the contact."
                        },
                        "type": {
                          "type": "string",
                          "enum": ["Home", "Work", "Other"],
                          "description": "Type of the email address."
                        }
                      },
                      "required": ["email", "type"],
                      "additionalProperties": false
                    }
                  },
                  "name": {
                    "type": "object",
                    "properties": {
                      "first_name": {
                        "type": "string",
                        "description": "First name of the contact."
                      },
                      "last_name": {
                        "type": "string",
                        "description": "Last name of the contact."
                      },
                      "formatted_name": {
                        "type": "string",
                        "description": "Full name of the contact."
                      }
                    },
                    "required": ["first_name", "last_name", "formatted_name"],
                    "additionalProperties": false
                  },
                  "org": {
                    "type": "object",
                    "properties": {
                      "company": {
                        "type": "string",
                        "description": "Company where the contact works."
                      },
                      "title": {
                        "type": "string",
                        "description": "Job title of the contact."
                      }
                    },
                    "required": ["company", "title"],
                    "additionalProperties": false
                  },
                  "phones": {
                    "type": "array",
                    "description": "List of phone numbers for the contact.",
                    "items": {
                      "type": "object",
                      "properties": {
                        "phone": {
                          "type": "string",
                          "pattern": "^\\+?[0-9\\s\\-()]{7,20}$",
                          "description": "Phone number of the contact."
                        },
                        "wa_id": {
                          "type": "string",
                          "pattern": "^[0-9]{11,15}$",
                          "description": "WhatsApp ID associated with the phone number."
                        },
                        "type": {
                          "type": "string",
                          "enum": ["MOBILE", "HOME", "WORK"],
                          "description": "Type of the phone number."
                        }
                      },
                      "required": ["phone", "wa_id", "type"],
                      "additionalProperties": false
                    }
                  }
                },
                "required": ["emails", "name", "org", "phones"],
                "additionalProperties": false
              }
            },
            "location": {
              "type": "object",
              "properties": {
                "latitude": {
                  "type": "number",
                  "minimum": -90,
                  "maximum": 90,
                  "description": "Latitude coordinate of the location."
                },
                "longitude": {
                  "type": "number",
                  "minimum": -180,
                  "maximum": 180,
                  "description": "Longitude coordinate of the location."
                }
              },
              "required": ["latitude", "longitude"],
              "additionalProperties": false
            }
          },
          "required": [
            "from",
            "id",
            "timestamp",
            "type",
            "received_date_time",
            "phone_number_id",
            "to",
            "orguuid"
          ],
          "allOf": [
            {
              "if": {
                "properties": {
                  "type": {
                    "const": "text"
                  }
                }
              },
              "then": {
                "required": ["text"],
                "properties": {
                  "text": {
                    "$ref": "#/properties/_incoming_whatsapp_data/properties/whatsapp_body/properties/text"
                  }
                }
              }
            },
            {
              "if": {
                "properties": {
                  "type": {
                    "const": "image"
                  }
                }
              },
              "then": {
                "required": ["image"],
                "properties": {
                  "image": {
                    "$ref": "#/properties/_incoming_whatsapp_data/properties/whatsapp_body/properties/image"
                  }
                }
              }
            },
            {
              "if": {
                "properties": {
                  "type": {
                    "const": "audio"
                  }
                }
              },
              "then": {
                "required": ["audio"],
                "properties": {
                  "audio": {
                    "$ref": "#/properties/_incoming_whatsapp_data/properties/whatsapp_body/properties/audio"
                  }
                }
              }
            },
            {
              "if": {
                "properties": {
                  "type": {
                    "const": "contact"
                  }
                }
              },
              "then": {
                "required": ["contacts"],
                "properties": {
                  "contacts": {
                    "$ref": "#/properties/_incoming_whatsapp_data/properties/whatsapp_body/properties/contacts"
                  }
                }
              }
            },
            {
              "if": {
                "properties": {
                  "type": {
                    "const": "location"
                  }
                }
              },
              "then": {
                "required": ["location"],
                "properties": {
                  "location": {
                    "$ref": "#/properties/_incoming_whatsapp_data/properties/whatsapp_body/properties/location"
                  }
                }
              }
            }
          ],
          "additionalProperties": false
        }
      },
      "required": ["message", "from", "from_name", "to", "whatsapp_profile_name"],
      "additionalProperties": false
    }
  },
  "required": ["_incoming_whatsapp_data"],
  "additionalProperties": false
}