Skip to content

WhatsApp Notifications PRO

Yatra → WhatsApp — Delivery / Templates / Widget / Logs tabs unlocked by this module

WhatsApp drives 90%+ open rates and a fraction of the spam complaints email gets — for tour operators that means customers actually see their booking confirmation, payment reminder, and "your trip starts tomorrow" message. The WhatsApp Notifications module sends transactional messages via Meta's official WhatsApp Business Cloud API, routes inbound replies into the Enquiries inbox, and ships a public click-to-WhatsApp widget for your site.

What you'll need

ThingWhere to get it
Yatra Pro license — Growth or Scale tierYatra → License
WhatsApp Notifications module enabledYatra → Modules → WhatsApp
Meta for Developers accountdevelopers.facebook.com (free, requires a Facebook account)
Meta Business Manager accountbusiness.facebook.com — owns your WhatsApp Business Account (WABA)
Verified phone numberA real phone that isn't already on WhatsApp consumer / Business app
Permanent access tokenGenerated in Business Settings → System Users
Webhook verify secretYour app's App Secret (Settings → Basic)

Meta bills you directly per conversation. Yatra never proxies messages. As of 2026, Meta charges $0.005–$0.05 per conversation depending on category + country — usually a fraction of SMS cost.

What it unlocks

SurfaceWhat it does
Delivery tabCloud API credentials + business identifiers + sender display name + admin notification phone.
Templates tabAll your message templates (bundled system templates + custom). Inline editor + test-send button per template.
Widget tabFloating "Chat on WhatsApp" button + single-trip CTA + the [yatra_whatsapp_button] shortcode.
Logs tabPer-message delivery log — who, when, template, Meta's response, conversation cost.
Inbound repliesCustomer replies route into Yatra → Enquiries alongside web enquiries.
Event-driven sendsBookings, payments, departures, reviews — each Yatra event maps to a template.

Step 1 — Get WhatsApp Cloud API access

  1. Sign in to Meta for Developers and Create app → choose Business.
  2. Add the WhatsApp product to the app.
  3. The setup screen gives you:
    • A temporary access token (24h validity — fine for testing, not for production).
    • A test phone number Meta provisions for free.
    • Your Phone Number ID and WhatsApp Business Account (WABA) ID.
  4. In Business Manager → Settings → Users → System Users, create a System User → assign your WABA → Generate token with whatsapp_business_messaging + whatsapp_business_management scopes → never expires. This is the production token.

Full Meta walkthrough: Cloud API: Get started.

Step 2 — Enable the module

  1. Open Yatra → Modules.
  2. Find WhatsApp Notifications → toggle on.
  3. A new menu entry WhatsApp appears in the sidebar.

Step 3 — Save credentials

Open Yatra → WhatsApp → Delivery.

Delivery tab — encrypted credentials with masked last-4 hints + business identifiers

FieldNotes
Permanent access tokenThe token from the System User above. Stored encrypted via libsodium AEAD (XChaCha20-Poly1305) — the browser only ever sees a masked last-4 hint after save.
Webhook verify secretYour app's App Secret (Settings → Basic → App Secret). Optional — only required when you want to receive inbound replies.
Phone Number IDNumeric ID from the WhatsApp → API Setup screen in Meta for Developers.
Business Account ID (WABA ID)Numeric ID for your WhatsApp Business Account.
Sender display nameFriendly name shown to recipients above messages.
Default country codeUsed to canonicalise phone numbers stored without +CC prefix (e.g. +1 for US).
Admin notification phoneWhere operator-recipient templates (new booking, payment received) get delivered.

Click Test connection to verify the token works against the /v17.0/{phone_number_id} endpoint.

Step 4 — Configure the webhook (optional)

Inbound replies route into the Enquiries inbox so you can carry the conversation through your normal CRM. To enable:

  1. Copy the webhook URL displayed under Yatra → WhatsApp → Delivery → Webhook URL.
  2. In Meta for Developers → your app → WhatsApp → Configuration, paste the URL and set the verify token to the Webhook verify secret you saved in Step 3.
  3. Subscribe to the messages field.
  4. Send yourself a test message from a personal WhatsApp → it should appear in Yatra → Enquiries within ~3 seconds.

Without a webhook, you can still send transactional messages — you just won't receive replies back into Yatra.

Step 5 — Review and edit templates

Open Yatra → WhatsApp → Templates.

Templates tab — system templates (lock icon) + custom templates with inline edit

The module ships with system templates — pre-baked for the common Yatra events. You can edit the message body / disable / re-enable them, but identity fields (event_key, recipient_type, template_key) are locked because Meta approves templates by content and changing the key would orphan the approval.

Templates need Meta's approval before they send

Every message template (the wording customers actually receive) must be approved by Meta before WhatsApp will deliver it. Approval is usually fast (a few minutes to a couple of hours) for clearly transactional content like booking confirmations and reminders. Marketing-flavoured templates can take up to 24 hours and have a higher rejection rate — Meta is strict about anything that reads like a promotion.

If a template gets rejected, Meta returns a short reason (e.g. "promotional content in utility category"). Common fixes:

  • Re-categorise as Marketing if the message promotes anything.
  • Remove emoji that suggest urgency or sales (🔥, 💸, ⏰).
  • Plain-language the variables — 1 is fine but the surrounding text must read naturally without placeholders.

Submit corrected templates the same way you submitted the first one — they go to the back of the queue, not a priority lane.

Bundled system templates

template_keyEventRecipient
booking_confirmedbooking.createdCustomer
payment_receivedpayment.receivedCustomer
payment_reminderpayment.reminderCustomer
departure_reminder_t_minus_1T-1 day departure cronCustomer
booking_cancelled_customerbooking.cancelledCustomer
review_requestT+1 day after trip endCustomer
admin_new_bookingbooking.createdAdmin
admin_payment_receivedpayment.receivedAdmin

Field reference

FieldNotes
NameInternal label shown only in the admin.
Event keyOne of the trigger events above (system rows: locked).
Recipient typecustomer or admin (system rows: locked).
Meta template nameMust match the template name approved by Meta in WhatsApp Manager. Yatra calls Meta's /messages endpoint with this name.
Language codeBCP-47 language tag matching the approved Meta template. Default: en_US.
BodyThe message body with merge tags. See merge-tag list below.
StatusActive / Paused. Paused templates skip without erroring.

Merge tags

All Yatra merge tags from the email system are honored — full list under Email & notifications → merge tags. Most-used in WhatsApp templates:

{{customer_name}}        {{trip_name}}           {{booking_id}}
{{departure_date}}        {{travelers_count}}     {{booking_total}}
{{amount_paid}}           {{amount_due}}          {{payment_link}}
{{customer_email}}        {{customer_phone}}      {{currency_symbol}}

Test send

Each template has a Test send button → enter a phone number → Yatra sends the template populated with realistic synthetic merge-tag data. Useful for proofreading + verifying Meta's approval covers your body content.

Version history (undo a bad edit)

Every save of a template is recorded as a snapshot. Click the History button next to Edit on any template row to see the full timeline newest-first.

Each row shows:

  • The version number (v1, v2, v3, …) and when it was saved.
  • A short summary of what changed (e.g. "edited: body, is_active").
  • The user ID of whoever made the edit (or empty for system-triggered changes like the defaults seed).
  • Click the row to expand it — you'll see the snapshot's name, event, recipient, active flag, and body so you can compare against the current template.

The Restore this version button rewrites the live template with the snapshot's contents. Before the restore happens, the current state is captured as a new version, so the chain stays linear — you can always restore back to where you were 30 seconds ago.

System templates have a restriction: only the Active toggle restores from history. Body, event binding, and recipient type are managed by the plugin (so a future plugin update can refresh them) and can't be reverted from this UI. Custom templates restore every field.

There's no auto-prune on history rows — templates with a long edit history keep every snapshot. Template edits are infrequent (a handful per template per month at most) so the row count stays small.

Step 6 — Public WhatsApp widget (optional)

Open Yatra → WhatsApp → Widget.

FieldNotes
EnabledMaster toggle. When off the widget doesn't render anywhere.
Contact phoneThe number customers tap-to-message. Include country code (+).
Default messagePre-filled message body that opens in the user's WhatsApp app. Supports the trip merge tags on single-trip pages.
Floating buttonToggle the bottom-right floating button + position (left/right) + colour.
Single-trip CTAToggle a "Chat on WhatsApp" button on every trip's sticky sidebar.
Shortcode[yatra_whatsapp_button] for use anywhere on your site (page builders, sidebar widgets, etc.).

Customer opt-in

Meta requires that customers opt in before they receive non-template messages from your business. The module surfaces an opt-in flag on every customer record + a Required toggle on the Widget tab. When the toggle is on:

  • Booking forms add a "Yes, send me WhatsApp updates" checkbox (default off).
  • The checkbox value is recorded against the customer's opt_in flag.
  • Sends to non-opted-in customers are skipped + logged.

Opt-in state is stored in a dedicated wp_yatra_whatsapp_opt_in table with a unique index on the phone number, so lookups are O(1) even at scale. STOP / UNSUBSCRIBE keywords in inbound replies flip the row to opted-out; subsequent inbound replies flip it back to opted-in (which is the implicit consent for the next 24-hour conversation window).

Step 7 — Verify it works

After a real booking:

  1. Open Yatra → WhatsApp → Logs.
  2. The latest row should show booking.createdtemplate: booking_confirmedstatus: sent → Meta message_id in the response column.
  3. Click the row for the full payload: rendered body, headers, Meta's response, opt-in state at send time, retry attempts.

Reminders cron

A twice-daily WP cron tick handles every time-based send (anything that's not action-triggered):

  • Trip reminders — sent N hours before departure (default 24h, configurable per template).
  • Review requests — sent N hours after departure for completed bookings.
  • Payment reminders — when an outstanding balance is due soon (Flexible Payments / Scheduled Payments integration).
  • Abandoned-checkout recovery — when a booking sat unfinished past a configurable threshold.

Each tick is split into background-job chunks of 10 bookings each, with 500 ms between sends inside a chunk and 6 seconds between chunks. This keeps you well under Meta's 1,000-messages-per-second tier limit and means the twice-daily tick itself stays fast even when 200 bookings are due for a reminder (it just schedules 20 background events).

Idempotency: each dispatch query joins against the message log filtered by template + booking ID. A booking never receives the same template twice even if the cron runs twice or a worker crashes mid-batch.

Cron lifecycle is owned by the module — disable WhatsApp Notifications and the cron is unscheduled automatically, no orphan events.

Message log retention

The wp_yatra_whatsapp_messages log keeps every outbound + inbound message for forensic review. A daily retention cron deletes rows older than the configured cut-off — 90 days by default, capped at 730 days (~2 years).

Operators with longer compliance retention needs can extend the window:

php
add_filter('yatra_whatsapp_retention_days', fn() => 365);  // 1 year

The sweep is hardened against exceptions — a cron failure here writes to the WordPress error_log but never cascades. The log itself isn't load-bearing for sends; it's forensic.

After each successful sweep, the yatra_whatsapp_retention_swept action fires with the row count + the retention window, useful for hooking into compliance dashboards.

REST API

EndpointVerbPurpose
/yatra/v1/whatsapp/metaGETModule eligibility + bundled events + capabilities.
/yatra/v1/whatsapp/settingsGET / PUTRead or update delivery + widget settings.
/yatra/v1/whatsapp/credentialsPUTSet or clear a single credential field (access_token, webhook_secret).
/yatra/v1/whatsapp/templatesGET / POSTList templates / create a new custom template.
/yatra/v1/whatsapp/templates/{id}GET / PUT / DELETERead / update / delete one template.
/yatra/v1/whatsapp/templates/{id}/test-sendPOSTSend the template populated with synthetic data.
/yatra/v1/whatsapp/templates/restore-defaultsPOSTRe-insert any deleted system templates.
/yatra/v1/whatsapp/templates/{id}/versionsGETList the template's version snapshots, newest first.
/yatra/v1/whatsapp/templates/{id}/versions/{versionId}/restorePOSTRestore the template from a snapshot. Captures the current state first so the restore itself can be undone.

All write endpoints require manage_options + Growth/Scale-active license. See REST API reference for the full schema.

Hooks & filters

HookPurpose
yatra_whatsapp_should_send (filter)Last gate before the API call. Return false to skip the send. Useful for per-customer opt-out logic.
yatra_whatsapp_template_body (filter)Edit the rendered body after merge-tag substitution but before the API call.
yatra_whatsapp_provider (filter)Swap the WhatsApp transport — defaults to Meta Cloud API, but you can route through Twilio or 360Dialog by registering a custom provider.
yatra_whatsapp_message_sent (action)Fires on each successful send with the Meta message_id + cost data.
yatra_whatsapp_message_failed (action)Fires on API error — useful for alerting / fallback to SMS.
yatra_whatsapp_inbound_message (action)Fires when a webhook delivers an inbound reply, before it's routed to Enquiries.
yatra_whatsapp_retention_days (filter)Override the 90-day default for message-log retention. Capped at 730 days.
yatra_whatsapp_retention_swept (action)Fires after each successful retention sweep with the row count + the window in days.

Troubleshooting

"WhatsApp" doesn't appear in the sidebar — verify (1) your license is Growth or Scale on the License page, (2) the module is toggled on under Modules.

Test connection returns 401 OAuthException — token expired (you're using the temporary 24h token) or revoked. Generate a permanent System User token with the right scopes — see Step 1.

Test connection returns 100 Invalid parameter — Phone Number ID is wrong. Open Meta for Developers → WhatsApp → API Setup and copy the numeric ID under your test number (not the WABA ID).

Sends queue but never arrive — Meta requires templates to be approved before they can be sent to phones outside your test allowlist. Open WhatsApp Manager → Account tools → Message templates and submit each template. Approval typically takes minutes for simple body-only templates and 24h for media templates.

Customer receives "Hi " with the literal merge tag — the Meta template name under Yatra and the approved Meta template don't share parameter shapes. Meta-approved templates use positional placeholders (1, 2); the module maps merge tags onto those positions. Re-submit your template body without literal merge-tag names.

Inbound replies don't appear in Enquiries — webhook setup incomplete. Re-check Step 4 + look at Yatra → WhatsApp → Logs filtered by inbound direction. Common failure: webhook URL points at HTTP instead of HTTPS; Meta requires TLS.

Conversation cost higher than expected — Meta bills per 24-hour conversation, not per message. A back-and-forth thread in the same day is one conversation; the next day's reply starts a new one. Use Yatra → WhatsApp → Logs to see the conversation cost Meta charged on each send.

Where to read more