WhatsApp via Twilio
WhatsApp messaging via Twilio for customer notifications (repair-ready, bespoke-ready) and employee task assignment. The integration runs on a platform-level Twilio account so no per-tenant setup is required. Mechanically shipped end-to-end; the customer-facing channel routing is in a meaningfully partial state versus the intended product design — that disclosure is in the section below.
Quick reference
- WhatsApp messages send via a platform-level Twilio account that Nexpura maintains — there's no per-tenant Twilio configuration. You don't enter credentials, you don't pay for a Twilio subscription, you don't need a Meta Business Account.
- Per-tenant configuration is the on/off toggles for each notification category on /settings/notifications — job-ready notifications to customers, task assignment to employees, status change to employees, urgent flag to employees. Each toggle persists in the tenant's notification settings.
- The notification mix today:
- Customer-facing job-ready notifications fire as WhatsApp (see honest disclosure below — this is where the partial state lives).
- Employee task-assignment notifications fire as WhatsApp (rich formatting, native app).
- Employee status-change and urgent-flag notifications fire as SMS (concise, with smart AU/US number selection).
- Every send is logged in
whatsapp_sendsorsms_sends(depending on channel) with the Twilio message ID, status, and any error returned by Twilio. Useful for ops when a customer says “I didn't get the ready message”. - Phone-number normalization runs server-side before Twilio gets the value. Inputs like “0412 345 678”, “(02) 9876-5432”, “+61 412 345 678” all normalise to E.164 (
+61412345678). Default country is AU.
How notifications fire
1. Customer notification — repair / bespoke ready
When a repair or a bespoke piece is marked ready for pickup, the system reads the customer's phone number off the customer record, checks that job-ready notifications are enabled for the tenant, and fires a message through Twilio.
The message body is templated:
Hi {customer name}! Great news — your {repair | order} is ready for pickup at {business name}! {job description}. See you soon!
The send result lands in the whatsapp_sends log with one of three outcomes — sent (Twilio accepted, message dispatched), failed (Twilio rejected — most commonly because the recipient doesn't have WhatsApp installed, or the number doesn't resolve in the WhatsApp directory), or a network error (Twilio unreachable). The log row exists either way; ops visibility is preserved.
2. Employee notification — task assignment
When a repair, bespoke job, or other task is assigned to a team member, the system looks up the assignee in team_members, confirms their phone number is on file and their per-user whatsapp_notifications_enabled flag is on, and fires a WhatsApp message.
The message body:
🔔 New {repair | bespoke job | task} assigned: {description} {— customer name if present}{newline Due: {due date} if present}
WhatsApp is the chosen channel for assignments because the format supports newlines and emoji cleanly, the notification appears as a chat from the business's ops account, and the staffer can reply or react in the same surface they get the message.
3. Employee notifications — status change and urgent
Status-change notifications (a customer-facing item moved from in-progress to quality check, etc.) and urgent-flag notifications (a repair was flagged urgent) fire as SMS rather than WhatsApp. The rationale is operational: these notifications need to be concise (a one-line summary) and high-reliability (delivery confirmed by the carrier, not gated on whether WhatsApp is installed). SMS is the right channel for both qualities.
The same per-team-member opt-out applies — a staffer who's turned off WhatsApp notifications in their settings is also opted out of these SMS notifications. The on/off control is unified at the staff member level; the channel split is per-notification-type.
4. Configure the toggles
Open /settings/notifications. Four tenant-level toggles control which notification categories fire:
- Job ready — customer notifications when a repair / bespoke is ready for pickup
- Task assignment — employee notifications when work is assigned to them
- Status change — employee notifications when an item they own moves between statuses
- Urgent flagged — employee notifications when an item is flagged urgent
Each toggle defaults to on. Owners and managers can flip them; staff roles see them but can't change them. Each team member also has an individual whatsapp_notifications_enabled flag on their team-member record — that's their personal opt-out, independent of the tenant-level toggles.

Honest disclosure
The integration mechanically works — Twilio is wired up, messages send, sends are logged, the failure paths are observable. The piece that's in a partial state is the channel routing for customer-facing notifications, which is the most-used surface of the integration.
What ships today
Every notification path described in the walkthrough above is wired up and reliable on the technical side. Twilio sends fire; Twilio responses are captured; failure-mode visibility is in the whatsapp_sends and sms_sends log tables with the per-send Twilio error code and message. Phone-number normalization (E.164, with AU as the default country) handles the common operator-entry shapes. Sandbox / preview environments suppress real sends so testing doesn't bother real customer phones.
Employee notifications — task assignment via WhatsApp, status change and urgent flag via SMS — match the intended product design end-to-end. Per-tenant on/off toggles work; per-team-member opt-outs work; channel split between rich-format WhatsApp for assignments and concise-SMS for status changes works as designed.
What's not aligned with intended state
Customer-facing job-ready notifications fire as WhatsApp messages via Twilio. The intended product design — captured in PR #81 on 2026-04-30 — is for customer-facing notifications to ship as SMS, not WhatsApp. The reasoning is delivery reliability: WhatsApp messages only land if the customer has WhatsApp installed and the number is registered to the WhatsApp directory. SMS lands on any phone that can receive a text — which is essentially every phone.
The practical effect today: jewelers' customers without WhatsApp installed don't receive the ready-for-pickup notification. The send goes out, Twilio either rejects it (number not on WhatsApp) or dispatches it to a number that never reads it (older customer who doesn't use WhatsApp). Either way, the customer doesn't know the piece is ready. The repair sits in the case waiting; the customer assumes nothing's happened yet.
This routing inversion is on the product fix-pile. The fix is the SMS channel for customer-facing notifications (the same way status-change / urgent-flag employee notifications already ship as SMS). When that ships, the customer-facing surface flips channel and every customer with a working phone number receives the notification — the WhatsApp dependency disappears.
Workaround until the routing flips
Two practical mitigations cover the gap. First, when you collect a customer phone number at intake, confirm it's a WhatsApp-capable number — most modern smartphones are, but older customers and some business numbers aren't. The intake conversation that captures the phone is the right moment to surface the dependency, since the alternative (a phone call when the piece is ready) needs to be set as the expectation upfront if WhatsApp won't reach them.
Second, track non-WhatsApp customers separately so they get the call rather than relying on the notification. A custom tag on the customer record (“ no-whatsapp” or similar) plus a query at job-ready time to flag those customers for the manual phone-call path keeps the operational coverage even while the notification routing is wrong. Some stores handle this by defaulting to a manual call regardless and treating the notification as a supplementary channel — which works fine and is what most pre-Nexpura shops did anyway.
The deeper diagnostic of the customer-side experience when the notification doesn't reach them lives on the problem page at The repair that never gets picked up — the same gap framed for the store owner evaluating Nexpura, with the customer's side of the experience walked through. Talk to us if these are load-bearing for your store.
Common questions
Do I need a Twilio account?
No. WhatsApp / Twilio is a platform-level integration — Nexpura runs a Twilio account and pays for the message sends. There's no per-tenant Twilio subscription, no API keys to manage on your side, no Meta Business Account to register.
The trade-off: tenants share the platform Twilio number for outbound. The customer sees the message as coming from a Nexpura-controlled WhatsApp number, not from your shop's own number. The message body identifies your business name explicitly, so the customer knows who the message is from; the sender number is just the carrier.
Why are employee task notifications WhatsApp but status-change notifications SMS?
Different operational needs. Task assignment is a human-facing message — the staffer reads “ you've been assigned this repair”, may reply to acknowledge, may share the message with a colleague. The rich-format channel (newlines, emoji, long body) and the reply-in-place affordance of WhatsApp matches that interaction.
Status changes and urgent flags are more like alerts — short, system-driven, “X moved to Y, act if you need to”. They benefit from the terse, carrier-guaranteed delivery of SMS. The choice isn't arbitrary; each channel is suited to the kind of message it carries.
How do I know if a specific notification went out?
The send is logged in the whatsapp_sends (or sms_sends) table with the recipient phone, the message body, the status, and the Twilio message ID. Today this is a backend table — there's no first-class notification log surface in the product.
Practical workaround: contact us with the customer name and the rough time of the expected notification. We can read the corresponding log row, confirm whether Twilio accepted the send, and tell you the specific status (sent, failed with this error code, never attempted because some upstream gate said no). A first-class “Notification log” surface within the product is on the roadmap.
A customer changed their phone number — does the new one start getting notifications automatically?
Yes. The notification dispatch reads the current phone number off the customer record at send time. Update the customer record with the new number (normalisation runs on save so any input shape works), and the next ready-notification fires to the new number. The history of sends to the old number stays in the log table; the routing is forward-looking from the moment of the change.
The opposite case — a stale number that no longer works — is the failure mode that'll show up in the log as a Twilio error code (typically 21211 for an invalid number or 63003 for a number not on WhatsApp). The log is the cleanest place to spot stale-number patterns before they cause a missed pickup.
Troubleshooting
Customer didn't receive the ready-for-pickup notification
Symptom: the repair / bespoke is marked ready, the customer says they never got a notification. Cause: today's most common cause is the routing gap documented in the honest disclosure above — the customer doesn't have WhatsApp installed, or the number isn't on the WhatsApp directory. Less commonly: the job-ready toggle on /settings/notifications is off, the customer has no phone number on file, or the phone number is malformed in a way normalisation can't rescue (extra characters like “ext” or letters). Fix: short-term, call the customer. Longer-term, follow the workaround in the honest disclosure section — flag customers as no-whatsapp at intake and default to a phone call for them. When the SMS routing ships, the underlying gap closes.
Employee says they're not getting WhatsApp task notifications
Symptom:a staffer is assigned work and doesn't receive the WhatsApp message. Cause: three candidates. (1) The staffer's per-team-member whatsapp_notifications_enabled flag is off. (2) Their phone number on the team-member record is empty or wrong. (3) The tenant-level Task Assignment toggle is off. Fix: check all three: open /settings/team, find the staff member, confirm phone number and the per-user flag. Then open /settings/notifications and confirm the tenant-level toggle is on. Both gates have to be on for the send to fire.
Sends are failing with Twilio code 63007 in the log
Symptom: thewhatsapp_sends log shows a series of failures with code 63007 ( “no Channel with this From address”). Cause: platform-level — the Twilio WhatsApp number isn't correctly configured. Not a tenant-side issue. Fix: contact us. This is operational on Nexpura's side; we'll check the platform Twilio config and verify the channel binding. While that's being investigated, customer-facing notifications won't send to anyone — important to know so you can default to the manual phone-call path until we confirm it's back.
The phone number on a customer is valid but normalisation rejected it
Symptom:a specific customer's phone send fails with “Invalid phone format” in the log. Cause:the normaliser couldn't E.164-format the value. Common reasons: the number has letters (“1300 ABCD”), the number has an extension (“5555 ext 12”), the number is too short or too long for any reasonable mobile format, the country code is non-AU and the normaliser's AU default didn't apply correctly. Fix: edit the customer record and re-enter the phone number in a recognisable format — preferably E.164 directly (+61412345678) but a clean local format like “0412 345 678” also works. Drop extensions; the customer's direct mobile is what WhatsApp needs.
I want to opt one staff member out of WhatsApp notifications entirely
Symptom:a staff member doesn't want any WhatsApp notifications regardless of category. Cause: N/A — this is a configuration question. Fix: open /settings/team, find the staff member, set their WhatsApp notifications enabled flag to off. The per-user flag is the universal opt-out — once it's off, no task assignment, status change, or urgent-flag notification fires for that staff member, regardless of the tenant-level toggles.
Related
- Related: The problem this solves — “The repair that never gets picked up” — the customer-side framing of the same notification-routing gap this page is the operational counterpart to
- Integrations & data overview — the broader integration lifecycle and where this sits in the data model
- Repair pipeline — the workflow that triggers customer-facing job-ready notifications
- Customer-facing repair tracking — the self-service surface the customer uses when the notification doesn't reach them