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
- 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.
- In the Meta App Dashboard, open WhatsApp > Configuration and set the Callback URL to the Meta webhook URL shown in Settings.
- Enter the same verify token and click Verify and save. Core Forms answers the
hub.challengehandshake automatically. - Subscribe the webhook to the messages field.
Setup: Twilio
- In WordPress, enter your Twilio auth token under Settings > WhatsApp Inbound Webhooks and save.
- 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:
- Quoted message ID -- if the customer replied to a specific message (Meta
context.id, TwilioOriginalRepliedMessageSid), that ID is matched against stored outbound message IDs. - 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 thewhatsapp: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_receivedaction ($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.