Zodiac Tech CRM Docs

WhatsApp automations

Send approved WhatsApp templates automatically from the automations engine — triggers, the send_whatsapp action, guard-chain failure codes and opt-out handling.

admin manager super-admin Medium ⏱ 15 min Updated 2026-10-05

WhatsApp automations

Once WhatsApp is connected and you have at least one approved message template, you can send it automatically. The automations engine supports a send_whatsapp action that attaches a template to any trigger — a new lead, a stage change, an appointment reminder, and more.

Who this is for

  • Admin or Manager building follow-up flows.
  • Super Admin diagnosing why an automation's WhatsApp step failed.

Difficulty: Medium · Time: about 15 minutes · Prerequisites:

  • WhatsApp connected (Settings → Connections → WhatsApp) and healthy.
  • An approved template (see Message templates).
  • The automations permissions for your role.

Step 1 — Create the automation

  1. Open Automations (/admin/automations) and click New automation.
  2. Give it a name and choose a trigger:
Trigger Fires when
New Lead Received A lead is created (any source)
Lead Stage Changed A lead moves stage in the sales process
Lead Assigned to User Routing assigns a lead to a salesperson
Tag Added to Lead A tag is attached
Lead Score Crosses Threshold Score-based hand-raise
No Activity (Time-based) A lead goes quiet for the configured period
Date Reached (birthday / anniversary) A lead date field is due (checked daily at 07:00)
Form Submitted A Meta lead form submission is ingested
Manual Trigger Only when fired by hand — great for testing
Appointment booked A booking is created
Appointment approaching Swept every 5 minutes; choose the lead time — 1, 3, 6, 12 or 24 hours before (default 24)
Follow-up due Swept every 5 minutes; fires when a follow-up task reaches its due time
  1. Optional conditions (stage, tag, source…) narrow when the automation runs.

Step 2 — Add the send_whatsapp action

  1. Add an action and choose Send WhatsApp.
  2. Pick a template from the template selector. The dropdown lists only templates that are approved (Meta-approved, or a legacy local template that is still usable). If the list is empty, approve a template first.
  3. The CRM shows a variable preview under the selector — the tokens each placeholder will be filled with, resolved from the template's mapping. You do not retype variables per automation.

Legacy automations keep working Automations created before the managed-template flow used mode: text (a free-text message with {{first_name}}-style tokens) or mode: template with a name, language and manual parameter rows. Those fields still render when no managed template is selected, so older automations stay editable and saveable.

Step 3 — Test it

  1. Set the trigger to Manual Trigger (or use the trigger's natural event with a test lead from Test your setup).
  2. Run the automation — with the local sync queue it executes immediately; in production it is picked up by the worker within a minute.
  3. Open Automations → Run history on the automation row to see the run and each step's outcome.

Step 4 — Understand failures before they confuse you

The send_whatsapp action verifies conditions at send time in a fixed guard order. The first guard that fails becomes the step's failure_code:

Order Failure code Meaning
1 TEMPLATE_UNAVAILABLE The chosen template no longer exists (deleted locally)
2 TEMPLATE_NOT_APPROVED The template is not approved anymore (rejected/disabled/paused)
3 OPTED_OUT The lead sent a STOP keyword — deliberately skipped
4 WHATSAPP_NOT_CONNECTED The workspace's WhatsApp connection is missing or disconnected
5 NO_VALID_PHONE The lead has no usable phone number
6 MISSING_TEMPLATE_VARIABLE A mapped token has no value at send time
7 MEDIA_NOT_FOUND The template needs media the CRM cannot locate
— WHATSAPP_ERROR The queue call to Meta failed unexpectedly

Opt-out skips are silent by design When the lead has opted out, the run skips the step with OPTED_OUT and writes no CRM message row or timeline entry — that is policy, not a bug. Every other failure writes a failed LeadMessage with its failure_code, visible in the lead's message history and the run history. The action never throws — a failure can't break the rest of the automation.

Opt-outs (STOP keywords)

If a lead replies with an opt-out keyword, the CRM automatically flags them:

  • Default keywords: stop, unsubscribe, do not message.
  • Matching is exact after normalisation (lowercased, punctuation/spacing removed) — "Please STOP." matches, "stopping by later" does not.
  • On match, the lead is marked opted out (whatsapp_opted_out_at, source inbound_keyword) with a reason, and a timeline entry on the lead.

No dedicated keyword screen (yet) The keyword list has no settings screen in the UI today. It lives in the tenant setting automation.whatsapp_optout_keywords; a Super Admin can change it per workspace. Treat this as an operator change, not self-service.

Expected result

The automation fires on its trigger and the lead receives the approved template from your business number. The run history shows a successful step; failures show one of the codes above so you know exactly which guard failed.

Common mistakes

  • Choosing a template, then editing it on Meta. If Meta rejects/disables it later, sends fail with TEMPLATE_NOT_APPROVED — pick another approved template.
  • Sending free-form expectations. Automations always send a template; free-form chat happens manually from the inbox inside the 24-hour window.
  • Testing with a lead whose phone is empty → NO_VALID_PHONE.
  • Forgetting the worker. With QUEUE_CONNECTION=sync (local) sends run inline; in production a queue worker must run or automations sit in the queue — see Cron & queue workers.

Troubleshooting

Symptom Likely cause Fix
Step shows TEMPLATE_UNAVAILABLE Template deleted from the CRM Re-create and resubmit; reselect in the automation
Step shows TEMPLATE_NOT_APPROVED Meta disabled/rejected it Check Message templates statuses
Step shows MISSING_TEMPLATE_VARIABLE A mapped token (e.g. appointment.date) has no value — e.g. no upcoming appointment Check the lead's data; appointment tokens read the next upcoming confirmed/scheduled/pending booking
Nothing happens at all No worker in production Run the scheduler + worker per Cron & queue workers
Reminders fire at the wrong time appointment_approaching lead time is wrong Edit the trigger config (hours before: 1/3/6/12/24)

Technical details

  • Action class: SendWhatsAppAction (registered as the send_whatsapp automation action); failure propagation via pullLastFailure().
  • Sends are queued as LeadMessage rows and dispatched by the SendLeadMessage job.
  • Sweeps that drive time-based triggers: CheckAppointmentApproaching and CheckFollowUpDue every 5 minutes; date_field daily at 07:00 — all registered in routes/console.php, so the scheduler must run every minute.
  • Opt-out handling: WhatsAppMessageService::maybeOptOut(); flags persist on the lead (whatsapp_opted_out_at, whatsapp_opt_out_source, reason + timeline entry).
  • Run visibility: AutomationRunHistory page per automation; failed steps carry the guards' codes.

Was this page helpful?