# Enviar una plantilla con un archivo en el encabezado

`POST /v1/messages`

**Es el caso de uso más común de una plantilla de utilidad: mandar la factura.** Una plantilla de Meta puede llevar un **encabezado** con un documento, una imagen o un video, y ese archivo se elige **en cada envío** — la plantilla aprobada define el TIPO, vos ponés el archivo.

**Cómo se manda.** Igual que cualquier plantilla (POST /v1/messages con `type: "template"`), pero el array `components` lleva **primero** un componente `header` con el archivo:

```
{ "type": "header", "parameters": [ { "type": "document", "document": { "link": "https://…/A-1042.pdf", "filename": "Factura A-1042.pdf" } } ] }
```

**De dónde sale el archivo: de un enlace tuyo.** Meta acepta `link` (una URL **https** pública que descarga **ella**) o `id` (un identificador de media). **Connect no almacena archivos y no tiene endpoint de subida**, así que los únicos `id` que existen son los de archivos que RECIBISTE — para mandar una factura tuya, **hospedala y mandá el enlace**. Es el mismo criterio que en «Enviar media», y por la misma razón: no guardamos contenido.

⚠ **El tipo del parámetro lo manda la PLANTILLA, no el archivo.** Si Meta aprobó el encabezado como `DOCUMENT`, el parámetro va como `document` aunque el archivo sea un JPG. Mandar `image` sobre una plantilla `DOCUMENT` lo rechaza Meta.

⚠ **`filename` es sólo para documentos** (es el nombre que ve quien lo recibe). En imagen y video, Meta lo rechaza.

🔴 **Lo que NO se puede: CREAR una plantilla con encabezado de archivo desde Connect.** Sólo se crean encabezados de **texto**. Si mandás un `header.format` de imagen/documento/video a `POST /v1/templates`, te contestamos `400 TEMPLATE_PRECHECK_FAILED` con el código `TPL_HEADER_FORMAT_UNSUPPORTED` — **no la creamos a medias ni te decimos que sí**. El camino es: creála en el **Administrador comercial de Meta** (ahí sí acepta encabezados de archivo) y después `POST /v1/templates/sync` — Connect la lee bien, la lista, te avisa cuando cambia de estado, y la envía como dice arriba.

## Ejemplos

### cURL

```bash
curl -X POST https://api.waiaconnect.com/v1/messages \
  -H "Authorization: Bearer wc_live_YOUR_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"connectionId":"conn_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX","to":"5493511234567","type":"template","template":{"name":"envio_factura","language":"es","components":[{"type":"header","parameters":[{"type":"document","document":{"link":"https://your-server.example/invoices/A-1042.pdf","filename":"Factura A-1042.pdf"}}]},{"type":"body","parameters":[{"type":"text","text":"María"}]}]}}'
# The header component goes FIRST and its type is the one the APPROVED TEMPLATE
# declares (document | image | video) — NOT the file's mime type.
# image: {"type":"image","image":{"link":"https://…/photo.jpg"}}   (no filename)
# by media id instead of a link: {"document":{"id":"1234567890"}}
# ⚠ You cannot CREATE a media-header template from Connect (only TEXT headers).
#   Create it in Meta Business Manager, then POST /v1/templates/sync.
```

### Node.js

```javascript
// The header component goes FIRST; its type is the one the APPROVED TEMPLATE declares
// (document | image | video), not the file's mime. `filename` applies to documents only.
const res = await fetch("https://api.waiaconnect.com/v1/messages", {
  method: "POST",
  headers: {
    "Authorization": "Bearer wc_live_YOUR_API_KEY",
    "Idempotency-Key": crypto.randomUUID(),
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
  "connectionId": "conn_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "to": "5493511234567",
  "type": "template",
  "template": {
    "name": "envio_factura",
    "language": "es",
    "components": [
      {
        "type": "header",
        "parameters": [
          {
            "type": "document",
            "document": {
              "link": "https://your-server.example/invoices/A-1042.pdf",
              "filename": "Factura A-1042.pdf"
            }
          }
        ]
      },
      {
        "type": "body",
        "parameters": [
          {
            "type": "text",
            "text": "María"
          }
        ]
      }
    ]
  }
})
});
console.log(await res.json()); // { id: "msg_…", status: "queued" }
```

### PHP

```php
<?php
// The header component goes FIRST; its type is the one the APPROVED TEMPLATE declares.
$ch = curl_init("https://api.waiaconnect.com/v1/messages");
curl_setopt_array($ch, [
  CURLOPT_POST => true,
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => [
    "Authorization: Bearer wc_live_YOUR_API_KEY",
    "Idempotency-Key: " . bin2hex(random_bytes(16)),
    "Content-Type: application/json",
  ],
  CURLOPT_POSTFIELDS => json_encode(["connectionId" => "conn_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX","to" => "5493511234567","type" => "template","template" => ["name" => "envio_factura","language" => "es","components" => [["type" => "header","parameters" => [["type" => "document","document" => ["link" => "https://your-server.example/invoices/A-1042.pdf","filename" => "Factura A-1042.pdf"]]]],["type" => "body","parameters" => [["type" => "text","text" => "María"]]]]]]),
]);
echo curl_exec($ch);
```

### Python

```python
import requests, uuid
# The header component goes FIRST; its type is the one the APPROVED TEMPLATE declares
# (document | image | video), not the file's mime. "filename" applies to documents only.
res = requests.post("https://api.waiaconnect.com/v1/messages",
  headers={
    "Authorization": "Bearer wc_live_YOUR_API_KEY",
    "Idempotency-Key": str(uuid.uuid4()),
  },
  json={"connectionId":"conn_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX","to":"5493511234567","type":"template","template":{"name":"envio_factura","language":"es","components":[{"type":"header","parameters":[{"type":"document","document":{"link":"https://your-server.example/invoices/A-1042.pdf","filename":"Factura A-1042.pdf"}}]},{"type":"body","parameters":[{"type":"text","text":"María"}]}]}})
print(res.json())
```

## Notas

- **Cómo saber si una plantilla lleva archivo:** `GET /v1/templates` devuelve `header: { format: "DOCUMENT" }` (o `IMAGE`/`VIDEO`). En el panel están marcadas con 📎.
- **Si te olvidás del archivo te lo decimos ANTES de Meta:** `422 TEMPLATE_HEADER_MEDIA_REQUIRED`, con `details.example` = el componente exacto que falta. Meta, en cambio, contesta un `132000` opaco.
- Y si llega igual (una plantilla que todavía no sincronizamos), el mensaje falla **en el primer intento** con `lastErrorCode` = `TEMPLATE_PARAM_MISMATCH` — no se reintenta cinco veces un payload que no puede funcionar.
- **Qué necesita el enlace:** ser **https**, apuntar **directo al archivo** (sin login ni página intermedia) y traer el `Content-Type` correcto. ⚠ Un enlace de "compartir" de Google Drive o Dropbox devuelve una **página HTML**: Meta la descarga y rechaza el envío. Límites de Meta: documento 100 MB, imagen 5 MB, video 16 MB.
- Meta **cachea tu enlace 10 minutos**: si cambiás el archivo detrás de la misma URL, agregale un `?v=…` distinto.
