Getting started with messaging#
The Messaging endpoints let your software send WhatsApp messages to your customers through Chronox. Every message you send appears in the customer's conversation in the Chronox inbox, just as if a team member had sent it.There are two ways to send a message:| Endpoint | What it sends | When you can use it |
|---|
| Send Whatsapp Message | A normal message: text, or a file such as an image or document. | Only within 24 hours of the customer's last message to you. |
| Send Whatsapp Template | One of your Meta-approved templates. | Any time, including to start a new conversation. |
WhatsApp's 24-hour rule#
When a customer sends you a message, WhatsApp opens a 24-hour window. During that window you can reply with normal messages. Each new message from the customer restarts the 24 hours.Once the window has closed, or if the customer has never messaged you, WhatsApp only lets you send an approved template. When the customer replies to it, a new window opens and you can send normal messages again.The 24-hour rule is Meta's rule for WhatsApp, not a Chronox limit. Chronox doesn't block a normal message outside the window; it passes the message to WhatsApp, and WhatsApp refuses to deliver it.
Not sure whether the window is open? Use Get Thread Details to see when the customer last messaged you. If it was more than 24 hours ago, send a template instead.
Before you send#
You need two things for every message:| What | Where to find it |
|---|
| The customer's WhatsApp number | Include the country code and use digits only, with no +, spaces or dashes. For example, the Indian number +91 98765 43210 is written 919876543210. |
Your WhatsApp number's integrated_channel_id | Call Get Meta Integration. Each connected WhatsApp number has its own integrated_channel_id. It tells Chronox which of your numbers to send from. |
If no conversation with that customer exists yet, Chronox creates one automatically.If you already have the conversation's ID from Get Inbox Data, you can send that instead of the phone number. It's called thread_id in Send Whatsapp Message and user_thread_id in Send Whatsapp Template.
Send a normal message#
Use Send Whatsapp Message to reply to a customer within the 24-hour window.Text#
A file#
Set type to media and list your files in media. Each file needs a type and a public url that WhatsApp can download. A caption is optional.File type | Use it for |
|---|
image | Photos and pictures |
video | Video clips |
audio | Voice notes and audio files |
document | PDFs and other documents |
sticker | WhatsApp stickers |
If you include more than one file, each one arrives as a separate message.
The file link must be publicly reachable. If WhatsApp can't download the file, the message isn't delivered. WhatsApp also sets its own limits on file types and sizes.
Send a template#
Use Send Whatsapp Template to start a conversation, or to contact a customer after the 24-hour window has closed. The template must have the status Approved. See Getting started with WhatsApp templates.whatsapp_template_id is the ID of your template, which you can find with Get Whatsapp Templates.The two endpoints use different names for the customer's number: end_user_phone_number in Send Whatsapp Message and user_wa_phone_number in Send Whatsapp Template. Make sure you use the right one.
Filling in template variables#
Most templates contain blanks (also called variables), such as {{customer_name}}, that you fill in each time you send. Provide a value for each one in template_variable_data:{
"integrated_channel_id": 101,
"user_wa_phone_number": "919876543210",
"whatsapp_template_id": 25,
"template_variable_data": [
{ "variable_id": 301, "variable_value": "Priya" },
{ "variable_id": 302, "variable_value": "ORD-10045" }
]
}
| Field | What to put |
|---|
variable_id | The blank's whatsapp_template_dynamic_variable_id. Find it with Get Whatsapp Template Details: every blank in the body, header and buttons has one. |
variable_value | The text to put in the blank. |
If the template has no blanks, send an empty list: "template_variable_data": [].On a basic template, a missing body value doesn't produce an error. Chronox leaves the blank out and sends the message anyway, and WhatsApp then refuses it: you get "status": true with "wa_message_id": null. Always send a value for every blank. Missing header values, and any missing value on a carousel, fail straight away with Invalid body!.
Finding the IDs#
Call Get Whatsapp Template Details for your template. Every blank has its own whatsapp_template_dynamic_variable_id, and it sits in a different place depending on which part of the template it belongs to. The tables below show where.You send one entry per blank, in any order. Chronox matches each entry to its blank by variable_id.
Named or numbered blanks make no difference to what you send. Chronox handles that from the template.
Blanks that aren't in the template don't need entries, and entries for blanks that aren't there are ignored.
Basic templates#
| Part of the template | Where its ID is in the template details | What to send | If you leave it out |
|---|
| Body blank | whatsapp_template_body → whatsapp_template_body_variable_data | The text for the blank. | No error, but WhatsApp refuses the message. |
| Text header blank | whatsapp_template_header → whatsapp_template_header_data → whatsapp_template_header_variable_data | The text. A header can have only one blank. | Invalid body! |
| Media header (image, video, document) | Same place as the text header | The public link to the file. | Invalid body! |
| Website button, dynamic link | whatsapp_template_button → whatsapp_template_button_data → whatsapp_template_button_sub_type_field_data → whatsapp_template_button_field_data_variable | Either the changing part of the link, or the whole link. | No error, but WhatsApp refuses the message. |
| Copy Offer Code button (marketing templates only) | Same place as the website button | The code the customer copies. | No error, but WhatsApp refuses the message. |
| Authentication (OTP) | whatsapp_template_body → whatsapp_template_body_variable_data (the {{1}} blank) | The code. Send it once: Chronox uses it for the body and the Copy Code button. | Invalid OTP error. |
| Flow button | You don't look these up in the template. See Flow inputs below. | Optional. | Nothing. The Flow opens without them. |
Document headers: WhatsApp shows the file name taken from your link. Chronox turns underscores into spaces and drops a number on the end, so price_list_1748419007.pdf appears as price list.pdf. Name your files the way you want them to appear.
No value needed for: website buttons with a fixed link, call phone number buttons, quick reply buttons, View Catalog buttons, or any button label. These are fixed when the template is created.Carousel templates#
A carousel is returned as several entries in whatsapp_template_data: one per card, each with its own whatsapp_template_carousel_variation_id. Each card has its own blanks, so look at every entry.| Part of the template | Where its ID is | What to send | If you leave it out |
|---|
| Text above the cards | whtatsapp_carousel_header_variable_data, at the top level of the template | The text for the blank. | Invalid body! |
| Card header | In each card: whatsapp_template_header → whatsapp_template_header_data → whatsapp_template_header_variable_data | The public link to the image or video. | Invalid body! |
| Card body blank | In each card: whatsapp_template_body → whatsapp_template_body_variable_data | The text for the blank. | Invalid body! |
| Card website button, dynamic link | In each card, in the button's whatsapp_template_button_field_data_variable | Either the changing part of the link, or the whole link. | No error, but WhatsApp refuses the message. |
The field name whtatsapp_carousel_header_variable_data is spelled that way in the API response, with an extra t. Use it exactly as it appears.
Carousels are stricter than basic templates. A missing body value on a basic template slips through and WhatsApp refuses it, but on a carousel it fails straight away with Invalid body!.
Copy Offer Code buttons can't be used on carousels.Catalog templates#
Only the body can contain blanks: send one entry per blank, as for a basic template. The View Catalog button is fixed, and there are no header or button values to send.Call Permission Request templates#
These never contain blanks. Send an empty list: "template_variable_data": [].Interactive messages#
Interactive messages aren't approved templates, so WhatsApp only delivers them inside the 24-hour window. Outside it, send an approved template instead.Chronox puts your values into the saved message first, then sends the finished message as a live WhatsApp message.| Part of the message | What to send |
|---|
| Body blank | The text for the blank. |
| Text header blank | The text. Missing values fail with Invalid body!. |
| Media header | The public link to the file. |
| Flow button | Optional Flow inputs. See below. |
Catalog messages can't have a header. List rows, reply button titles and website links aren't variables: they come from the saved message.If a template or interactive message opens a WhatsApp Flow, you can pass values into the Flow. These entries look different from ordinary blanks:{
"variable_id": 42,
"variable_value": "gold",
"flag_flow_variable": true
}
| Field | What to put |
|---|
variable_id | The Flow variable's ID. This is not a template blank ID, and it doesn't appear in the template details. |
variable_value | The value to pass into the Flow. |
flag_flow_variable | Must be true. |
Flow inputs are optional. An ID that doesn't match a Flow variable fails with Invalid body!. You can mix Flow inputs with ordinary entries in the same list.One request with every kind of value#
{
"integrated_channel_id": 101,
"user_wa_phone_number": "919876543210",
"whatsapp_template_id": 25,
"template_variable_data": [
{ "variable_id": 301, "variable_value": "Priya" },
{ "variable_id": 302, "variable_value": "ORD-10045" },
{ "variable_id": 310, "variable_value": "https://example.com/invoice_ORD-10045.pdf" },
{ "variable_id": 311, "variable_value": "order/10045" },
{ "variable_id": 312, "variable_value": "SAVE20" },
{ "variable_id": 42, "variable_value": "gold", "flag_flow_variable": true }
]
}
Here 301 and 302 are body blanks, 310 is a document header link, 311 is the changing part of a website link, 312 is an offer code and 42 is a Flow input. A real template wouldn't use all of these at once.WhatsApp's character limits#
Chronox doesn't check these before sending. Going over one doesn't give you a clear error: the message goes to WhatsApp, WhatsApp refuses it, and you get "status": true with "wa_message_id": null. Check them in your own code.
Lengths are measured after your values are filled in, and include spaces, punctuation and emojis. A 60-character header containing Order {{order_id}} must still be 60 characters or fewer once the order number is in it.| Template | Part | Limit |
|---|
| Basic | Body | 1024 characters |
| Basic | Text header | 60 characters |
| Basic | Dynamic website link (whole URL) | 2000 characters |
| Basic | Offer code | 20 characters |
| Basic | OTP code | 15 characters |
| Carousel | Text above the cards | 1024 characters |
| Carousel | Each card's body | 160 characters |
| Carousel | Dynamic website link (whole URL) | 2000 characters |
| Catalog template | Body | 1024 characters |
| Call Permission Request | Values | None to send |
| Interactive | Body — reply buttons, CTA URL, catalog | 1024 characters |
| Interactive | Body — list, text, flow | 4096 characters |
| Interactive | Text header | 60 characters |
There's no length limit on links to media files (basic template headers, carousel card headers and interactive headers) or on values passed into a Flow.For a dynamic website link, the whole URL counts: the fixed part plus the value you send.The few things Chronox checks itself when sending:| Check | What happens |
|---|
| Catalog message body over 1024, or footer over 60 | The request fails with an error. |
| Header blank with no value, or any missing value on a carousel | The request fails with Invalid body!. |
| Flow input that matches no Flow variable | The request fails with Invalid body!. |
Check that WhatsApp accepted the message#
A response with "status": true means Chronox handled your request. It doesn't always mean WhatsApp accepted the message. Check the response as follows:| Endpoint | The message was accepted if… |
|---|
| Send Whatsapp Message (text) | data.wa_message_response.status is true. If it's false, WhatsApp's reason is inside data.wa_message_response.error. |
| Send Whatsapp Message (files) | data.wa_message_response is a list with one entry per file, in the order you sent them. An entry containing messages was accepted. An empty entry {} means WhatsApp didn't accept that file, and no reason is given. |
| Send Whatsapp Template | data.wa_message_id has a value. If it's null, the message wasn't sent, and the response doesn't say why. The usual causes are a missing value, a limit above, or a closed 24-hour window. |
Even after WhatsApp accepts a message, it can still fail to deliver it later. You can follow a message's progress in the conversation using Get Thread Details.Things to watch out for#
Don't send twice by accident. If a request times out, the message may still have been sent. Check the conversation with Get Thread Details before trying again. See Errors. Keep to your rate limit. Sending many messages quickly counts towards your API key's limit. See Rate limiting. Respect customer choices. Meta can pause your templates or limit your account if customers block or report your messages. Only message customers who expect to hear from you.
Your workspace must be active. If your workspace is paused, sending fails with Your organization is paused by admin. Please contact your admin.
What this section doesn't cover#
Creating templates. See the WhatsApp Templates section.
Reading conversations. See the Inbox section.
Broadcasts and campaigns. Sending one message to a large list of customers is done with campaigns in the Chronox dashboard, not through the API.
Other channels. This section covers WhatsApp only.