Plantillas

Envía plantillas HSM (mensajes de utilidad pre-aprobados por Meta) a tus clientes: confirmaciones de pedido, "tu pedido va en camino", "tu pedido fue...

Un solo endpoint funciona sin importar por qué canal está la conversación:

  • WhatsApp Business (Cloud API): se envía como plantilla real aprobada por Meta. La conexión WABA en el producto llegará pronto; hoy el listado puede estar vacío.
  • WhatsApp Web, Instagram, Facebook o Widget Web: Yolani envía el mismo contenido como texto libre con variables reemplazadas (delivery_mode: "text_fallback").

WhatsApp Business API:

La conexión por Cloud API en Yolani está próximamente. Mientras tanto, usa el endpoint con fallback de texto en conversaciones de WhatsApp Web u otros canales.

Tip:

La respuesta indica qué pasó realmente con delivery_mode: "template" (se envió como plantilla de Meta) o "text_fallback" (se envió como texto libre).

Listar plantillas aprobadas

GET /api/v1/templates

Scope: messages:send_template

Devuelve solo las plantillas con status APPROVED en tu WABA. Si tu cuenta no tiene WhatsApp Business (Cloud API) conectado, devuelve una lista vacía (puedes seguir usando el envío por fallback de texto libre si conoces el nombre y variables de tu plantilla).

curl https://api.yolani.co/api/v1/templates \
  -H "Authorization: Bearer yol_TU_TOKEN"

Respuesta:

{
  "success": true,
  "data": [
    {
      "name": "pedido_en_camino",
      "language": "es_MX",
      "category": "UTILITY",
      "body": "Hola {{1}}, tu pedido #{{2}} va en camino y llega hoy.",
      "header_format": null,
      "header_text": null,
      "footer": null,
      "buttons": []
    }
  ]
}

Enviar una plantilla

POST /api/v1/conversations/:id/messages/template

Scope: messages:send_template

CampoTipoRequeridoDescripción
template_namestringSíNombre exacto de la plantilla aprobada
languagestringNoCódigo de idioma (ej. es_MX). Si la omites, se usa la primera plantilla aprobada que coincida con el nombre
body_paramsstring[]Sí si la plantilla tiene variablesValores para las variables del cuerpo, en orden ({{1}}, {{2}}, ...)
header_paramstringNoValor de la variable del encabezado, o URL pública del archivo si el encabezado es multimedia. Solo aplica cuando se envía como plantilla real (WhatsApp Business Cloud API)
button_paramsstring[]NoValores para botones dinámicos (URL con variable, código de cupón). Solo aplica cuando se envía como plantilla real
client_request_idstringNoID propio para idempotencia
curl -X POST https://api.yolani.co/api/v1/conversations/913/messages/template \
  -H "Authorization: Bearer yol_TU_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "template_name": "pedido_en_camino",
    "body_params": ["Andrea", "1042"]
  }'

Respuesta (enviada como plantilla real):

{
  "success": true,
  "data": {
    "message_id": 15300,
    "conversation_id": 913,
    "channel": "whatsapp",
    "delivery_mode": "template",
    "status": "sent"
  }
}

Respuesta cuando el canal no soporta plantillas (se manda como texto):

{
  "success": true,
  "data": {
    "message_id": 15301,
    "conversation_id": 927,
    "channel": "instagram",
    "delivery_mode": "text_fallback",
    "status": "sent"
  }
}

Comportamiento por canal:

Canal¿Cómo se envía?
WhatsApp Business (Cloud API)Plantilla real aprobada por Meta. Soporta header_param y button_params
WhatsApp Web (sin Cloud API)Texto libre con las variables ya reemplazadas. header_param y button_params se ignoran
Instagram / Facebook / Widget WebTexto libre con las variables ya reemplazadas. header_param y button_params se ignoran

Ejemplo: notificar pedido en camino

async function notificarPedidoEnCamino(conversationId, nombreCliente, numeroPedido) {
  const response = await fetch(
    `https://api.yolani.co/api/v1/conversations/${conversationId}/messages/template`,
    {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${process.env.YOLANI_API_KEY}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        template_name: 'pedido_en_camino',
        body_params: [nombreCliente, numeroPedido],
        client_request_id: `pedido-${numeroPedido}-en-camino`,
      }),
    },
  );
  return response.json();
}
import requests

def notificar_pedido_entregado(conversation_id, nombre_cliente, numero_pedido):
    response = requests.post(
        f"https://api.yolani.co/api/v1/conversations/{conversation_id}/messages/template",
        headers={"Authorization": f"Bearer {YOLANI_API_KEY}"},
        json={
            "template_name": "pedido_entregado",
            "body_params": [nombre_cliente, numero_pedido],
        },
    )
    return response.json()

Errores propios de plantillas

HTTPCódigoDescripción
404TEMPLATE_NOT_FOUNDNo existe una plantilla aprobada con ese template_name (y language, si lo enviaste)
400TEMPLATE_NOT_APPROVEDLa plantilla existe pero Meta aún no la aprueba
400TEMPLATE_PARAMS_MISMATCHLa cantidad de body_params no coincide con las variables de la plantilla

Ver también Errores y límites para los códigos generales de la API.