Enviar plantilla de mensaje
Envía una plantilla de WhatsApp aprobada para iniciar una conversación con un cliente. Si ya existe una conversación abierta, el mensaje se añade a ella; si no, se crea una nueva.
Actualmente, este endpoint solo es compatible con el canal de WhatsApp.
POST https://api.platica.mx/v1/messages/template Cuerpo de la solicitud
{
"channelId": "wb-123456789",
"conversationId": "521234567890",
"responderAgentId": "agent_123",
"campaignId": "pV6PvG2lc8ChQb2VmETr",
"template": {
"name": "bienvenida_cliente",
"params": ["Juan", "Premium"],
"type": "image",
"file": "https://cdn.assets.com/welcome_image.jpg",
"buttons": [
{
"index": 0,
"parameters": [{ "type": "text", "text": "promo/enero" }]
}
]
},
"client": {
"name": "José",
"customFields": {
"placas": "ABC123",
"id_recepcion": "REC001"
}
}
} Parámetros del cuerpo
| Campo | Tipo | Descripción | Requerido |
|---|---|---|---|
channelId | string | Canal emisor. Usa preferentemente el prefixedChannelId (por ejemplo wb-123); por compatibilidad se aceptan el teléfono o channelId legacy del agente | ✓ |
conversationId | string | Número de teléfono del cliente en formato E.164 sin + | ✓ |
responderAgentId | string | Agente opcional que atenderá las respuestas. No necesita tener asignado el canal emisor | — |
campaignId | string | ID de la campaña a la que se atribuye el mensaje. Si se omite, el mensaje se registra bajo la campaña api | — |
template.name | string | Nombre de la plantilla a utilizar | ✓ |
template.params | array | Variables para el cuerpo de la plantilla. La cantidad debe coincidir exactamente con el número de variables definidas en la plantilla | — |
template.type | enum | Tipo de encabezado: image, document, video. Obligatorio si la plantilla tiene encabezado multimedia | — |
template.file | string | URL pública https:// del archivo para el encabezado. Obligatoria si template.type está presente | — |
template.buttons | array | Variables dinámicas de los botones de la plantilla. Máximo 3 elementos | — |
delay | number | Retraso en milisegundos (3,000 – 86,400,000; máximo 24 horas) | — |
scheduleTime | string | Fecha/hora de envío programado (ISO 8601). Máximo 30 días después de la solicitud | — |
client | object | Información del cliente a actualizar (Upsert) | — |
Si se envía el objeto client, se actualizará la información del perfil del cliente (o se creará si no existe), permitiendo al agente de IA tener acceso inmediato a los nuevos datos.
Canal y agente respondedor
El canal y el agente son independientes:
channelIddecide desde qué número/canal se envía.responderAgentIddecide qué agente atenderá las respuestas.- Si omites
responderAgentIdcon unchannelIdcanónico, la conversación nueva quedainitiatedy sin agente. EldefaultAgentIddel canal no se hereda (ese campo es solo para inbound). - Si usas el identificador legacy (teléfono del agente), se conserva ese agente.
- Si no hay agente, el mensaje se envía igual. Cuando el contacto responde, el
hilo pasa a
supervisedy sigue sin IA hasta que asignes un agente. - Si ya existe una conversación activa para ese contacto y canal, conserva su agente actual.
Cada elemento del array representa un botón dinámico de la plantilla. Los botones estáticos (sin variables) no necesitan incluirse.
| Campo | Tipo | Descripción | Requerido |
|---|---|---|---|
index | integer | Índice base-0 del botón en la plantilla. Debe corresponder a un botón existente | ✓ |
sub_type | enum | url, phone_number, quick_reply, otp. Se infiere automáticamente del tipo definido en la plantilla si se omite | — |
parameters | array | Exactamente un elemento con { "type": "text", "text": "<valor>" } | ✓ |
Reglas importantes:
- Los índices no pueden repetirse dentro del mismo array
- Para botones de tipo URL,
textdebe ser un segmento de ruta (ej:"promo/enero"), no una URL completa. Enviar"https://..."devuelve error 400 - Si
sub_typese omite, se infiere del tipo del botón definido en la plantilla (URL→url,OTP→otp,PHONE_NUMBER→phone_number)
"buttons": [
{
"index": 0,
"parameters": [{ "type": "text", "text": "promo/enero" }]
},
{
"index": 1,
"sub_type": "otp",
"parameters": [{ "type": "text", "text": "482910" }]
}
] Programación
Envía la plantilla inmediatamente, con un retraso o en una fecha específica. Después puedes consultarla, reprogramarla o cancelarla por messageId .
Envío con retraso (delay):
- Mínimo:
3000ms (3 segundos) - Máximo:
86400000ms (24 horas) - Ejemplo:
"delay": 5000envía el mensaje en 5 segundos
Envío programado (scheduleTime):
- Formato ISO 8601
- Debe ser una fecha futura
- No puede ser más de 30 días después de la solicitud
- Ejemplos:
"2026-10-15T18:40:00"— Hora de México (UTC-6)"2026-10-15T18:40:00Z"— Hora UTC"2026-10-15T18:40:00-06:00"— Con zona horaria específica
No puedes usar delay y scheduleTime en la misma solicitud.
| Campo | Tipo | Descripción |
|---|---|---|
client.name | string | Nombre completo del cliente |
client.firstname | string | Primer nombre |
client.lastname | string | Apellido |
client.email | string | Correo electrónico |
client.birthdate | string | Fecha de nacimiento (dd/mm/yyyy) |
client.gender | enum | Género: male o female |
client.company | string | Nombre de la compañía |
client.country | enum | Código ISO 3166-1 alpha-2 (ej: MX, US) |
client.state | string | Estado de residencia |
client.city | string | Ciudad de residencia |
client.address | string | Dirección completa |
client.postalCode | string | Código postal |
client.customFields | map | Objeto con pares clave-valor de los campos personalizados definidos en el workspace. Consulta Campos personalizados para ver los disponibles. |
client.owners | array | Correos de usuarios responsables |
Validación contra la plantilla
Al recibir la solicitud, el API verifica que el payload sea compatible con la definición de la plantilla registrada en WhatsApp. Si hay incompatibilidades, se devuelve un error 400 con el detalle de cada problema.
Las reglas que se validan automáticamente son:
- Cantidad de params: debe coincidir exactamente con el número de variables
{{1}},{{2}}... en el cuerpo de la plantilla - Encabezado multimedia: si la plantilla tiene encabezado de imagen, video o documento,
template.typeytemplate.fileson obligatorios ytypedebe coincidir con el formato definido - Índices de botones: cada
indexentemplate.buttonsdebe corresponder a un botón existente en la plantilla - Variables de botones URL: el valor de
textdebe ser un segmento de ruta, no una URL completa
{
"message": "Template payload is incompatible with template configuration",
"template": "bienvenida_cliente",
"errors": [
{
"field": "template.params",
"message": "The number of params does not match the template definition",
"expected": 2,
"received": 1
},
{
"field": "template.type",
"message": "This template requires media header type",
"expected": "image",
"received": null,
"example": {
"type": "image",
"file": "https://example.com/your-media-file"
}
}
]
} Respuesta
La respuesta varía según si el mensaje se envía de forma inmediata, diferida o programada.
Envío inmediato:
{
"messageId": "msg_123xyz",
"status": "sent",
"timestamp": "2026-09-20T20:00:00Z"
} Con delay (HTTP 202):
{
"messageId": "msg_123xyz",
"kind": "template",
"status": "delayed",
"timestamp": "2026-09-20T20:00:00Z",
"executeAt": "2026-09-20T20:00:05.000Z",
"delayMs": 5000
} Con scheduleTime (HTTP 202):
{
"messageId": "msg_123xyz",
"kind": "template",
"status": "scheduled",
"timestamp": "2026-09-20T20:00:00Z",
"executeAt": "2026-10-16T00:40:00.000Z",
"scheduledTime": "2026-10-15T18:40:00"
} | Campo | Tipo | Descripción |
|---|---|---|
messageId | string | ID del mensaje creado. En envíos programados, úsalo para consultar, reprogramar o cancelar el recurso ; no necesitas campaignId ni runId |
kind | enum | template en las respuestas HTTP 202 de este endpoint |
status | enum | sent, delayed o scheduled |
timestamp | string | Fecha/hora en que se procesó la solicitud (ISO 8601 UTC) |
executeAt | string | Fecha/hora en que se enviará el mensaje (ISO 8601 UTC). Solo presente en envíos diferidos o programados |
delayMs | number | Retraso configurado en milisegundos. Solo presente cuando se usó delay |
scheduledTime | string | Valor original de scheduleTime enviado en la solicitud. Solo presente cuando se usó scheduleTime |
Los envíos con delay o scheduleTime quedan aceptados, pero todavía no enviados. Consulta Mensajes Programados para conocer sus estados y reglas de ejecución.
Contacto bloqueado
Un contacto con status: \"blocked\" nunca recibe plantillas. La API responde:
{
"code": 409,
"error": "Conflict - The resource state conflicts with this request",
"details": {
"code": "CONTACT_BLOCKED",
"clientId": "client_123",
"status": "blocked"
}
} La comprobación también se repite al ejecutar mensajes diferidos o programados.
Reglas de WhatsApp
Plantillas obligatorias
Para iniciar una conversación debes usar una plantilla pre-aprobada. No puedes enviar mensajes de texto libre hasta que el cliente responda.
Ventana de 24 horas
Las conversaciones permanecen activas durante 24 horas desde el último mensaje del cliente.
Si el cliente NO responde:
- Envías la plantilla
- El cliente no responde
- No puedes enviar más mensajes hasta que responda
Si el cliente SÍ responde:
- Envías la plantilla
- El cliente responde
- Puedes enviar mensajes libremente durante 24 horas
- La ventana se reinicia con cada mensaje del cliente
Limitaciones de entrega
WhatsApp puede bloquear mensajes por:
- Restricciones del país del cliente
- Números en experimentos de WhatsApp
- Clientes que desactivaron notificaciones de marketing
Consultar estado
Verifica si tu mensaje fue entregado:
- Desde la bandeja de entrada de la plataforma
- Usando el endpoint Obtener Conversación