Saltar al contenido principal

Plantillas

Una plantilla es un mensaje aprobado previamente por Meta. Es la única forma de escribir a alguien fuera de la ventana de 24 horas.

Las plantillas pertenecen a la WABA (cuenta de empresa), no a un número — todos los números de la misma cuenta comparten la misma biblioteca.

Categorías​

CategoríaPara quéCoste
UTILITYConfirmación, actualización de pedido, recordatorio de citabajo
AUTHENTICATIONCódigo de verificaciónbajo
MARKETINGPromoción, novedad, reenganchemás alto

Meta reclasifica las plantillas que considera mal categorizadas. Una «utilitaria» que en la práctica vende pasa a MARKETING, y el coste sube. allowCategoryChange: true (el valor por defecto) deja que eso ocurra en lugar de rechazar la plantilla.

Ciclo de vida​

La aprobación tarda de minutos a horas. El resultado llega por el webhook message_template_status_update — no lo consultes en bucle.

PAUSED ocurre cuando muchos clientes bloquean o denuncian mensajes de esa plantilla. Vuelve sola si la calidad se recupera; si empeora, pasa a DISABLED y deja de enviarse.

Variables y ejemplos​

Toda plantilla con variables debe declarar ejemplos — sin ellos Meta la rechaza. Joinotify lo valida antes de enviar y devuelve 422 con el campo issues señalando el problema, lo que evita el ciclo lento de enviar, esperar y ser rechazado.

Formato posicional​

{
"name": "confirmacao_pedido",
"category": "UTILITY",
"language": "pt_BR",
"components": [
{
"type": "BODY",
"text": "Hola {{1}}, tu pedido {{2}} está confirmado y llega en {{3}}.",
"example": { "body_text": [["María", "1042", "2 días hábiles"]] }
}
]
}

body_text es un array de arrays — Meta permite más de un juego de ejemplos. Con uno basta.

Formato nombrado​

{
"type": "BODY",
"text": "Hola {{nombre}}, tu pedido {{numero}} está confirmado.",
"example": {
"body_text_named_params": [
{ "param_name": "nombre", "example": "María" },
{ "param_name": "numero", "example": "1042" }
]
}
}

Más legible cuando la plantilla tiene muchas variables. Elige un formato y quédate con él.

Las reglas validadas​

ReglaPor qué
Toda variable necesita ejemploMeta usa el ejemplo para revisar la plantilla
El ejemplo no puede estar vacíoRechazo automático
Numeración posicional sin huecos{{1}}, {{3}} sin {{2}} es inválido
No mezclar posicional y nombradoUn formato por plantilla
Cabecera de texto: como máximo 1 variableLímite de Meta
Pie: ninguna variableLímite de Meta
Botón de URL con variable exige ejemplo de URL completaMeta valida el dominio

Cuando algo falla:

422 Unprocessable Entity
{
"error": {
"message": "Invalid template components.",
"type": "invalid_request",
"issues": [{ "path": "components[0].text", "message": "Variable {{2}} has no example value." }]
}
}

Crear​

curl -X POST https://api.joinotify.com/templates \
-H 'Authorization: Bearer sk_live_xxx' \
-H 'Content-Type: application/json' \
-d '{
"name": "confirmacao_pedido",
"category": "UTILITY",
"language": "pt_BR",
"components": [
{ "type": "HEADER", "format": "TEXT", "text": "Pedido confirmado" },
{
"type": "BODY",
"text": "Hola {{1}}, tu pedido {{2}} está confirmado.",
"example": { "body_text": [["María", "1042"]] }
},
{ "type": "FOOTER", "text": "Joinotify" },
{
"type": "BUTTONS",
"buttons": [
{ "type": "URL", "text": "Seguir", "url": "https://ejemplo.com/pedidos/{{1}}", "example": ["https://ejemplo.com/pedidos/1042"] }
]
}
]
}'

El name solo acepta minúsculas, dígitos y guion bajo. Es la clave de envío — elígelo pensando en cómo lo vas a llamar en el código, no en cómo lo ve el cliente.

Listar​

curl 'https://api.joinotify.com/templates?status=APPROVED' \
-H 'Authorization: Bearer sk_live_xxx'

El listado viene de un espejo local, que se actualiza por webhook y se sincroniza bajo demanda cuando supera los 15 minutos.

CampoPara qué
staletrue cuando el espejo está viejo y la sincronización falló
syncedAtCuándo se actualizó el espejo por última vez
syncResumen de la sincronización, si se ejecutó en esta petición
syncErrorMotivo del fallo — los datos en caché se devuelven igualmente

refresh=true fuerza la sincronización; refresh=false sirve solo la caché. Para una pantalla de listado, refresh=false es lo correcto: es instantáneo y el espejo ya se mantiene solo.

Sincronizar manualmente​

curl -X POST https://api.joinotify.com/templates/sync \
-H 'Authorization: Bearer sk_live_xxx' \
-H 'Content-Type: application/json' \
-d '{ "all": true }'

Solo hace falta en dos casos: plantillas creadas directamente en Business Manager, o la sospecha de que se perdió un webhook. Una sincronización ya en curso devuelve 202 y nada se duplica.

Eliminar​

curl -X DELETE 'https://api.joinotify.com/templates/confirmacao_pedido' \
-H 'Authorization: Bearer sk_live_xxx'

La eliminación afecta a todos los idiomas de ese nombre. Los mensajes ya enviados permanecen en las conversaciones de los clientes.

El nombre queda bloqueado 30 días

Después de borrarla, Meta no deja crear otra plantilla con el mismo nombre durante 30 días. Si la intención es corregir el contenido, edítala en lugar de borrarla y recrearla.

Enviar​

curl -X POST https://api.joinotify.com/messages \
-H 'Authorization: Bearer sk_live_xxx' \
-H 'Content-Type: application/json' \
-d '{
"type": "template",
"to": "5541987111527",
"name": "confirmacao_pedido",
"language": "pt_BR",
"components": [
{ "type": "header", "parameters": [{ "type": "text", "text": "Pedido confirmado" }] },
{ "type": "body", "parameters": [
{ "type": "text", "text": "María" },
{ "type": "text", "text": "1042" }
]},
{ "type": "button", "sub_type": "url", "index": "0",
"parameters": [{ "type": "text", "text": "1042" }] }
]
}'

Fíjate en la asimetría: al crear, los componentes van en mayúsculas (BODY); al enviar, en minúsculas (body). Así es en Meta y lo reenviamos sin cambios.

En un botón de URL, el parameter es solo la parte variable — en el ejemplo anterior, 1042 completa https://ejemplo.com/pedidos/{{1}}.

Errores habituales al enviar​

Código de MetaQué pasó
132000El número de parámetros no coincide con la plantilla
132001La plantilla no existe en ese idioma
132005Parámetro demasiado largo
132007Plantilla con formato inválido
132012Formato de parámetro incorrecto
132015Plantilla pausada por calidad
132016Plantilla deshabilitada por calidad

Todos llegan dentro de error.meta en una respuesta 422 meta_error.