Inicio / Tipos de mensaje / Plantilla (HSM)

Enviar plantilla (HSM)

Las plantillas certificadas (HSM) son la única forma de iniciar conversación con un cliente fuera de la ventana de 24 horas. Deben estar previamente aprobadas por Meta. Útiles para confirmaciones de pedido, OTPs, recordatorios de pago, marketing y notificaciones masivas.

POST https://api.wis.chat/v22.0/{tid}/messages

Aprobación previa requerida. Crea tus plantillas en Meta Business Manager. Una vez aprobadas por Meta, se sincronizan automáticamente al panel de Wis.Chat (wis.chat/wischat → Plantillas), donde puedes ver el listado, el idioma de cada una y su estado de aprobación. Sólo las plantillas con estado APPROVED pueden enviarse por la API.

Prueba rápida con hello_world

Para verificar conectividad sin necesidad de crear y esperar la aprobación de una plantilla propia, puedes usar hello_world: una plantilla pre-aprobada por defecto en toda cuenta de WhatsApp Business. Aparece automáticamente en tu panel de Wis.Chat junto al resto. Es útil para tu primera llamada a la API:

{
  "messaging_product": "whatsapp",
  "to": "593999999999",
  "type": "template",
  "template": {
    "name": "hello_world",
    "language": { "code": "en_US" }
  }
}

El mensaje llega en inglés con un texto fijo ("Hello World!") que no se puede modificar: es solo para verificación técnica. Para mensajes reales, crea tus propias plantillas.

Ejemplo con variables en el body

Una plantilla típica de producción tiene variables marcadas con {{1}}, {{2}}, etc. en el cuerpo, que se reemplazan dinámicamente al enviar. En este ejemplo, una plantilla confirmacion_pago con 3 variables:

{
  "messaging_product": "whatsapp",
  "to": "593999999999",
  "type": "template",
  "template": {
    "name": "confirmacion_pago",
    "language": { "code": "es" },
    "components": [
      {
        "type": "body",
        "parameters": [
          { "type": "text", "text": "Juan Pérez" },    // {{1}} — nombre
          { "type": "text", "text": "$ 145.50" },      // {{2}} — monto
          { "type": "text", "text": "FAC-001-4521" }   // {{3}} — referencia
        ]
      }
    ]
  }
}

El nombre exacto de la plantilla, el idioma y la cantidad de variables debe coincidir con lo que tienes aprobado. Consulta tus plantillas disponibles en el panel para ver el nombre exacto, el idioma y los placeholders esperados de cada una.

Estructura del objeto template

CampoTipoRequeridoDescripción
name string requerido Nombre exacto de la plantilla aprobada (case-sensitive). Lo encuentras en wis.chat/wischat → Plantillas, sincronizado desde Meta.
language object requerido Objeto con code: el idioma de la plantilla. Ej: es, en_US, pt_BR. El idioma de cada plantilla también se ve en el panel.
components array opcional Lista de componentes (header, body, button) con sus parámetros dinámicos.

Componentes disponibles

Body con variables

El componente body es el más común. Contiene las variables {{1}}, {{2}}, etc. que se reemplazan en el orden del array parameters.

{
  "type": "body",
  "parameters": [
    { "type": "text", "text": "Oscar" },
    { "type": "text", "text": "#4521" }
  ]
}

Header con imagen

Si tu plantilla aprobada tiene un header con imagen, video o documento, lo envías así:

{
  "type": "header",
  "parameters": [
    {
      "type": "image",
      "image": { "link": "https://midominio.com/banner.jpg" }
    }
  ]
}

Otros tipos de header soportados:

Botón URL dinámico

Para botones que tienen una URL con un parámetro al final (ej: https://app.com/orden/{{1}}):

{
  "type": "button",
  "sub_type": "url",
  "index": "0",
  "parameters": [
    { "type": "text", "text": "4521" }
  ]
}

Botón quick reply (con payload)

{
  "type": "button",
  "sub_type": "quick_reply",
  "index": "0",
  "parameters": [
    { "type": "payload", "payload": "CONFIRMAR_4521" }
  ]
}

Ejemplo completo · plantilla con todo

Plantilla con header de imagen, body con 3 variables y botón URL dinámico:

{
  "messaging_product": "whatsapp",
  "to": "593999999999",
  "type": "template",
  "template": {
    "name": "confirmacion_pedido",
    "language": { "code": "es" },
    "components": [
      {
        "type": "header",
        "parameters": [
          { "type": "image", "image": { "link": "https://midominio.com/logo.jpg" } }
        ]
      },
      {
        "type": "body",
        "parameters": [
          { "type": "text", "text": "Oscar" },
          { "type": "text", "text": "#4521" },
          { "type": "text", "text": "$ 145.50" }
        ]
      },
      {
        "type": "button",
        "sub_type": "url",
        "index": "0",
        "parameters": [
          { "type": "text", "text": "4521" }
        ]
      }
    ]
  }
}

Implementaciones por lenguaje

curl -X POST "https://api.wis.chat/v22.0/TU_ID_LINEA/messages" \
  -H "Authorization: Bearer TU_CODIGO_SEGURIDAD" \
  -H "Content-Type: application/json" \
  -d '{
    "messaging_product": "whatsapp",
    "to": "593999999999",
    "type": "template",
    "template": {
      "name": "confirmacion_pago",
      "language": { "code": "es" },
      "components": [{
        "type": "body",
        "parameters": [
          {"type":"text","text":"Juan Pérez"},
          {"type":"text","text":"$ 145.50"},
          {"type":"text","text":"FAC-001-4521"}
        ]
      }]
    }
  }'
function enviarPlantillaWischat($tid, $token, $to, $nombre, $idioma, $variables = []) {
    $params = array_map(function($v) {
        return ['type' => 'text', 'text' => $v];
    }, $variables);

    $payload = [
        'messaging_product' => 'whatsapp',
        'to'                => $to,
        'type'              => 'template',
        'template'          => [
            'name'       => $nombre,
            'language'   => ['code' => $idioma],
            'components' => empty($params) ? [] : [[
                'type'       => 'body',
                'parameters' => $params,
            ]],
        ],
    ];

    $ch = curl_init("https://api.wis.chat/v22.0/{$tid}/messages");
    curl_setopt_array($ch, [
        CURLOPT_POST           => true,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_POSTFIELDS     => json_encode($payload),
        CURLOPT_HTTPHEADER     => [
            "Authorization: Bearer {$token}",
            'Content-Type: application/json',
        ],
    ]);
    $res  = json_decode(curl_exec($ch), true);
    curl_close($ch);
    return $res;
}

// Uso:
$resp = enviarPlantillaWischat(
    15,
    'TU_CODIGO_SEGURIDAD',
    '593999999999',
    'confirmacion_pago',
    'es',
    ['Juan Pérez', '$ 145.50', 'FAC-001-4521']
);

if ($resp['success'] ?? false) {
    $wamid = $resp['messages'][0]['id'];
    echo "Mensaje enviado: {$wamid}";
} else {
    echo "Error: " . ($resp['message'] ?? 'desconocido');
}
async function enviarPlantilla({ tid, token, to, nombre, idioma, variables = [] }) {
  const params = variables.map(v => ({ type: 'text', text: v }));

  const res = await fetch(`https://api.wis.chat/v22.0/${tid}/messages`, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${token}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      messaging_product: 'whatsapp',
      to,
      type: 'template',
      template: {
        name: nombre,
        language: { code: idioma },
        components: params.length ? [{ type: 'body', parameters: params }] : [],
      },
    }),
  });
  return await res.json();
}

// Uso:
const data = await enviarPlantilla({
  tid: 15,
  token: 'TU_CODIGO_SEGURIDAD',
  to: '593999999999',
  nombre: 'confirmacion_pago',
  idioma: 'es',
  variables: ['Juan Pérez', '$ 145.50', 'FAC-001-4521'],
});

console.log(data);
import requests

def enviar_plantilla(tid, token, to, nombre, idioma, variables=None):
    variables = variables or []
    params = [{'type': 'text', 'text': v} for v in variables]

    payload = {
        'messaging_product': 'whatsapp',
        'to': to,
        'type': 'template',
        'template': {
            'name': nombre,
            'language': {'code': idioma},
            'components': [{'type': 'body', 'parameters': params}] if params else [],
        },
    }

    res = requests.post(
        f'https://api.wis.chat/v22.0/{tid}/messages',
        headers={
            'Authorization': f'Bearer {token}',
            'Content-Type': 'application/json',
        },
        json=payload
    )
    return res.json()


# Uso:
data = enviar_plantilla(
    tid=15,
    token='TU_CODIGO_SEGURIDAD',
    to='593999999999',
    nombre='confirmacion_pago',
    idioma='es',
    variables=['Juan Pérez', '$ 145.50', 'FAC-001-4521'],
)
print(data)

Listar plantillas disponibles

Puedes consultar el listado de plantillas activas y su estado de aprobación desde tu panel en wis.chat/wischat → Plantillas. Sólo las que tienen estado APPROVED son aptas para envío.