docs
/
AI skills

WhatsApp messaging

WhatsApp on one of the business's numbers — turned on with its display name, templates written and sent to WhatsApp for approval, the 24-hour rule for free text, STOP replies, one message or a reply from the Inbox, a broadcast saved as a draft, and the AI answering. Nothing is sent without a yes.

WhatsApp runs on the business's own phone numbers, through the same phone service as calls and texts. A number gets a WhatsApp sender with the business's display name. Messages, replies and broadcasts all go from a number that has WhatsApp on.

Two WhatsApp rules decide every send:

RuleWhat it means
The 24-hour windowFree text (and pictures) can go to a customer only within 24 hours of their last WhatsApp message to the business. Outside it, only an approved template can be sent.
Templates are approved by WhatsAppA template is submitted and reviewed by WhatsApp before it can be used. Its text can't be changed after; a change is a new submission.

Every WhatsApp message reaches a real person and costs money. This skill builds and checks; a person says yes before anything is sent.

Ask first

  • Which number? One the business bought through the phone service (Phone & SMS). WhatsApp can't be turned on for a number added from elsewhere.
  • The display name customers will see at the top of the chat. It must match the business's name.
  • Has the business linked its WhatsApp Business Account? If the phone service says it isn't linked, the person does a one-time sign-up with Meta (step 1). The AI can't.
  • What will be sent? Replies to people who write in, or messages the business starts (reminders, updates, offers). Starting a conversation needs a template.
  • Have these people agreed to get WhatsApp messages from the business? For a broadcast, if the answer isn't a clear yes, stop.

Steps

1. Phone & SMS: turn WhatsApp on

Find the number: find_records on phone by data.phoneNumber. WhatsApp lives in data.whatsapp, not in capabilities:

data.whatsapp.statusScreen pillMeaning
none, or offOffnot turned on (reason may say why)
pendingPending approvalWhatsApp is approving the number, usually a few minutes
onOnit can send and receive
failedNeeds attentionreason says what to fix

call_appengine GET /phone/whatsapp/numbers lists the numbers with WhatsApp on.

To turn it on, after a yes: call_appengine POST /phone/whatsapp/enable/<phone sk> with { "displayName": "<business name>" }. It registers the number as a WhatsApp sender, with the number's own text webhook for replies. A failure still answers 200, with status: "failed" and the reason saved on the number. Read it:

reason (shortened)What to do
Enter the business name customers will see in WhatsApp.send displayName
WhatsApp can only be turned on for numbers bought through the phone service.use a number bought on Phone & SMS
This phone account isn't linked to a WhatsApp Business Account yet…the person does it: finish Meta's WhatsApp Business sign-up for their phone account, then press Turn on WhatsApp again
the display name doesn't match the businesschange displayName to the business's name

GET /phone/whatsapp/status/<phone sk> asks again and saves the answer. A sender WhatsApp has removed goes back to off: This number is not registered for WhatsApp any more. Press Turn on WhatsApp to register it again.

Hands on: the number in + form, with whatsapp.status = on. Check: on Configuration › Phone & SMS (/phone-system), the number's WhatsApp card shows On, with Display name, Turn on WhatsApp and Check status. Broadcast › Channels › WhatsApp (/broadcast?tab=channels&channel=whatsapp) lists every number with its state.

2. Message Templates: the templates, approved

Anything the business starts, and anything sent more than 24 hours after the customer last wrote, must be an approved template. Make one per kind of message (a booking reminder, an order update, an offer).

Create a message_template with create_record:

FieldValue
namee.g. booking-reminder
deliveryTypewhatsapp (or a list including it)
textthe body, at most 1,024 characters, with numbered placeholders {{1}}, {{2}}… in order from {{1}}. Named ones ({{firstName}}) are refused.
whatsapp.categoryUTILITY (updates about something they asked for; the default), MARKETING (offers) or AUTHENTICATION (codes). WhatsApp reviews each differently; an offer sent as UTILITY is rejected.
whatsapp.languagee.g. en (the default)
whatsapp.headeroptional { type: "text" | "image" | "document" | "video", text, mediaUrl }
whatsapp.footeroptional short line
whatsapp.buttonsoptional [{ type: "quick_reply" | "url" | "phone", text, url, phone }]

Stop: submitting sends the template to WhatsApp for review. Show the text and category, then wait for yes. Then call_appengine POST /crm/message-template/whatsapp/submit/<template sk> with { "samples": { "1": "Ada", "2": "Friday 3 pm" } }. Real-looking samples help it pass. Without them, each placeholder is sent as "example n".

  • whatsapp.approval.status becomes pending, then approved or rejected (with reason). A template WhatsApp pauses or disables reads rejected with its reason.
  • Resubmitting an unchanged rejected template is refused (409, "…Change the template before submitting it again."). Change the words, then submit again.
  • GET /crm/message-template/whatsapp/status/<template sk> asks where it stands now.

Hands on: each approved template's sk (or name). Check: open it on Message Templates (/message-template). The WhatsApp section shows Pending approval, Approved or Rejected, with Submit for WhatsApp approval and Refresh status.

3. IVR & Phone System: STOP replies

WhatsApp replies go through the number's SMS routing, the same as texts. A STOP is recorded only when the number has an enabled sms_routing with optOut.enabled. The words are STOP, UNSUBSCRIBE, CANCEL, END and QUIT by default; START, SUBSCRIBE or YES undo it. A STOP from one number counts for both texts and WhatsApp, for a year. Check it as in SMS broadcast to a group, step 3. Setting one up changes how the number answers, so it is the person's decision.

The same routing's auto-replies and keywords answer WhatsApp messages too. If it has a text auto-reply, WhatsApp customers get it.

Hands on: whether STOP replies are recorded for this number.

4. Inbox: one message, or a reply

Customers' WhatsApp messages land in Inbox (/inbox) as conversations on the WhatsApp channel, saved as message records (deliveryType: "whatsapp", direction: "inbound", with profileName, their WhatsApp name).

Before writing, check the window: call_appengine GET /crm/inbox/whatsapp-window?to=<customer +number>&from=<business +number> answers { open, lastInboundAt, closesAt }. The window counts only messages to that business number. Without from, it counts any of the business's numbers.

  • Open: free text, with pictures if wanted.
  • Closed: only an approved template (step 2). Don't send free text: it is refused with This customer last wrote more than 24 hours ago — WhatsApp only allows an approved template now. (reason: whatsapp_window_closed).

Stop: show the customer, the business number, the words (or template and its values), and the cost, then wait for yes. Then call_appengine POST /crm/inbox/update?send=true with:

{ "data": {
  "deliveryType": "whatsapp",
  "to": ["+12145550142"],
  "from": "+12145550100",
  "text": "Hi Ada, your table for 4 is ready.",
  "media": [{ "url": "https://…/menu.jpg" }]
} }

For a template, send "template": { "contentSid": "<whatsapp.contentSid>", "variables": { "1": "Ada" } } instead of text. Staff send from the Inbox; the same call is what its composer uses. A number without + takes the sending number's country code.

What one message costs on the platform's shared phone account (the business's own rates are on Service rates):

KindDefault price before markupWith the default 100% markup
free text inside the window$0.005$0.01
a template$0.03$0.06

Hands on: the message's sk. Check: the message shows in the conversation, pending then sent. A late failure is written onto the message (status: "failed", its reason in statusHistory). Common ones, in the person's words:

ReasonMeaning
This number isn't turned on for WhatsApp yet…step 1 isn't finished
This customer has stopped receiving business messages on WhatsApp…reach them by text or email instead
…WhatsApp only allows an approved template now.the window closed before it went

5. Broadcast: a WhatsApp draft to a group

Find the group as in SMS broadcast to a group, step 1. Count it with POST /broadcast/audience/count and { "lists": ["<group sk>"], "channel": "whatsapp" }, and ask who is left out with POST /broadcast/audience/people and "show": "out". The same rules as SMS apply: one message per number, no number, STOP, and US/Canada for a number without +.

Create an email_broadcast with create_record:

FieldValue
namethe campaign's name
channelwhatsapp
whatsappConfig.templateIdthe approved template's sk or name
whatsappConfig.variablese.g. { "1": "{{firstName}}" }, filled per person
whatsappConfig.fromthe business number, + form
recipientMethod / selectedListslists / ["<group sk>"]
statusdraft

A broadcast with a template sends the template to everyone. A broadcast with only a message (whatsappConfig.message or content) sends it only to people whose window is open; everyone else fails with whatsapp_window_closed. For a group, always use a template.

Never set status to pending or scheduled, add a schedule, or call POST /broadcast/<id>/send.

Hands on: the broadcast's sk. Check: read it back (status: draft, type: whatsapp) and open it (/broadcast?openId=<sk>). Its WhatsApp section shows WhatsApp template, Fill in the template and Message for recent conversations (optional).

The composer says the optional message goes to people who wrote in the last 24 hours. It doesn't: when a template is set, everyone gets the template and the message is not used. Don't promise the person otherwise.

Stop: send the broadcast

Show the template exactly as each person will see it (with a real name filled in), the number it comes from, the group and its count, who is left out and why, whether STOP is recorded, and the cost: people × the template price. Confirm these people agreed to get WhatsApp messages. A person presses Settings & Send → Send Now (or schedules it). If they say "send it" in chat, repeat the count and cost, and send only after a clear yes.

6. The AI on WhatsApp (optional)

  • An AI assistant answers WhatsApp when the number's SMS routing hands messages to it, or when the business has no routing at all and an assistant listens on whatsapp. Set it up with AI assistant for the website chat or a phone line.
  • An AI employee listening on whatsapp gets each inbound message as a job (WhatsApp from (+1…)), with pictures attached. See Give an AI employee a standing job.
  • Their tools: reply_to_conversation answers on the channel the customer used, and send_whatsapp (to, message or templateId with variables, mediaUrls, from) starts one. Both obey the window: outside it, they need an approved templateId.

When it's done

Tell the person:

  • the number and its WhatsApp state, and the display name;
  • each template, its category and approval state;
  • whether STOP replies are recorded;
  • what was sent, to whom, and what it cost; or the broadcast waiting as a draft, its count and cost;
  • what's waiting for them: Meta's sign-up, a template in review, pressing Send.

What it can't do yet

  • WhatsApp only through the phone service. Connecting a WhatsApp Business number directly through Meta isn't supported. WhatsApp messages Meta sends straight to Appmint are ignored.
  • STOP needs an SMS routing. Without one with opt-out on, a STOP isn't recorded. A broadcast leaves out recorded STOPs; a single message from the Inbox or the AI doesn't check them.
  • No consent record. Nothing stores that a person agreed to WhatsApp messages.
  • A broadcast's "message for recent conversations" isn't sent when a template is set (see the warning in step 5).
  • Templates can't be edited. A change is a new submission and a new review.

Don'ts

  • Don't send free text when the window is closed, and don't retry a refused send as free text.
  • Don't put a marketing offer in a UTILITY template.
  • Don't use named placeholders like {{firstName}} in a template's text. Map them in variables instead.
  • Don't send, submit a template or turn WhatsApp on without a yes.
  • Don't message people the person hasn't said agreed to it.