Skip to main content
This guide adds a “Send on WhatsApp” button to your CRM or admin panel. The button sends an approved template to a phone number. When the number has no conversation in Kai, the send opens one. WhatsApp accepts free text only in the 24 hours after the customer’s last message. Outside this window, and for a first contact, WhatsApp accepts only a template that Meta approved. This is a rule of Meta, not of Kai. The key for this guide needs the messages:send permission. This permission includes templates:read and conversations:read.

1. Find the channel

Read the channel list once and store the id of your WhatsApp channel:
When the workspace has one WhatsApp channel, you can omit channel_id in the next steps. Kai finds the channel for you.

2. List the templates, with hints

Ask for the templates when your user opens the send window. Add the email address of the teammate that sends the message, and the customer:
The response holds only the templates that you can send. variables names the placeholders, in the order that your send must fill them.

Templates with a title

A template can have a title above the message. WhatsApp shows the title in bold on the first line. header holds the title, or null when the template has none. The title can have its own variables, and Kai fills them. WhatsApp numbers and names the variables of the title and of the message separately, so {{1}} in the title and {{1}} in the message are two different values. Each variable therefore has an address, which is the name you use when you send: The variables field lists these addresses in the order that a send fills them: the variables of the title first, then the variables of the message. Each hint also holds part, which is header or body, so you can group your inputs.
Kai cannot send a template with an image, a video or a document title, because that title needs a file and not a value. Kai also cannot send a template with a variable link in a button. These templates are absent from the response. Add status=all to see them, where sendable is false.

Use the hints

Each entry in variable_hints tells you how to fill one input:
  • A value that is not null is the value that Kai would use. Prefill your input with it. Your user can change it before they send.
  • A value of null means that Kai cannot fill this variable. Ask your user for it, and do not send until they answer.
binding says where the value comes from. agent_name reads the profile of the teammate in agent. customer_name reads the contact. free means that a person types it every time. The workspace configures a binding under Settings → Channels. Kai guesses one from the name of the variable when nobody configured it, so {{consultant_name}} and {{customer_name}} work without setup. An agent address that no member holds returns "agent": null and empty hints for the agent variables. Read this field when you debug an empty input.
Kai never fills a variable at send time. The send needs every value. Your form is what the person reads before the message leaves, so a value that Kai adds after that screen is a value that nobody approved.
Kai mirrors the template library of the channel. To add or change a template, use the WhatsApp Manager of Meta, then sync in Kai under Settings → Channels.

3. Send the template

Send the values from your form, which hold the hints or the changes that your user made. Every variable is required.

Two shapes for the values

A template that names its variables accepts an object, as above. The keys are the addresses from step 2. Kai puts the values in the order of the template, so you do not need to know that order. A template that numbers all of its variables ({{1}}, {{2}}) accepts an array, in the order of the variables field from step 2. The values of the title come first:
An array also works for a named template. But then your values follow the order of the template, and somebody can change that order in the WhatsApp Manager of Meta. Two values that change places are still two strings, so nothing fails and the customer reads the wrong name. Use the object for a named template. Kai refuses a variable name that the template does not hold, and names it in the error. A misspelled name is a fault in your integration, not a value to drop. A plain name is always a variable of the message: to fill a variable of the title, you must write header. in front of it. One call does all of it. Kai finds or makes the conversation for the number. Kai finds or makes the contact behind it. Kai fills the title and the body of the template from its mirror and sends. Then Kai assigns the conversation to the assignee. You must set opt_in_confirmed to true on every call. This is your assertion that this person agreed to receive your messages. Kai stores the assertion on the message.
existing_conversation is true when the thread already existed. Then the message joined that thread, and no second thread exists. You can also name the person with "to": { "contact_id": "..." }. Kai then uses the phone number that the contact holds. A contact without a phone number returns a no_phone error.

4. Retry safely

A send costs money and reaches a person. Send an Idempotency-Key header with a unique value per intended message.
  • When a call with the same key already succeeded, Kai returns the stored response and does not send again.
  • When the first call failed, Kai releases the key. Your retry runs.
  • When the first call still runs, Kai returns a 409 idempotency_in_flight error. Retry after a moment.
  • The same key with a different body returns a 422 idempotency_mismatch error. Use a new key for a new message.

5. Decide who answers the reply

The send itself does not decide who handles the conversation. The assignee field does.
  • With assignee, the conversation belongs to that teammate. Kai does not answer on an assigned conversation. The reply of the customer waits in the inbox of that teammate, and in their Element X rooms.
  • Without assignee, the conversation stays with the reply policy of the channel. When the channel runs on autopilot, Kai can answer the customer.
Name an assignee when a person must handle what comes back, for example a sales call. Omit it when Kai can handle the reply, for example a payment reminder.

Errors

For the error format and the general codes, see Error handling.