# Templates WhatsApp — la realidad brutal

**Este es el archivo más importante del kit.** Las reglas de Meta para templates de WhatsApp Business son medias documentadas, cambiantes y no perdonan. Acá está todo lo que descubrimos en una sesión.

## ¿Qué es un template?

Es una "plantilla" pre-aprobada de mensaje que Meta autoriza a tu negocio enviar. Necesario para:
- Iniciar conversación con un cliente fuera de la ventana de 24h.
- Mandar mensajes con botones interactivos (quick-reply, call-to-action, list-picker).

Sin template aprobado:
- Podés responder texto plano dentro de la ventana de 24h.
- NO podés mandar botones interactivos.

## Tipos que existen en Twilio Content API

| Tipo | Botones máx | ¿Items dinámicos? | ¿Elegible WhatsApp? |
|---|---|---|---|
| `twilio/quick-reply` | 3 botones fijos | ❌ No | ✅ Sí |
| `twilio/list-picker` | menú con N items | ✅ Sí | ❌ **NO para WhatsApp** |
| `twilio/card` | 2 botones + imagen | ❌ No (subtitle rechaza variables) | ✅ Sí |
| `twilio/call-to-action` | botones URL/teléfono | ❌ No | ✅ Sí |
| `twilio/text` | ninguno | — | ✅ Sí (no necesita aprobación) |

**Conclusión #1**: si querés botones interactivos en WhatsApp, **solo quick-reply** (3 fijos). Lo demás no se puede.

## Reglas duras que Meta aplica (descubiertas a las duras)

### En el body del template

1. **NO puede ser solo la variable**: body = `{{1}}` → rechazado por "only have parameters". Hay que tener texto fijo además.
2. **NO más de 2 newlines consecutivos**: `\n\n` está OK, `\n\n\n` rechazado.
3. **NO más de 10 emojis totales** en el body renderizado (sumando texto fijo + variables).
4. **Variable NO al inicio NI al final**: `{{1}} texto` rechazado, `texto {{1}}` rechazado, `texto {{1}} texto` ✅.
5. **Body muy corto en relación a variables** → "too many variables for its length". Si tu body es `{{1}} {{2}}`, agregale texto fijo.

### En los títulos de botones

1. **NO emojis** en botones de templates **recién creados** (Meta cambió esta regla en algún punto). Templates viejos con emojis siguen funcionando, los nuevos los rechaza.
2. **NO variables** `{{N}}` en títulos. Twilio devuelve "Reply Title text cannot contain the following characters: [_*~{}\n]".
3. **NO formatting characters** (`_`, `*`, `~`, `…`, `\n`).
4. **Max 24 caracteres** (Twilio acepta, Meta a veces wrappea antes).
5. **NO duplicar IDs** entre botones del mismo template.

### Al enviar (ContentVariables)

1. **NO `\n` en variables** → error 21656 "Content Variables parameter is invalid".
2. **Workaround**: usar `U+2028` (LINE SEPARATOR) o `U+2029` (PARAGRAPH SEPARATOR) en lugar de `\n`. **Twilio los acepta**, WhatsApp los renderiza según cliente (a veces como salto, a veces como espacio).
3. **El JSON debe ser object, no array**: PHP `array_merge(['1'=>...], [])` renumera keys y produce `["a"]` (array) en lugar de `{"1":"a"}` (object). Usar `+` operator o `JSON_FORCE_OBJECT`.
4. **`JSON_UNESCAPED_UNICODE`** evita que acentos se rompan en transit.

## Aprobación de templates

### Flujo
1. Crear template via Twilio Content API (`POST /v1/Content`).
2. Submit a aprobación: `POST /v1/Content/{Sid}/ApprovalRequests/whatsapp` con `category` (UTILITY, MARKETING, AUTHENTICATION).
3. Meta evalúa (typical 5-60 min para UTILITY).
4. Status posibles: `unsubmitted` → `received` → `pending` → `approved` o `rejected`.

### Lo que importa saber
- **`rejected` ≠ no funciona**: en algunos casos los templates rechazados igual se entregan si las reglas violadas son del body (no de delivery). Templates con variables en botones SÍ se rompen siempre.
- **Meta cambia política durante el día**. Templates aprobados antes del cambio siguen funcionando. Templates nuevos con mismas características son rechazados.
- **Templates son INMUTABLES**. No se editan. Si querés cambiar algo, hay que crear uno nuevo con friendly_name distinto.
- **El friendly_name puede repetirse** (Twilio no exige unicidad), pero por orden conviene versionar (`v1`, `v2`).

## Categorías

| Categoría | Aprobación típica | Caso de uso |
|---|---|---|
| `UTILITY` | Rápida (minutos a horas) | Confirmaciones, recordatorios, notificaciones de pedido |
| `AUTHENTICATION` | Rápida | Códigos OTP |
| `MARKETING` | Lenta (24-72h) | Promociones, ofertas |

⚠️ Meta puede **cambiar la categoría** que vos pediste si cree que no corresponde. Si pediste UTILITY y Meta lo pasa a MARKETING, los costos por envío son más caros.

## Mejores prácticas para el producto

1. **Pre-crear templates al onboarding del cliente** (no al vuelo). Esperar aprobación antes de habilitar funciones que dependen de botones.
2. **Tener fallback a texto plano** siempre. Si el template falla, mandar el cuerpo como mensaje normal.
3. **Versionar templates**: cuando Meta cambia política, podés generar `v2`, `v3`, etc. sin perder los viejos que aún funcionan.
4. **Validar approval status** antes de usar un template recién creado (consultar `GET /v1/Content/{Sid}/ApprovalRequests`).
5. **Sanitizar el body que pasás como variable**: reemplazar `\n` por `U+2028`, em-dash por guion ASCII, etc.

## Templates típicos que vas a necesitar

| Nombre | Función | Variables | Botones |
|---|---|---|---|
| `menu_principal` | Saludo + 3 opciones rápidas | `{{1}}` saludo personalizado | "Consultar X", "Hacer pedido", "Mi saldo" |
| `seleccion_X` | Mostrar 2-3 opciones con detalle | `{{1}}` contexto + `{{2-4}}` items | "Opción 1/2/3" |
| `tipo_entrega` | Elegir cómo recibir | `{{1}}` resumen | "Retiro", "Reparto", "Urgente" |
| `confirmacion` | Confirmar antes de cerrar | `{{1}}` resumen del pedido | "Confirmar", "Cancelar" |

Body de cada uno: header fijo + `{{N}}` + footer fijo (para cumplir regla "variable no al inicio/final").

## Templates ejemplares que funcionaron

```json
// menu_principal
{
  "body": "Asistente Tu Negocio. {{1}} Elegí una opción.",
  "actions": [
    {"title": "Consultar precio", "id": "precio"},
    {"title": "Nuevo pedido",     "id": "pedido"},
    {"title": "Mi saldo",         "id": "saldo"}
  ]
}

// seleccion_3 (multi-línea con variables por producto)
{
  "body": "Encontré opciones para {{1}}:\n\n1) {{2}}\n2) {{3}}\n3) {{4}}\n\nTocá la que querés.",
  "actions": [
    {"title": "1️⃣ Opción 1", "id": "op1"},
    {"title": "2️⃣ Opción 2", "id": "op2"},
    {"title": "3️⃣ Opción 3", "id": "op3"}
  ]
}
```

Nota: el segundo tiene emojis `1️⃣` en botones que SÍ funcionan **si el template fue creado antes del cambio de política de junio 2026**. Si lo creás hoy, Meta lo rechaza. Probá y tené fallback.
