Crea una plantilla y la envía a Meta para su aprobación. La respuesta indica que fue enviada, no aprobada: consulta el resultado con GET /retailers/api/v1/whatsapp_templates/{id}.
Soporta texto, imagen, video, documento, botones, carrusel, oferta limitada y autenticación (OTP).
Crea y consulta las plantillas de WhatsApp (HSM) desde la API. Esta sección explica cómo se arma el contenido de una plantilla (variables, ejemplos, imágenes, formato) y qué errores devuelve la API cuando una regla no se cumple.
Versión actual: texto, imagen, video y documento; botones de respuesta rápida y de llamado a la acción; carrusel; oferta limitada; plantillas de autenticación (código OTP); y soporte para cuentas con varios números de WhatsApp. La ubicación (
location) aún no está disponible por API.
Todas las peticiones llevan el header Api-Key del retailer.
| Caso | Respuesta |
|---|---|
Sin header Api-Key | 401 |
Api-Key desconocida | 404 Resource not found |
El límite global es de 10 peticiones por segundo por IP.
| Método | Ruta | Descripción |
|---|---|---|
POST | /retailers/api/v1/whatsapp_templates | Crea la plantilla y la envía a Meta para su aprobación |
GET | /retailers/api/v1/whatsapp_templates/:id | Consulta una plantilla en cualquier estado. :id es el id numérico o el internal_id |
GET | /retailers/api/v1/whatsapp_templates | Lista solo las plantillas accepted y disabled (las utilizables para enviar) |
GET | /retailers/api/v1/whatsapp_templates/integrations | Lista los números de WhatsApp con los que se pueden crear plantillas (cuentas con varios números) |
La creación es asíncrona de cara a Meta: la respuesta indica que la plantilla fue enviada, no aprobada. Consulta el resultado con GET /whatsapp_templates/:id.
| Campo | Obligatorio | Descripción |
|---|---|---|
name | Sí | Nombre de la plantilla. Se normaliza: minúsculas, espacios → _ y solo a-z, 0-9, _. Único por retailer (sin distinguir mayúsculas). Máx. 512 |
language | Sí | spanish o english (también se aceptan es_ES y en_US) |
category | Sí | MARKETING, UTILITY o AUTHENTICATION (ver Autenticación) |
template_type | Sí (salvo autenticación) | text, image, video, document o carousel |
text | Sí (salvo autenticación) | Cuerpo del mensaje (en un carrusel, el texto principal sobre las tarjetas). Máx. 1024 caracteres sin contar las variables |
body_examples | Sí, si text tiene variables | Un valor de ejemplo por variable, en orden |
header_text | No | Encabezado de texto. Solo con template_type: text. Máx. 60 caracteres, sin HTML |
media_url | Sí en image, video y document | URL https pública del archivo (ver Imágenes, video y documentos). No se permite en text |
buttons | No | Lista de botones (ver Botones). No va en carruseles ni con una oferta |
offer | No | Oferta limitada (ver Oferta limitada) |
cards y cards_media_type | Solo en carousel | Tarjetas y tipo de media común (ver Carrusel) |
add_security_recommendation, code_expiry_minutes, code_example | Solo en AUTHENTICATION | Opciones del código (ver Autenticación) |
team_id | No | Equipo del retailer al que se asigna la plantilla |
integration_id | Solo si hay más de un número activo | Número de WhatsApp con el que se crea (ver Varios números) |
integration_platform | No | Solo para confirmar la plataforma de integration_id; se deduce sola |
Las variables son los huecos que se rellenan al enviar el mensaje (nombre del cliente, número de pedido…).
- Sintaxis:
{{1}},{{2}},{{3}}… — número entero mayor que 0 entre dobles llaves. - Deben ser correlativas desde
{{1}}y no repetirse.{{1}} … {{3}}(salta el 2) o{{1}} … {{1}}se rechazan. - El texto no puede empezar ni terminar con una variable (regla de Meta):
Hola {{1}}, graciases válido;{{1}} graciasno. - No se permiten nombres:
{{nombre}}es inválido.
Meta revisa la plantilla con valores de muestra. Envía en body_examples un valor por variable, en el mismo orden, sin vacíos:
{
"text": "Hola {{1}}, tu pedido {{2}} va en camino",
"body_examples": ["Ana", "ORD-1042"]
}Mercately construye el ejemplo que ve Meta reemplazando cada variable: Hola [Ana], tu pedido [ORD-1042] va en camino. Estos valores solo sirven para la revisión; los valores reales se indican al enviar el mensaje (template_params).
Si el texto no tiene variables, body_examples debe omitirse o ir vacío.
Al ser aprobada, Mercately guarda internamente el text con cada {{n}} convertido en * y escapa los * literales como \*. Por eso, en una plantilla accepted, text se ve así: Hola *, tu pedido * va en camino.
Para no tener que interpretar eso, las respuestas incluyen body: el mismo texto con las variables restauradas como {{1}}, {{2}}… y los asteriscos de formato (*negrita*) como los escribiste. Usa body para leer el contenido de una plantilla; text se conserva solo por compatibilidad con el listado existente. En plantillas aún no aprobadas, body y text coinciden.
WhatsApp admite formato con marcas dentro de text:
| Marca | Resultado |
|---|---|
*texto* | negrita |
_texto_ | cursiva |
~texto~ | |
`texto` | monoespaciado |
El texto se envía tal cual a Meta, que valida el formato. Evita HTML.
Una plantilla tiene un solo encabezado:
template_type | Encabezado |
|---|---|
text | Opcional: header_text (máx. 60, no admite variables, sin HTML) |
image | La imagen indicada en media_url |
video | El video indicado en media_url |
document | El PDF indicado en media_url |
header_text no se permite junto a image, video o document.
Para incrustar un archivo en la plantilla indica su URL en media_url. Mercately lo descarga, lo sube al proveedor de WhatsApp y usa esa referencia como ejemplo de cabecera en la revisión de Meta.
| Tipo | Formato | Tamaño máximo |
|---|---|---|
image | JPG, PNG | 5 MB |
video | MP4 | 16 MB |
document | 40 MB |
Requisitos de la URL:
- Debe ser
https(puerto 443), sin usuario ni contraseña, y accesible públicamente sin autenticación. - El tipo se valida por el contenido real del archivo, no por la extensión ni por el
Content-Type. - Se siguen hasta 3 redirecciones, cada una debe ser
httpsy pública. - Por seguridad se rechazan direcciones privadas, locales o de infraestructura interna.
- La descarga tiene tiempos de espera cortos: el servidor debe responder en pocos segundos.
El archivo no se almacena en Mercately: se usa solo durante la creación.
Una plantilla puede llevar botones de respuesta rápida o botones de llamado a la acción, pero no ambos a la vez. No envíes interactive_action: se deduce de los botones (quick_reply o call_to_action) y, si lo envías, se rechaza.
Cada botón es un objeto con type en mayúsculas y un text de máx. 20 caracteres. Los textos no pueden repetirse (sin distinguir mayúsculas). Un botón solo admite los campos de su tipo; cualquier otro se rechaza con unknown_field.
type | Campos | Límite |
|---|---|---|
QUICK_REPLY | text | Hasta 3 botones |
URL | text, url, example (solo si la URL es dinámica) | Hasta 1 por plantilla |
PHONE_NUMBER | text, phone_number | Hasta 1 por plantilla |
Los botones URL y PHONE_NUMBER pueden combinarse entre sí (máx. 2 en total). No se pueden mezclar con QUICK_REPLY.
phone_number va en formato internacional con + y sin espacios: +573001234567.
- Estática: una URL completa
http(s)://…, sin variables y sinexample. - Dinámica: la URL termina en
{{1}}(la única variable permitida, y solo al final). Se completa al enviar el mensaje. Exigeexamplecon una URL completa de muestra que empiece igual que la parte fija:
{
"type": "URL",
"text": "Rastrear pedido",
"url": "https://tienda.com/track/{{1}}",
"example": ["https://tienda.com/track/ORD-1042"]
}example también puede enviarse como texto simple. La URL admite hasta 2000 caracteres.
Un carrusel es un mensaje principal (text) con 2 a 10 tarjetas deslizables. Se crea con template_type: "carousel".
| Campo | Obligatorio | Descripción |
|---|---|---|
text / body_examples | Sí | Mensaje principal sobre las tarjetas, con las mismas reglas de variables que cualquier cuerpo |
cards_media_type | Sí | image o video: es el mismo tipo en todas las tarjetas |
cards | Sí | Lista de 2 a 10 tarjetas |
Cada tarjeta es un objeto con estos campos (cualquier otro se rechaza con unknown_field):
| Campo de la tarjeta | Obligatorio | Descripción |
|---|---|---|
body | Sí | Texto de la tarjeta, máx. 160 caracteres, con las mismas reglas de variables ({{1}}, {{2}}…, correlativas y sin empezar ni terminar en variable) |
body_examples | Si el body tiene variables | Un ejemplo por variable de esa tarjeta |
media_url | Sí | URL https del archivo de la tarjeta (mismas reglas, formatos y tamaños que los archivos) |
buttons | Sí | 1 o 2 botones (QUICK_REPLY, URL o PHONE_NUMBER), texto de hasta 25 caracteres |
Reglas del conjunto:
- Todas las tarjetas deben tener los mismos tipos de botón en el mismo orden (si la primera lleva
URL, todas llevanURL); los textos y las URL pueden diferir. Si no,cards[n].buttons / mismatch. - En un carrusel los botones pueden mezclarse (por ejemplo
QUICK_REPLY+URL), a diferencia de una plantilla normal. - El carrusel no admite
header_text,media_urlnibuttonsen el nivel principal. - Los errores indican la tarjeta:
cards[1].body,cards[0].media_url,cards[2].buttons[0].text…
{
"name": "coleccion_octubre", "language": "spanish", "category": "MARKETING", "template_type": "carousel",
"text": "Hola {{1}}, mira nuestra colección", "body_examples": ["Ana"],
"cards_media_type": "image",
"cards": [
{ "body": "Camisa azul", "media_url": "https://cdn.mitienda.com/azul.png",
"buttons": [{ "type": "URL", "text": "Comprar", "url": "https://tienda.com/azul" }] },
{ "body": "Pantalón {{1}} nuevo", "body_examples": ["rojo"], "media_url": "https://cdn.mitienda.com/rojo.png",
"buttons": [{ "type": "URL", "text": "Comprar", "url": "https://tienda.com/rojo" }] }
]
}Una oferta limitada es una plantilla de marketing con un encabezado de oferta (por ejemplo «Solo hoy»), un botón para ir a la tienda y, opcionalmente, una cuenta regresiva con un código de cupón.
Requisitos: category: "MARKETING", template_type image o video (con su media_url) y el objeto offer. No se envía buttons: la oferta define los suyos.
Campo de offer | Obligatorio | Descripción |
|---|---|---|
title | Sí | Título de la oferta, máx. 16 caracteres |
url | Sí | Botón { "text", "url", "example" }, con las mismas reglas que un botón URL (estática o dinámica con {{1}} al final y example) |
expires_in_minutes | No | Duración de la oferta en minutos desde el envío, entero ≥ 1. Activa la cuenta regresiva |
code | Si hay expires_in_minutes | Código de cupón de ejemplo que se copia con el botón. No se permite sin expiración |
code_button_text | No | Texto del botón de copiar (máx. 25). Por defecto «Copiar código de oferta» / «Copy offer code» |
{
"name": "oferta_viernes", "language": "spanish", "category": "MARKETING", "template_type": "image",
"media_url": "https://cdn.mitienda.com/oferta.png",
"text": "Hola {{1}}, solo por hoy tenemos un descuento para ti", "body_examples": ["Ana"],
"offer": {
"title": "Solo hoy",
"url": { "text": "Comprar", "url": "https://tienda.com/oferta" },
"expires_in_minutes": 120,
"code": "VIP10"
}
}
expires_in_minutesse cuenta desde el momento en que Mercately envía la plantilla al proveedor.
Con category: "AUTHENTICATION" la plantilla sirve para enviar códigos de verificación. Mercately genera el texto y el botón, igual que la pantalla de creación: no envíes text, body_examples, header_text, media_url, buttons, offer ni cards (se rechazan con not_allowed).
| Campo | Obligatorio | Descripción |
|---|---|---|
name, language, category | Sí | language: spanish o english |
template_type | No | Si se envía, debe ser text |
code_example | No | Código de muestra que aparece en el texto (por defecto 123456), máx. 30 |
add_security_recommendation | No | true agrega «Por tu seguridad, no lo compartas.» (en inglés: «For your security, do not share this code.») |
code_expiry_minutes | No | Entero de 1 a 90. Agrega «Este código caduca en N minutos.» (en inglés: «This code expires in N minutes.») |
El texto resultante en español, con ambas opciones, es:
Tu código de verificación es: 123456
Por tu seguridad, no lo compartas.
Este código caduca en 10 minutos.y el botón es Copiar código (Copy code en inglés), de tipo OTP / COPY_CODE. Puedes leer ambos en la respuesta (body y buttons).
{ "name": "codigo_login", "language": "spanish", "category": "AUTHENTICATION",
"add_security_recommendation": true, "code_expiry_minutes": 10 }Si la cuenta tiene varios números, cada plantilla se crea para uno de ellos.
- Consulta los disponibles:
GET /retailers/api/v1/whatsapp_templates/integrations. Devuelve solo los activos y compatibles con plantillas, conid,platform,name,phone_numberystatus. - Envía el
idelegido comointegration_idal crear la plantilla. La plataforma se deduce sola.
{ "integrations": [ { "id": "int-1", "platform": "whatsapp_gupshup_messages", "name": "Ventas", "phone_number": "+573001234567", "status": "active" } ] }- Si solo hay un número activo,
integration_ides opcional y se usa ese. - Si hay varios y no lo envías, la API responde
422 integration_id / requiredy lista los ids disponibles. - En cuentas con un solo número,
integration_idno aplica y se rechaza connot_applicable. - Una plantilla pertenece al número con el que se creó: no se comparte entre números.
POST → submitted → accepted (Meta la aprobó: ya se puede usar para enviar)
→ rejected (Meta la rechazó: ver `reason`)
accepted ↔ disabledstatus | Significado |
|---|---|
pending | Creada, aún sin enviar a Meta |
submitted | Enviada a Meta, a la espera de aprobación |
accepted | Aprobada. Aparece en el listado y se puede usar en send_notification_by_id con su internal_id |
rejected | Rechazada. El motivo está en reason |
disabled | Desactivada |
deleted | Eliminada |
Para saber cuándo se aprueba, consulta periódicamente GET /whatsapp_templates/:id (por ejemplo cada minuto; Meta suele resolver en minutos u horas).
Éxito (201)
{
"template": {
"id": 1234,
"internal_id": "7f3f0c1e-1f6b-4a43-9a25-0d1a5f0f0a11",
"name": "order_update",
"status": "submitted",
"category": "UTILITY",
"language": "spanish",
"template_type": "text",
"text": "Hola {{1}}, tu pedido {{2}} va en camino",
"body": "Hola {{1}}, tu pedido {{2}} va en camino",
"header_text": "Tu pedido",
"reason": null,
"created_at": "2026-10-07T12:40:37.636Z"
}
}id es estable desde el primer momento. internal_id es el identificador de Meta/proveedor y puede ser null mientras la plantilla está pending.
Error
{
"message": "Template could not be created",
"errors": [
{ "field": "text", "code": "variables_not_sequential", "detail": "variables must be sequential starting at {{1}}" }
]
}Cuando Meta rechaza la plantilla se responde 422 con code: provider_rejected, el motivo en detail y la plantilla guardada en template (con status: rejected).
curl -X POST https://app.mercately.com/retailers/api/v1/whatsapp_templates \
-H "Api-Key: $API_KEY" -H "Content-Type: application/json" \
-d '{
"name": "order_update", "language": "spanish", "category": "UTILITY", "template_type": "text",
"header_text": "Tu pedido",
"text": "Hola {{1}}, tu pedido {{2}} va en camino",
"body_examples": ["Ana", "ORD-1042"]
}'curl -X POST https://app.mercately.com/retailers/api/v1/whatsapp_templates \
-H "Api-Key: $API_KEY" -H "Content-Type: application/json" \
-d '{
"name": "promo_octubre", "language": "spanish", "category": "MARKETING", "template_type": "image",
"media_url": "https://cdn.mitienda.com/promos/octubre.png",
"text": "Hola {{1}}, tenemos una promo para ti: *20% de descuento* hasta el viernes",
"body_examples": ["Ana"]
}'curl -X POST https://app.mercately.com/retailers/api/v1/whatsapp_templates \
-H "Api-Key: $API_KEY" -H "Content-Type: application/json" \
-d '{
"name": "catalogo_2026", "language": "spanish", "category": "MARKETING", "template_type": "document",
"media_url": "https://cdn.mitienda.com/catalogo.pdf",
"text": "Hola, aquí tienes nuestro catálogo actualizado"
}'curl -X POST https://app.mercately.com/retailers/api/v1/whatsapp_templates \
-H "Api-Key: $API_KEY" -H "Content-Type: application/json" \
-d '{
"name": "confirmar_cita", "language": "spanish", "category": "UTILITY", "template_type": "text",
"text": "Hola {{1}}, ¿confirmas tu cita del {{2}}?",
"body_examples": ["Ana", "viernes 10 de octubre"],
"buttons": [
{ "type": "QUICK_REPLY", "text": "Sí, confirmo" },
{ "type": "QUICK_REPLY", "text": "Reprogramar" }
]
}'curl -X POST https://app.mercately.com/retailers/api/v1/whatsapp_templates \
-H "Api-Key: $API_KEY" -H "Content-Type: application/json" \
-d '{
"name": "pedido_enviado", "language": "spanish", "category": "UTILITY", "template_type": "image",
"media_url": "https://cdn.mitienda.com/envio.png",
"text": "Hola {{1}}, tu pedido salió hoy",
"body_examples": ["Ana"],
"integration_id": "int-1",
"buttons": [
{ "type": "URL", "text": "Rastrear", "url": "https://tienda.com/track/{{1}}",
"example": ["https://tienda.com/track/ORD-1042"] },
{ "type": "PHONE_NUMBER", "text": "Llámanos", "phone_number": "+573001234567" }
]
}'curl https://app.mercately.com/retailers/api/v1/whatsapp_templates/7f3f0c1e-1f6b-4a43-9a25-0d1a5f0f0a11 \
-H "Api-Key: $API_KEY"Estos campos se rechazan con 422 y code: field_not_supported (no se ignoran en silencio): interactive_action (se deduce de buttons) y footer. Además, template_type: location responde not_supported_yet: la creación de plantillas de ubicación aún no está disponible por API.
| HTTP | field | code | Qué hacer |
|---|---|---|---|
| 422 | cualquiera | required | Falta un campo obligatorio |
| 422 | name | invalid, too_long | El nombre debe tener letras o números y máx. 512 caracteres |
| 422 | name | (mensaje del modelo) | Ya existe una plantilla con ese nombre |
| 422 | language / category / template_type | invalid | Usa uno de los valores permitidos |
| 422 | template_type | not_supported_yet | location aún no está disponible por API |
| 422 | text | too_long | Máx. 1024 caracteres sin contar variables |
| 422 | text | variables_invalid | Usa {{1}}, {{2}}… (solo enteros) |
| 422 | text | variables_repeated | No repitas una variable |
| 422 | text | variables_not_sequential | Numera desde {{1}} sin saltos |
| 422 | text | variable_at_edge | El texto no puede empezar ni terminar con variable |
| 422 | body_examples | mismatch | Un ejemplo no vacío por variable |
| 422 | body_examples | unexpected | Quita los ejemplos si no hay variables |
| 422 | header_text | too_long, invalid, not_allowed | Máx. 60, sin HTML, solo en text |
| 422 | media_url | required, not_allowed | Obligatoria en image/video/document; no en text |
| 422 | media_url | invalid_url | Usa una URL https válida, sin credenciales |
| 422 | media_url | blocked_host | La URL debe apuntar a un servidor público |
| 422 | media_url | too_many_redirects | Reduce las redirecciones |
| 413 | media_url | file_too_large | El archivo supera el máximo de su tipo |
| 415 | media_url | unsupported_media_type | Formato no permitido para ese tipo |
| 502 | media_url | download_failed | No se pudo descargar el archivo; revisa que sea público |
| 504 | media_url | download_timeout | El servidor del archivo tardó demasiado |
| 422 | team_id | invalid | El equipo no pertenece al retailer |
| 422 | buttons | invalid | Debe ser una lista de objetos |
| 422 | buttons | mixed_types | No mezcles QUICK_REPLY con URL/PHONE_NUMBER |
| 422 | buttons | too_many | Máx. 3 quick replies o 2 botones de llamado a la acción |
| 422 | buttons | duplicate_type | Solo un botón URL y uno PHONE_NUMBER |
| 422 | buttons | duplicate_text | Los textos de los botones deben ser únicos |
| 422 | buttons[n] | unknown_field | El botón trae un campo que no corresponde a su tipo |
| 422 | buttons[n].type | invalid | QUICK_REPLY, URL o PHONE_NUMBER en mayúsculas |
| 422 | buttons[n].text | required, too_long | Obligatorio, máx. 20 caracteres |
| 422 | buttons[n].url | required, invalid, too_long | URL http(s) válida; {{1}} solo al final; máx. 2000 |
| 422 | buttons[n].example | mismatch, not_allowed | La URL dinámica exige un ejemplo completo; la estática no lleva example |
| 422 | buttons[n].phone_number | invalid | Formato internacional, p. ej. +573001234567 |
| 422 | cards | required, invalid, too_few, too_many | Un carrusel necesita de 2 a 10 tarjetas (lista de objetos) |
| 422 | cards[n] | unknown_field | La tarjeta trae un campo no permitido (solo body, body_examples, media_url, buttons) |
| 422 | cards[n].body / .body_examples | (reglas de variables) | Mismas reglas que el cuerpo, con máx. 160 caracteres |
| 422 | cards[n].media_url | required | Toda tarjeta lleva su archivo (también download_failed, unsupported_media_type, file_too_large… indicando la tarjeta) |
| 422 | cards[n].buttons | required, too_many, mismatch | 1 o 2 botones, con los mismos tipos que la primera tarjeta |
| 422 | cards_media_type | required, invalid, not_allowed | image o video, solo en carruseles |
| 422 | offer | requires_marketing, not_allowed, invalid, unknown_field | La oferta es solo de marketing, no va con carrusel y es un objeto con sus claves |
| 422 | template_type | invalid_for_offer | Una oferta necesita image o video |
| 422 | offer.title | required, too_long | Obligatorio, máx. 16 caracteres |
| 422 | offer.url… | (reglas de botón URL) | Se reporta como offer.url.text, offer.url.url, offer.url.example |
| 422 | offer.expires_in_minutes | invalid | Entero de al menos 1 |
| 422 | offer.code | required, too_long, not_allowed | Obligatorio si la oferta expira; no se permite sin expiración |
| 422 | offer.code_button_text | too_long, not_allowed | Máx. 25 y solo con expiración |
| 422 | text, buttons, media_url… | not_allowed | En AUTHENTICATION esos campos los genera Mercately |
| 422 | code_expiry_minutes | invalid | Entero de 1 a 90 |
| 422 | code_example | invalid, too_long | Texto no vacío, máx. 30 |
| 422 | add_security_recommendation | invalid | true o false |
| 422 | integration_id | required | Hay varios números activos: elige uno |
| 422 | integration_id | not_found, not_active | No existe o no está activo para plantillas |
| 422 | integration_id | unavailable | No hay ningún número activo |
| 422 | integration_id / integration_platform | not_applicable, mismatch | La cuenta tiene un solo número, o la plataforma no coincide |
| 502 | integrations | integrations_unavailable | No se pudieron consultar los números; reintenta |
| 422 | cualquiera | field_not_supported | Campo aún no disponible |
| 422 | template | provider_rejected | Meta/proveedor rechazó la plantilla; ver detail |
Se normaliza (minúsculas, espacios a _, solo a-z, 0-9, _). Único por retailer.
Obligatorio salvo en AUTHENTICATION.
Cuerpo del mensaje, máx. 1024 caracteres sin contar variables. Obligatorio salvo en AUTHENTICATION.
Un valor de ejemplo por variable, en orden. Obligatorio si text tiene variables.
[ "Ana", "ORD-1042" ]
Solo en carousel. Todas las tarjetas llevan los mismos tipos de botón en el mismo orden.
Número de WhatsApp con el que se crea. Obligatorio si hay más de uno activo (ver GET .../integrations).
- Production serverhttps://app.mercately.com/retailers/api/v1/whatsapp_templates
- Shops API Production serverhttps://mercately.shop/retailers/api/v1/whatsapp_templates
curl -i -X POST \
https://app.mercately.com/retailers/api/v1/whatsapp_templates \
-H 'Content-Type: application/json' \
-H 'api-key: YOUR_API_KEY_HERE' \
-d '{
"name": "order_update",
"language": "spanish",
"category": "UTILITY",
"template_type": "text",
"header_text": "Tu pedido",
"text": "Hola {{1}}, tu pedido {{2}} va en camino",
"body_examples": [
"Ana",
"ORD-1042"
]
}'{ "template": { "id": 1234, "internal_id": "7f3f0c1e-1f6b-4a43-9a25-0d1a5f0f0a11", "name": "order_update", "status": "submitted", "category": "UTILITY", "language": "spanish", "template_type": "text", "text": "Hola {{1}}, tu pedido {{2}} va en camino", "body": "Hola {{1}}, tu pedido {{2}} va en camino", "header_text": "Tu pedido", "interactive_action": "string", "buttons": [ … ], "cards": [ … ], "offer": { … }, "reason": "string", "created_at": "2026-10-07T12:40:37.636Z" } }