WhatsApp messages
This guide lists what you can send on WhatsApp, and what the person can send back. Formats are the ones in the WhatsApp Cloud API and Kapso documentation. What a format needs from a real number is said where it applies.
Send inside the 24-hour window
Inside the 24 hours after the last message of the person, POST /v2/cases/{id}/messages with author: "team" takes interactive in place of text. The agent sends the same formats with its system tools.
type | Content field | What it does | Agent tool |
|---|---|---|---|
buttons | buttons | 1 to 3 quick replies. headerMedia puts an image, video or document above. | send_buttons |
list | list | A menu of up to 10 rows. | send_list |
product | product | One product of the catalog. | send_products |
product_list | products | Up to 30 products in up to 10 sections. | send_products |
catalog | catalog | Opens the catalog of the number. | send_products |
cta_url | cta | One button that opens an https link. headerMedia is allowed. | send_cta_url |
flow | flow | A button that opens a WhatsApp Flow (a form). | send_flow |
location_request | none | Asks the person to share a location. Only body. | request_location |
contact_request | none | Asks the person to share their phone. Only body. | |
call | call | A button that starts a WhatsApp call. call is optional. | |
carousel | carousel | 2 to 10 swipeable cards with an image or video and one button each. | send_carousel |
Limits that the API checks and names in param: body up to 1,024 characters; buttons and link labels up to 20; link and media URLs must be public https; a carousel card body takes up to 160 characters and 2 line breaks; every card of a carousel uses the same kind of button (all links or all quick replies, with the same count) and the quick reply ids are unique in the message.
A message needs cases:send, a person in control and the 24-hour window. Outside the window only an approved template goes out (422 channel_window_closed).
The Flow, the call button and the contact request need the feature on the WhatsApp account. The platform sends them in the shape the documentation shows; whether your account has them is Meta's answer, and it comes back in error (see A message that fails).
What the person sends back
Everything arrives as a message of the case and as message.received.
| The person | Field of the message | type in message.received |
|---|---|---|
| Taps a button or a list row | reply: { id, title } | reply |
| Sends a cart from the catalog | order: { catalogId, items } | order |
| Shares a location | location: { latitude, longitude, name?, address? } | location |
| Finishes a Flow | flowResponse: { token?, data } | flow_response |
Shares their phone for a contact_request | contact: { phones } | contact |
text always carries a sentence the agent reads, such as Location: -33.4489, -70.6693 (Home) or Flow response: {"date":"2026-11-02"}. A contact card the person forwards on their own is not kept.
The event of a location, a Flow answer and a shared phone carries only the type, because they are personal data of the person: read the data with GET /v2/cases/{id}/messages.
Catalog and commerce settings
The catalog is created in Meta Commerce Manager and connected in WhatsApp Manager. Then:
- Save its id on the number:
PATCH /v2/whatsapp/phone-numbers/{id}withcatalogId. - Read or change the cart button and the catalog icon:
GETandPATCH /v2/whatsapp/phone-numbers/{id}/commerce-settingswithisCartEnabledandisCatalogVisible.
A product, product_list or catalog message, and a template with a catalog button, only goes out when the number has a catalog and the catalogId of the message is that one. Otherwise: 422 catalog_not_connected. The platform cannot ask Meta whether the catalog exists; a wrong id shows up as a failed message with its reason.
Templates
Outside the 24-hour window you send an approved template with POST /v2/whatsapp/messages, a campaign or a trigger. Besides text variables a template can have:
| In the template | When you send |
|---|---|
header: { type: "image" | "video" | "document", exampleFileId } | components.headerImage, components.headerVideo (fileId, url or attachmentId) or document |
A url button ending in a variable, like https://shop.example.com/orders/{{order_id}} | the value in variables.order_id |
A catalog button | components.catalog.thumbnailProductId (optional) |
An mpm button (several products) | components.mpm: { thumbnailProductId, sections } (required) |
A flow button (flowId, flowAction, screen) | components.flow: { token, data } (optional) |
carousel: { type: "media", cards } | components.cards: one image or video per card, each with fileId or url |
carousel: { type: "product", buttonText } | components.catalogId and components.cards: 2 to 10 productId (marketing category) |
A media carousel has the number of cards you create it with. A product carousel is created with two and sent with 2 to 10. WhatsApp reviews every combination when it reviews the template.
Files for messages, campaigns and templates
Upload a file once with POST /v2/files (multipart, the file in file, the purpose next to it) and use the fil_… id wherever a message, a campaign or a template takes media. You do not need a public URL, and the file does not have to stay on your server.
purpose | Where the fileId goes | Accepts |
|---|---|---|
message_media | document.fileId, components.headerImage.fileId, components.headerVideo.fileId and the cards of POST /v2/whatsapp/messages | JPEG and PNG up to 5 MB, MP4 and 3GPP up to 16 MB, PDF, text, Word, Excel and PowerPoint up to 100 MB |
campaign_media | the same fields, in a campaign | the same |
template_header | header.exampleFileId and carousel.cards[].header.exampleFileId when you create a template | JPEG and PNG up to 5 MB, MP4 up to 16 MB, PDF |
The limits are the ones in the WhatsApp media table; for template samples, the types that the resumable upload takes. The type is read from the content, not from the Content-Type you send, and a file only works where its purpose says (400 invalid_request with the field in param otherwise). A file too big is 413 payload_too_large.
When the message goes out, Lelemon uploads the file to WhatsApp and sends it by media id, which is what Meta recommends over a link. A template sample is uploaded with the resumable upload and Meta returns the handle that the review needs. A URL still works in url and exampleUrl, but Meta caches a link for ten minutes and does not recommend it.
A document that carries one person's data, such as a statement, is uploaded with contactId and purpose: "message_media". It can only be sent to that contact and it is erased with them.
GET /v2/files lists them (filter with purpose), GET /v2/files/{id} reads one and DELETE /v2/files/{id} removes the stored file. A file used by a campaign that has not finished, or by a message that has not gone out, answers 409 resource_in_use. The scopes are files:read and files:write. ?dryRun=true on the upload validates the file and the purpose and stores nothing.
POST /v2/cases/{id}/attachments stays as it was: those files belong to one case and its person, and you send them with attachmentIds in a case message. A file of /v2/files belongs to the organization and is reused by many messages.
A message that fails
A message that WhatsApp or the platform could not send has status: "failed" and error: { code, message }. code is WhatsApp's code when WhatsApp rejected it, and null when the platform stopped it first (for example, recipient_not_allowed).
Not available in Chile
order_details,order_statusand payment inside WhatsApp: Kapso Pix is only for Brazil. In Chile the payment stays an external link: usecta_url.- The address message is only for India.