Booking Whatsapp E2e Tutorial

Nexaflow Editor

5 MIN READ

Nexaflow Booking: WhatsApp end-to-end testing tutorial

Version: 27 October 2026. Scope: connection, templates, outbound booking notifications, inbound replies, delivery receipts and failure recovery.

This is a test procedure, not a record of completed live testing. Test against the deployed build containing the communication fixes. A passing unit test or a green “queued” toast does not prove a message reached a phone.

#1. Test strategy and equipment

Use four checkpoints in order:

  1. Connection: Meta can send to a test handset and Nexaflow receives its replies.
  2. Templates and callbacks: Nexaflow can send an approved template, and a real delivery callback updates its log.
  3. Business flows: booking, reminders, rescheduling, estimates, bills and receipts produce the right messages and database changes.
  4. Failure and isolation: disabled sending, opt-out, invalid templates, duplicates and other clinics cannot produce incorrect messages or mutations.

Use a staging clinic and synthetic patient records. Use actual consenting test handsets; do not use invented numbers that might belong to someone. Keep the clinic sender separate from patient and doctor recipient numbers. Do not use a real clinical history, diagnosis or financial transaction.

| Test asset | Setup | | --- | --- | | Clinic sender | Dedicated test Cloud API number or staging clinic number, connected to Nexaflow | | Patient A | Tester-controlled WhatsApp number; normal booking recipient | | Patient B | Second tester-controlled number; guardian and wrong-recipient tests | | Doctor A | Provider profile with a tester-controlled mobile number | | Doctor B | Different provider; preferably a different test handset | | Service | “Test consultation”, 30 minutes, INR 1,000 | | Treatment | “Test treatment course”, agreed cost INR 10,000, four instalments | | Location | “Staging clinic”, timezone Asia/Kolkata, future availability |

If handsets are limited, run recipient roles sequentially, but do at least one reschedule with different patient and doctor numbers. Otherwise a routing error is difficult to spot.

Create a test register with: case ID, build/version, clinic/module, sender phone-number ID, booking ID, action time with timezone, expected recipient, outbox ID, Meta message ID, final status, handset evidence, result and defect reference. Never record access tokens or app secrets.

#2. Connect WhatsApp before testing bookings

2.1 Choose the sender route

For an initial transport check, Meta's developer setup provides test assets. Add and verify the recipient numbers allowed by the test setup, then send the supplied sample template from Meta's API Setup/Get Started screen. Screen labels may vary.

For a full Nexaflow test, use the actual embedded onboarding flow with a dedicated staging account/number, or an already connected staging sender. A sample message sent from Meta alone does not prove the sender is connected to Nexaflow's booking module.

For your Tech Provider setup, use the clinic account owner/admin to select the correct WhatsApp assets during onboarding. Keep the WABA/account ID, phone-number ID, and display telephone number distinct. The phone-number ID is the numeric sender identifier used by the API; it is not the telephone number.

2.2 Verify the Nexaflow links

  1. Complete WhatsApp onboarding in Nexaflow.
  2. Confirm that the intended clinic number appears as connected.
  3. Assign the number to the intended agent/bot.
  4. Link that agent to the booking module and enable the link.
  5. Confirm the sender and booking module belong to the same account owner.
  6. Open Booking Settings → Communications → WhatsApp appointment updates.
  7. Confirm the sender is offered in the sender dropdown. If it is absent, fix the account/agent/module linkage first.

Pass: the correct sender is selectable. Do not continue by selecting another clinic's sender.

2.3 Validate the webhook independently

The application endpoint is:

https://YOUR-STAGING-HOST/api/whatsapp/webhook text

On the server, verify the deployed environment has the intended META_APP_ID, META_APP_SECRET, META_GRAPH_API_VERSION, META_WEBHOOK_CALLBACK_URL, and META_WEBHOOK_VERIFY_TOKEN. Use your existing server configuration; do not paste secrets into test records. Embedded onboarding also uses the configured signup IDs and phone-registration PIN.

  1. Configure/verify the HTTPS callback in Meta using the server's verification token.
  2. Ensure the app is subscribed to the clinic's account and the WhatsApp messages webhook field. Nexaflow's webhook-sync action can be used to check or repair the account subscription.
  3. Confirm the active callback points at staging rather than another deployment.
  4. From Patient A's handset, send Hello, this is an E2E booking test to the clinic number.
  5. Verify the inbound message reaches the intended Nexaflow agent/conversation and generates a reply.
  6. Send an outbound message and verify real status callbacks arrive too.

Pass: both inbound content and outbound status receipts reach the application. A successful webhook verification handshake alone is insufficient. If a real clinic recipient is outside the app's developer/test users, check the app's production access and the connected business assets as well.

#3. Create and approve the templates

In WhatsApp Manager, select the clinic's account, open Message Templates, create a template, choose its language and submit it for approval. Use Utility content describing a requested booking or transaction; Meta decides the final category and approval. Enter realistic synthetic examples for every variable when requested.

Current Nexaflow contract: BODY-only templates, positional variables, no header, footer or buttons. The variable count and order below must match exactly. Use the exact approved identifier and language code in Nexaflow; en and en_US are different configurations. Suggested names below are examples, not templates that already exist.

| Purpose | Suggested name | Positional parameters, in exact order | | --- | --- | --- | | General appointment update | booking_appointment_update | 1 event; 2 booking reference; 3 location; 4 local date/time | | Patient registration | patient_registration_confirmation | 1 clinic; 2 patient; 3 patient ID; 4 mobile; 5 DOB | | Walk-in booking | walk_in_booking_confirmation | 1 patient; 2 patient ID; 3 service and provider; 4 date/time; 5 location | | Reminder | booking_reminder | 1 patient; 2 doctor; 3 date; 4 time; 5 visit instructions | | Estimate | treatment_estimate | 1 patient; 2 treatment; 3 doctor; 4 visit date; 5 estimate; 6 clinic | | Treatment bill | treatment_bill | 1 patient; 2 treatment; 3 total cost; 4 total paid; 5 balance; 6 payment plan | | Payment receipt | payment_receipt | 1 patient; 2 treatment; 3 receipt number; 4 payment amount; 5 cumulative paid; 6 balance; 7 method; 8 receipt URL | | Reschedule proposal | appointment_reschedule_proposal | 1 clinic; 2 doctor; 3 original date/time; 4 proposed date/time; 5 confirmation URL | | Patient reschedule confirmation | Reuse booking_appointment_update | Same four parameters as general appointment update | | Doctor reschedule confirmation | doctor_reschedule_confirmation | 1 doctor; 2 patient; 3 service; 4 new date/time; 5 location |

Patient and doctor confirmation settings can fall back to the main four-parameter appointment template. A dedicated doctor template gives clearer wording.

Copyable template bodies

General appointment update — 4 variables

Appointment update: {{1}}. Reference: {{2}}. Location: {{3}}. Date and time: {{4}}. Please contact the clinic if you need assistance. text

Patient registration — 5 variables

Registration confirmed at {{1}}. Patient: {{2}}. Patient ID: {{3}}. Registered mobile: {{4}}. Date of birth: {{5}}. Please contact the clinic to correct any details. text

Walk-in appointment — 5 variables

Hello {{1}}, your appointment is registered. Patient ID: {{2}}. Service and provider: {{3}}. Date and time: {{4}}. Location: {{5}}. Please contact reception when you arrive. text

Reminder — 5 variables

Hello {{1}}, this is a reminder of your appointment with {{2}} on {{3}} at {{4}}. Visit instructions: {{5}}. Thank you. text

Estimate — 6 variables

Hello {{1}}, your requested estimate for {{2}} with {{3}}, scheduled for {{4}}, is {{5}}. Clinic: {{6}}. Please contact us if you have questions about this estimate. text

Treatment bill — 6 variables

Hello {{1}}, your bill for {{2}} has been updated. Total cost: {{3}}. Total paid: {{4}}. Balance: {{5}}. Payment plan: {{6}}. Please contact the clinic if a correction is needed. text

Receipt — 8 variables

Hello {{1}}, payment for {{2}} has been recorded. Receipt: {{3}}. Amount received: {{4}}. Total paid: {{5}}. Balance: {{6}}. Payment method: {{7}}. View your receipt: {{8}}. Thank you. text

Reschedule proposal — 5 variables

Appointment change from {{1}}: your visit with {{2}} is proposed to move from {{3}} to {{4}}. Review and confirm here: {{5}}. Your original appointment remains active until the change is confirmed. text

Doctor reschedule confirmation — 5 variables

Hello {{1}}, the appointment for {{2}}, service {{3}}, has been rescheduled to {{4}} at {{5}}. Please check your updated appointment list. text

Do not assume submission means approval. Continue only when each template needed for the next test is approved and available in the sender's account. You can start with the general template and add the remaining templates in stages.

#4. Enable the application in stages

  1. Open Booking Settings → Communications → WhatsApp appointment updates.
  2. Enable the channel and select the staging sender.
  3. Set the main appointment template and language.
  4. Set registration, walk-in, reminder and reschedule templates in their respective sections.
  5. Under Estimates & Payments, set the estimate, bill and receipt template names.
  6. Enable the relevant booking events in Appointment communications.
  7. Set one reminder lead time first, e.g. 30 minutes, and provide visit instructions.
  8. Save and reopen settings to confirm values persisted.
  9. Confirm Doctor A's Service Provider profile has the correct recipient mobile, with country code.
  10. Inspect pending staging notifications before enabling the server gate. On the intended server set:
BOOKING_WHATSAPP_ENABLED=true env

Restart the backend using the project's normal deployment/service process. Starting only the Vite frontend does not run the booking notification worker; the worker starts through the backend server entrypoint. It checks approximately every 10 seconds, but that is not a delivery guarantee.

Pass: the app no longer reports server sending as disabled, the sender is linked, and the notification log is available. Keep the gate restricted to your staging sender/test recipients during this exercise.

#5. Understand what a passing message looks like

For each action, verify all three layers:

  1. Business record: correct booking, treatment, payment or proposal exists.
  2. Transport evidence: an outbox entry and Meta message ID/status can be correlated to that record and recipient role.
  3. Handset evidence: the intended person receives the correctly populated message and any link opens the correct record.

| Nexaflow status | Meaning and test action | | --- | --- | | pending | Queued; check worker/server gate if it persists | | sending | Claimed by worker; do not trigger another send | | accepted | Meta accepted the request; not yet proof of handset delivery | | sent | Sending status reported by WhatsApp | | delivered | Delivery reported; verify the intended handset too | | read | Read reported when available; do not require this for every pass | | blocked | No send attempted; inspect template, sender or configuration | | failed | Definite provider failure; inspect error and supported retry action | | unknown | Delivery outcome ambiguous; do not blindly resend | | skipped | Suppressed, e.g. opt-out, superseded reminder or missed window; inspect reason |

Notifications can arrive out of order or omit intermediate states. Do not require every run to visibly show every status. Missing read alone is not a failure.

#6. Run this first happy-path journey

Use one future booking for most of this sequence; create fresh bookings where the scenario needs it. Record evidence after every step.

| Case | Action | Required result | | --- | --- | --- | | E01 Inbound connection | Patient A sends a greeting | Correct agent receives it; response returns to A | | E02 Registration | Register synthetic Patient A using reception/QR flow | Correct registration message, patient ID and synthetic DOB go to A | | E03 Appointment | Book with explicit WhatsApp consent | Exactly one applicable confirmation; patient, doctor, date/time and location are correct | | E04 Appointment list | Search by A's name and mobile | Name and mobile remain visible, even in filtered results | | E05 Estimate | Open payment tracker and send estimate | Exactly one estimate; amount/range and currency correct; UI says queued until real delivery | | E06 Bill | Set INR 10,000, four instalments; enable bill checkbox | Bill shows 10,000 total, 0 paid, 10,000 balance; no payment is created | | E07 First payment | Record INR 2,500 with receipt checkbox enabled | One payment and one receipt; paid 2,500, balance 7,500; receipt URL opens on A's phone | | E08 Reminder | Create a booking more than 30 minutes away, then wait until the 30-minute threshold | One timely reminder; current doctor/date/time and instructions are correct | | E09 Reschedule proposal | Propose a future slot | A receives proposed time and working confirmation link; original slot is still booked | | E10 Confirm proposal | Open link and accept | Original slot released; new slot reserved; one patient and one doctor confirmation; calendars updated | | E11 Follow-up | Create another visit and manually link the ongoing treatment | Follow-up label; shared bill counted once; another instalment updates the same account | | E12 Unrelated visit | Book A with Doctor B for a different treatment | It does not show or charge the first treatment's payment account | | E13 Final payment | Pay the remaining balance on the treatment account | Correct cumulative paid, zero balance, settled status and matching receipt | | E14 Cancellation | Cancel a separate future appointment | Slot released; appropriate cancellation message; no duplicate confirmation/cancellation | | E15 Complete/no-show | Complete one visit and mark another no-show | Correct configured notification behavior and final booking states |

For E08, choose a slot around 35–40 minutes away for a 30-minute reminder, or prepare a future test slot appropriately. Do not move the production clock or lower the supported reminder lead time. A reminder more than 15 minutes late is intentionally skipped in this implementation.

Do not complete/cancel/reschedule a booking immediately after creating it during the initial confirmation test. A newer event can legitimately suppress an older unsent event. Test this suppression separately.

Booking conversation

Have Patient A send: “I would like an appointment with Doctor A tomorrow.” Verify the agent discovers actual availability, confirms the selected slot and patient identity, obtains the required confirmation/consent and creates one booking. Verify the slot in the admin UI. Do not pass this case based on an AI reply alone.

Repeat for an unavailable slot and two testers competing for the last slot. Exactly one appointment should reserve it; the other tester should be asked to choose another slot.

Guardian routing

Book a synthetic dependent with Patient B as guardian. Confirm the intended guardian receives notices and receipt/estimate messages, and Patient A is not notified by mistake. Change the booking contact and verify consent/contact routing is re-evaluated appropriately. Opening a link must not expose unrelated patient records.

STOP / START

  1. From A send STOP; verify acknowledgement.
  2. Trigger a fresh notification for A; expect suppression with RECIPIENT_OPTED_OUT.
  3. Verify B still receives its own notifications.
  4. From A send START; verify acknowledgement.
  5. Trigger a new event; expect delivery to resume.

Use new events for step 5. Do not assume START retroactively resends previously skipped messages. Also test UNSUBSCRIBE and RESUME; ordinary sentences containing “stop” should not be interpreted as the exact opt-out command.

YES / NO replies

Test recall campaigns separately: send one recall, reply YES, verify the booking link, select an available slot, then verify the booking/campaign state. Use another recipient to test NO and a preferred-time reply.

For a reschedule proposal, use its secure confirmation URL for the deterministic end-to-end test. A generic YES reply is not proof that a specific reschedule proposal was applied. Check the Known gaps section before signing off any reply-to-confirm claim.

#8. Run inside and outside the 24-hour window

Run the critical outbound cases twice:

  • Open conversation: tester messages the clinic immediately before the test.
  • Closed conversation: use a tester who has not sent the clinic a message for more than 24 hours. Do not send a greeting just before this run.

An outbound message from the clinic does not reset the customer's inbound-message window. Approved templates are the intended path for proactively sending these notifications. Changing a Nexaflow database timestamp is not a valid simulation of Meta's real messaging window.

Repeat appointment confirmation, reminder, estimate, bill, receipt and reschedule confirmation under both conditions. Add cancellation and recall to this run specifically to expose any remaining direct-text paths.

#9. Failure, recovery and isolation tests

| Case | Deliberate condition | Expected result | | --- | --- | --- | | F01 | Server gate off | No actual send; financial action reports not queued, not sent | | F02 | Module WhatsApp channel off | No actual send; booking/payment still saves correctly | | F03 | Missing financial template name | Explicit configuration error; no false delivery success | | F04 | Wrong template name/language or not approved | Blocked before send; visible error in notification log | | F05 | Wrong variable count/order | Count mismatch blocked; order checked on handset against expected values | | F06 | Unlink sender or disable agent-module link | Sender rejected; no other clinic's number used | | F07 | Invalid/missing patient or doctor mobile | Explicit failure/warning; no fallback to another person's number | | F08 | Receipt delivery fails | Recorded payment and balance remain correct; do not record the payment again just to resend a receipt | | F09 | Same confirmation request retried with same idempotency key | One booking mutation and one set of applicable notifications | | F10 | Meta redelivers same inbound message/webhook | No duplicate booking/payment/proposal application | | F11 | Delivered/read callback arrives before an older sent/failed callback | Final status does not regress | | F12 | Network timeout after dispatch | Unknown outcome; no automatic duplicate resend; late callback can resolve it | | F13 | Restart or two workers claim messages | No duplicate dispatch for one queued event | | F14 | Reschedule/cancel before old reminder sends | Old reminder suppressed; future reminder uses new time | | F15 | Finish/reschedule after payment receipt is queued | Receipt is not discarded merely because appointment lifecycle changed | | F16 | Same contact used in two staging clinics | Correct sender/module handles replies, opt-out and booking links; no cross-clinic mutations | | F17 | Invalid webhook signature | Rejected; no business mutation or status update | | F18 | Status persistence failure | Webhook is not falsely acknowledged as successfully persisted |

Use controlled test fixtures for transport faults, signatures, out-of-order callbacks and worker races. Keep manual handset tests for actual delivery, identity, wording and link behavior. Never replay signed production webhooks against production as a test.

#10. Troubleshooting by symptom

| Symptom | First checks | | --- | --- | | Sender absent in booking settings | WhatsApp number → intended agent → enabled booking-module link; owner match | | No outbox entry after financial action | Server gate, channel, dedicated template, recipient and returned error | | Pending indefinitely | Backend/worker running, sending gate, database access, worker logs | | Blocked | Exact approved template name/language, parameter contract, linked sender, opt-out reason | | Accepted but no delivery confirmation | Real handset receipt, Meta failure callbacks, webhook subscription and correct callback deployment | | Handset received it but log is stale | Signed status callbacks, sender/account/recipient/message correlation, persistence errors | | Patient got update but doctor did not | Doctor's stored mobile, selected doctor, event/channel settings and doctor outbox entry | | Nothing arrives inbound | Webhook verification AND account subscription/messages field; assigned agent; app/account access | | Receipt link fails | Public APP_URL/APP_BASE_URL, HTTPS host, route availability and receipt identity | | Works only after tester sends “Hi” | Possible direct-text dependency; repeat closed-window template test | | Wrong booking confirmed by YES | Separate recall vs reschedule context; inspect exact proposal/campaign and module scope |

For a blocked event, correct the captured template/account configuration and use the supported retry. Retrying does not rewrite the original recipient, template name or language. An event captured with the wrong values needs a deliberately corrected new notification; do not blindly repeat the financial action. Unknown outcomes are not retryable through the normal UI.

#11. Known gaps to treat as release checks

Code inspection identified these paths; the tutorial does not claim they are already live-tested:

  • The legacy cancellation service still contains a direct-text send in addition to booking lifecycle notification handling. Test closed-window cancellation and duplicate-message behavior explicitly.
  • Recall campaign dispatch still uses direct text. Do not assume proactive recall delivery outside the 24-hour window is solved by configuring the new financial templates.
  • The webhook explicitly handles recall replies and STOP/START. There is no dedicated reschedule-proposal YES/CONFIRM handler in that dispatch path; verify link-based rescheduling, and treat plain-reply confirmation as an unverified feature/gap.
  • The current inbound webhook dispatch selects the first inbound message from a received batch. Include multi-message batch tests; complete outbound-status batching is not proof of complete inbound-message batching.
  • Recalls look up a recent recipient by phone suffix. Cross-clinic reply attribution must be tested; do not sign off tenant isolation based solely on separate sender numbers.
  • A treatment bill on saving a plan is not a scheduled instalment-due reminder. Automatic payment-pending/due-date schedules need their own trigger/template tests when implemented.
  • Developer test assets and passing mocks are not proof of production app/account access or handset delivery.

#12. Sign-off criteria and repeatable regression

Sign off only when:

  • All critical happy paths pass with business state, message correlation and handset evidence.
  • Critical template sends pass inside and outside the 24-hour window.
  • Patient and doctor recipients are independently verified, including guardian and unrelated-treatment cases.
  • No duplicate messages or duplicate financial/booking mutations occur in retry tests.
  • Failures are honest: no “sent” claim for disabled, blocked or unconfigured sending.
  • Outstanding gaps are recorded as defects or explicitly excluded from release scope.

Run the unit tests after changes to communication code. Example from the repository root:

npm test -- tests/unit/TransactionalWhatsApp.test.ts tests/unit/BookingPaymentService.test.ts tests/unit/BookingRescheduleService.test.ts tests/unit/BookingCommunicationSettings.test.ts tests/unit/BookingWhatsAppDelivery.test.ts tests/unit/BookingWhatsAppRegression.test.ts bash

Frontend checks:

cd frontend npm run test:run -- src/components/modules/booking/BookingPaymentTracker.test.tsx src/components/modules/booking/BookingReschedule.test.tsx src/components/modules/booking/BookingWhatsAppSettings.test.tsx src/components/modules/booking/BookingNotifications.test.tsx bash

Database integration tests require a dedicated DATABASE_URL_TEST and run sequentially because setup resets the test schema. Do not point the test runner at a live clinic database. Re-run the short real-handset smoke journey after deployment, sender reconnection, template changes or webhook changes.

Suggested execution order

Session 1: connection, inbound/outbound smoke, general template, registration and booking. Session 2: estimates, bills, receipts, reminders and link-based rescheduling. Session 3: guardian, STOP/START, recalls, failure recovery and isolation. Next day: closed-24-hour-window repetitions and release sign-off.

#Official references

Application details above were checked against the repository; Meta screen labels and account eligibility should be verified against the current dashboard and documentation.

Helpful for you?

Help us improve the world of AI agents.

Keep Learning

View All Guides