Skip to main content

WhatsApp Inbound Replies

Receive WhatsApp replies from your customers and attach them to the right submission's conversation thread. Works with both outbound WhatsApp actions -- Send WhatsApp (Cloud API) (Meta) and Send WhatsApp (Twilio).

Class: Core_Forms\Integrations\WhatsAppInbound Source: src/integrations/class-whatsapp-inbound.php

Webhook URLs

Core Forms registers two signed REST endpoints and displays them under Settings > WhatsApp Inbound Webhooks:

/wp-json/core-forms/v1/whatsapp/meta
/wp-json/core-forms/v1/whatsapp/twilio

Settings Reference

Setting Used for Description
Meta verify token Meta Cloud API Token you invent; Meta echoes it during webhook verification
Meta app secret Meta Cloud API App secret from your Meta app; used to validate the X-Hub-Signature-256 header
Twilio auth token Twilio Your Twilio auth token; used to validate the X-Twilio-Signature header

Unsigned or incorrectly signed requests are rejected: Meta payloads with a missing/invalid HMAC-SHA256 body signature and Twilio requests with an invalid signature both return 401. Meta verification requests with the wrong verify token return 403.

Setup: Meta Cloud API

  1. In WordPress, go to Settings > WhatsApp Inbound Webhooks, enter a Meta verify token (any random string) and your app's Meta app secret, then save.
  2. In the Meta App Dashboard, open WhatsApp > Configuration and set the Callback URL to the Meta webhook URL shown in Settings.
  3. Enter the same verify token and click Verify and save. Core Forms answers the hub.challenge handshake automatically.
  4. Subscribe the webhook to the messages field.

Setup: Twilio

  1. In WordPress, enter your Twilio auth token under Settings > WhatsApp Inbound Webhooks and save.
  2. In the Twilio Console, set the inbound message webhook of your WhatsApp sender (or Messaging Service) to the Twilio webhook URL shown in Settings, using HTTP POST.

Core Forms responds to Twilio with an empty TwiML <Response>, so no auto-reply is sent.

How Replies Are Correlated

Outbound WhatsApp actions store the provider message ID with each send. When a reply arrives, Core Forms finds the submission in two steps:

  1. Quoted message ID -- if the customer replied to a specific message (Meta context.id, Twilio OriginalRepliedMessageSid), that ID is matched against stored outbound message IDs.
  2. Most recent recipient thread -- otherwise, the reply is attached to the submission with the most recent outbound WhatsApp message to that phone number (compared digits-only, ignoring + and the whatsapp: prefix).

If neither matches, the message is ignored. Matched replies are:

  • Saved as an inbound message on the submission's conversation thread with the subject "WhatsApp reply".
  • Marked with the submission status replied.
  • Announced to developers via the cf_whatsapp_reply_received action ($submission_id, provider, message/params).

Meta status callbacks (sent, delivered, read, failed) also update the status of stored outbound messages, so the conversation view reflects delivery state.

Supported Message Content

Text bodies, button taps, and interactive button/list reply titles are stored as the message text. Other types (images, audio, documents, and so on) are stored as a placeholder such as [image message] -- the raw provider payload is kept with the message for developers.

Troubleshooting

  • Meta verification fails: The verify token in Settings must exactly match the one entered in the Meta App Dashboard, and it cannot be empty.
  • Replies return 401: The Meta app secret or Twilio auth token doesn't match the credentials signing the webhooks. Check for copy/paste whitespace.
  • Reply not appearing on a submission: There must be a prior outbound WhatsApp send recorded for that phone number (or a direct reply to a tracked message). Sends made before configuring the outbound actions can't be correlated.