Sending messages
Start WhatsApp conversations with templates, follow each send and reply inside the 24-hour window.
This guide walks through the flow of a business system, for example an ERP that tells a customer their glasses are ready:
- Choose the channel and the template.
- Send the template to the customer's phone.
- Follow the send.
- Receive the customer's reply.
- Reply with text while the window is open.
The key needs the conversations:read, templates:read and messages:send scopes.
1. Choose the channel and the template
List the channels and take the id of the WhatsApp number you will write from.
curl https://getricky.ai/api/v1/channels \
-H "Authorization: Bearer $RICKY_API_KEY"{
"data": [
{
"id": "0b6f2c1e-7d4a-4c8e-9f3b-2a1d5e6c7b80",
"type": "whatsapp",
"name": "Óptica Central",
"address": "+50720001000",
"whatsapp_business_account_id": "102938475610293",
"connected_at": "2026-09-02T14:10:00.000Z"
}
],
"next_cursor": null
}List the templates. Ricky reads them live from Meta.
curl https://getricky.ai/api/v1/templates \
-H "Authorization: Bearer $RICKY_API_KEY"{
"data": [
{
"id": "1478523690147852",
"name": "pedido_listo",
"language": "es",
"category": "UTILITY",
"status": "APPROVED",
"whatsapp_business_account_id": "102938475610293",
"parameter_format": "POSITIONAL",
"components": [
{
"type": "BODY",
"text": "Hola {{1}}, tus lentes están listos en {{2}}. Puedes retirarlos desde el {{3}}."
},
{
"type": "FOOTER",
"text": "Óptica Central"
}
]
}
],
"next_cursor": null
}Use a template that meets three conditions:
statusisAPPROVED. Ricky rejects any other with422 rule_violation.whatsapp_business_account_idmatches the channel's.- You know its variables:
{{1}},{{2}}… whenparameter_formatisPOSITIONAL, or{{name}}when it isNAMED.
2. Send the template
POST /conversations sends a template to a phone number. Ricky finds or creates the contact and reuses that number's conversation on that channel. You do not need to create the contact first. phone carries the country code, for example +50760001234.
curl https://getricky.ai/api/v1/conversations \
-H "Authorization: Bearer $RICKY_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: pedido-48213-listo" \
-d '{
"channel_id": "0b6f2c1e-7d4a-4c8e-9f3b-2a1d5e6c7b80",
"phone": "+50760001234",
"template": {
"id": "1478523690147852",
"components": [
{
"type": "body",
"parameters": [
{ "type": "text", "text": "Ana" },
{ "type": "text", "text": "Óptica Central Costa del Este" },
{ "type": "text", "text": "viernes 16 de octubre" }
]
}
]
}
}'{
"data": {
"id": "8f0c2d4e-6a1b-4c3d-8e9f-0a1b2c3d4e5f",
"conversation_id": "3f6d2a10-8b7c-4e1d-9a2f-5c4b3e2d1a09",
"status": "queued",
"message_id": null,
"failure_reason": null,
"created_at": "2026-10-14T15:30:02.118Z"
}
}202 means Ricky accepted the send and queued it. It does not yet mean WhatsApp accepted it. Keep id (the send ID) and conversation_id.
Derive the Idempotency-Key from your own data, such as the order number. Then, if your system restarts and repeats the send, Ricky does not send the message twice. See Idempotency.
Template variables
components uses the WhatsApp Cloud API format. Each item fills the variables of one part of the template:
type | Use |
|---|---|
header | Header variables: text, or an image, video or document file with its public HTTPS link. |
body | Body variables, in order. |
button | Variables of one button. Set sub_type (url or quick_reply) and index, the button position from "0". |
In a NAMED template, each text parameter carries parameter_name:
{
"type": "body",
"parameters": [{ "type": "text", "parameter_name": "nombre", "text": "Ana" }]
}A header with an image and a button with a variable URL:
[
{
"type": "header",
"parameters": [{ "type": "image", "image": { "link": "https://example.com/lentes.jpg" } }]
},
{
"type": "button",
"sub_type": "url",
"index": "0",
"parameters": [{ "type": "text", "text": "48213" }]
}
]Send a template without variables with "components": [] or without components.
Common errors
| Response | Cause |
|---|---|
404 not_found | The channel does not exist or is disconnected, or the template does not exist. |
422 rule_violation | The channel is not WhatsApp, or the template is not APPROVED. |
502 upstream_error | Ricky could not read the templates from Meta. Follow Unknown state. |
3. Follow the send
Read the send by its id:
curl https://getricky.ai/api/v1/sends/8f0c2d4e-6a1b-4c3d-8e9f-0a1b2c3d4e5f \
-H "Authorization: Bearer $RICKY_API_KEY"{
"data": {
"id": "8f0c2d4e-6a1b-4c3d-8e9f-0a1b2c3d4e5f",
"conversation_id": "3f6d2a10-8b7c-4e1d-9a2f-5c4b3e2d1a09",
"status": "sent",
"message_id": "a7e5c3b1-9d8f-4a6e-b2c4-1d3f5e7a9b0c",
"failure_reason": null,
"created_at": "2026-10-14T15:30:02.118Z"
}
}status | Meaning |
|---|---|
queued | Ricky is still handing it to the provider and retries when needed. |
sent | The provider accepted the message. |
failed | It failed for good. failure_reason explains why. |
Poll with growing waits, for example at 2, 4 and 8 seconds, until the status is no longer queued.
Once the status is sent, message_id is the message in the conversation: the same id the message list shows and the message.sent webhook carries.
sent does not mean delivered or read. For that, list the conversation's messages: each outbound message carries its status, for example sent, delivered, read or failed, and the times sent_at, delivered_at and read_at.
4. Receive the reply
Subscribe a webhook to the message.received event. See Webhooks.
{
"id": "5b8e0f3a-2c51-4b8e-9d0e-6f1a2b3c4d5e",
"type": "message.received",
"occurred_at": "2026-10-14T15:42:10.000Z",
"organization_id": "0d9c4b7e-1f2a-4c3d-8e5f-6a7b8c9d0e1f",
"data": {
"conversation_id": "3f6d2a10-8b7c-4e1d-9a2f-5c4b3e2d1a09",
"message_id": "a7e5c3b1-9d8f-4a6e-b2c4-1d3f5e7a9b0c"
}
}Ricky delivers events in passes every 15 minutes, so the event can arrive several minutes after the message. If your process needs the reply sooner, read the conversation.
The event does not carry the text. List the conversation's messages and find message_id. The list starts with the newest.
curl https://getricky.ai/api/v1/conversations/3f6d2a10-8b7c-4e1d-9a2f-5c4b3e2d1a09/messages \
-H "Authorization: Bearer $RICKY_API_KEY"{
"data": [
{
"id": "a7e5c3b1-9d8f-4a6e-b2c4-1d3f5e7a9b0c",
"conversation_id": "3f6d2a10-8b7c-4e1d-9a2f-5c4b3e2d1a09",
"direction": "inbound",
"type": "text",
"text": "Gracias, paso el viernes en la tarde.",
"sender": { "type": "contact", "name": null },
"status": "delivered",
"media": null,
"provider_message_id": "wamid.HBgLNTA3NjAwMDEyMzQVAgASGBQzRUIwRDFCMkM0RTZGOEEwQjlDMgA=",
"created_at": "2026-10-14T15:42:11.204Z",
"sent_at": "2026-10-14T15:42:10.000Z",
"delivered_at": null,
"read_at": null,
"failed_at": null,
"edited_at": null,
"deleted_at": null
}
],
"next_cursor": "eyJpZCI6ImE3ZTVjM2IxIn0"
}When the message carries a file, media.url is a signed link valid for one hour. It is null until Ricky has downloaded the file.
5. Reply with text
While the WhatsApp window is open, reply with text in the same conversation. The window lasts 24 hours from the customer's last message.
curl https://getricky.ai/api/v1/conversations/3f6d2a10-8b7c-4e1d-9a2f-5c4b3e2d1a09/messages \
-H "Authorization: Bearer $RICKY_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: pedido-48213-respuesta-1" \
-d '{ "type": "text", "text": "Perfecto, Ana. Te esperamos el viernes." }'The response is 202 with a send, as in step 2. Follow it with GET /sends/{send_id}.
With the window closed, Ricky answers 422 outside_messaging_window:
{
"error": {
"code": "outside_messaging_window",
"message": "…",
"request_id": "7c1e9a3b-5d2f-4e8a-b6c0-1f3d5a7b9e2c"
}
}In that case, send a template in the same conversation:
curl https://getricky.ai/api/v1/conversations/3f6d2a10-8b7c-4e1d-9a2f-5c4b3e2d1a09/messages \
-H "Authorization: Bearer $RICKY_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: pedido-48213-recordatorio" \
-d '{
"type": "template",
"template": {
"id": "1478523690147852",
"components": [
{
"type": "body",
"parameters": [
{ "type": "text", "text": "Ana" },
{ "type": "text", "text": "Óptica Central Costa del Este" },
{ "type": "text", "text": "viernes 16 de octubre" }
]
}
]
}
}'Templates only exist on WhatsApp: in an Instagram or Messenger conversation, a template gets 422 rule_violation. On those channels, send text inside each channel's reply window. Text takes up to 4096 characters; on Messenger, up to 2000.