> ## Documentation Index
> Fetch the complete documentation index at: https://developer.iobot.chat/llms.txt
> Use this file to discover all available pages before exploring further.

# Enviar Plantilla

> Envía una plantilla de WhatsApp a un número usando su ID interno y los parámetros que requiere

Envía una plantilla de WhatsApp en nombre del negocio, identificándola por el **`id` interno** obtenido en el [listado de plantillas](/plantillas-mensajes/obtener-plantillas).

No requiere un `chat_id` ni un `contacto_id` preexistentes: si el número no tiene contacto o conversación registrada, ambos se crean automáticamente. Es el endpoint indicado para disparos externos, integraciones de CRM y flujos donde el negocio inicia el contacto sin intervención de un agente.

## Autenticación

Requiere el encabezado `x-api-key` con el App Key del negocio. Consulta [Autenticación](/authentication).

## Encabezados

<ParamField header="x-api-key" type="string" required>
  App Key del negocio. Consulta [Autenticación](/authentication).
</ParamField>

## Cuerpo de la solicitud

<ParamField body="empresa_id" type="number" required>
  ID del negocio que envía la plantilla. Debe ser numérico.
</ParamField>

<ParamField body="phone_number" type="string" required>
  Número de WhatsApp del destinatario. Se aceptan formatos con separadores (guiones, espacios, `+`): el sistema conserva únicamente los dígitos. `+52 155 1234 5678` y `5215512345678` son equivalentes.
</ParamField>

<ParamField body="plantilla_id" type="number" required>
  **ID interno de la plantilla**, tomado del campo `id` del [listado](/plantillas-mensajes/obtener-plantillas). Debe pertenecer a `empresa_id`; de lo contrario responde `404`.
</ParamField>

<ParamField body="parameters" type="string[]" default="[]">
  Valores que sustituyen los marcadores `{{1}}`, `{{2}}`, … del cuerpo de la plantilla, **en orden posicional**: el primer elemento reemplaza `{{1}}`, el segundo `{{2}}`, y así sucesivamente.

  Cada elemento debe ser un string. El sistema los envuelve automáticamente como `{ type: "text", text: "..." }` dentro de un componente `body` antes de enviarlos a Meta.

  ```json theme={null}
  ["Juan Pérez", "COT-9982"]
  ```

  Debe ser un arreglo; cualquier otro tipo se rechaza con `400`. Consulta [cómo saber cuántos parámetros requiere una plantilla](/plantillas-mensajes/obtener-plantillas).
</ParamField>

<ParamField body="name" type="string">
  Nombre del contacto, usado solo si se crea en esta llamada. Si se omite, se usa el número. Debe ser texto; otro tipo se rechaza con `400`.
</ParamField>

<ParamField body="media_url" type="string">
  URL pública `https://` que reemplaza, solo para este envío, la imagen/video/documento del encabezado. Solo aplica si la plantilla tiene encabezado multimedia (`type` ≠ `text`) y empieza con `https://`; si no, `400`.

  Si se omite, se usa el archivo de la plantilla. Para un archivo local, súbelo primero con [Subir Media](/plantillas-mensajes/subir-media).

  ```json Reemplazar la imagen theme={null}
  { "plantilla_id": 2325, "media_url": "https://.../nueva-imagen.jpg" }
  ```

  ```json Usar la imagen ya guardada theme={null}
  { "plantilla_id": 2325 }
  ```
</ParamField>

<Warning>
  El número de elementos en `parameters` debe coincidir **exactamente** con el número de marcadores del cuerpo de la plantilla — ni de más ni de menos. Si mandas parámetros de más (incluida una plantilla sin marcadores, con `parameters` no vacío) o de menos, Meta rechaza el mensaje y la respuesta será `400 Error al enviar la plantilla`. Este endpoint no valida la cantidad antes de llamar a Meta.
</Warning>

## Comportamiento

<Steps>
  <Step title="Validación">
    Se verifican los tipos de todos los campos, y que la empresa y la plantilla existan y estén relacionadas entre sí.
  </Step>

  <Step title="Resolución del contacto">
    Se normaliza `phone_number` a solo dígitos y se busca el contacto. Si no existe, se crea con `name` (o el número) como nombre.
  </Step>

  <Step title="Resolución del chat">
    Se busca una conversación del contacto en esa empresa. Si no existe, se crea con estado `bot`, bot disponible y proveedor `fb-apicloud`.
  </Step>

  <Step title="Envío y registro">
    Se envía la plantilla por WhatsApp Cloud API y se registra el mensaje en la conversación, con los marcadores ya sustituidos por los valores de `parameters`, atribuido al nombre del negocio.
  </Step>
</Steps>

## Respuesta

<ResponseField name="success" type="boolean">
  `true` cuando la plantilla fue enviada y registrada correctamente.
</ResponseField>

<Note>
  La respuesta exitosa no incluye el identificador del mensaje (`wamid`). Para dar seguimiento al estado de entrega, consulta la conversación del contacto.
</Note>

<Tip>
  **Antes de probar el curl**, no adivines `plantilla_id` ni cuántos `parameters` lleva: llama a [Listar Plantillas](/plantillas-mensajes/obtener-plantillas), busca en la respuesta el objeto cuyo `id` es tu `plantilla_id`, y cuenta el marcador `{{n}}` más alto en su `descripcion` (o en `template.components` tipo `BODY`, si está disponible). Ese número es la cantidad de elementos que debe traer `parameters`, en ese mismo orden.
</Tip>

<RequestExample>
  ```bash theme={null}
  curl -X POST https://beta.api-iobot-desarrollo.com/chats/enviar/plantilla/business \
    -H "Content-Type: application/json" \
    -H "x-api-key: TU_APP_KEY" \
    -d '{
      "empresa_id": 1,
      "phone_number": "5215512345678",
      "plantilla_id": 12,
      "name": "Juan Pérez",
      "parameters": ["Juan Pérez", "COT-9982"]
    }'
  ```

  ```bash Con media_url theme={null}
  curl -X POST https://beta.api-iobot-desarrollo.com/chats/enviar/plantilla/business \
    -H "Content-Type: application/json" \
    -H "x-api-key: TU_APP_KEY" \
    -d '{
      "empresa_id": 1,
      "phone_number": "5215512345678",
      "plantilla_id": 12,
      "name": "Juan Pérez",
      "parameters": ["Juan Pérez", "COT-9982"],
      "media_url": "https://ejemplo.com/otra-imagen.jpg"
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json 200 Éxito theme={null}
  {
    "success": true
  }
  ```

  ```json 400 Campo requerido theme={null}
  {
    "success": false,
    "error": "empresa_id es requerido y debe ser un número"
  }
  ```

  ```json 400 parameters inválido theme={null}
  {
    "success": false,
    "error": "parameters debe ser un arreglo"
  }
  ```

  ```json 400 Rechazo de Meta theme={null}
  {
    "success": false,
    "error": "Error al enviar la plantilla"
  }
  ```

  ```json 400 media_url no aplica theme={null}
  {
    "success": false,
    "error": "media_url no aplica: la plantilla no tiene encabezado multimedia"
  }
  ```

  ```json 400 media_url no accesible theme={null}
  {
    "success": false,
    "error": "media_url no es accesible: 404"
  }
  ```

  ```json 404 Negocio no encontrado theme={null}
  {
    "success": false,
    "error": "Empresa no encontrada"
  }
  ```

  ```json 404 Plantilla no encontrada theme={null}
  {
    "success": false,
    "error": "Plantilla no encontrada"
  }
  ```

  ```json 500 Error inesperado theme={null}
  {
    "success": false,
    "error": "Error: ..."
  }
  ```
</ResponseExample>

## Errores comunes

| Estado | Error                                                              | Causa                                                                                                                          |
| ------ | ------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------ |
| `400`  | `empresa_id es requerido y debe ser un número`                     | Falta `empresa_id` o no es numérico                                                                                            |
| `400`  | `phone_number es requerido`                                        | Falta el número o viene vacío                                                                                                  |
| `400`  | `plantilla_id es requerido y debe ser un número`                   | Falta `plantilla_id` o no es numérico                                                                                          |
| `400`  | `parameters debe ser un arreglo`                                   | `parameters` no es un arreglo                                                                                                  |
| `400`  | `name debe ser un texto`                                           | `name` se envió con un tipo distinto de string                                                                                 |
| `400`  | `Error al enviar la plantilla`                                     | Meta rechazó el envío: plantilla no aprobada, número inválido, o cantidad de parámetros incorrecta                             |
| `400`  | `media_url debe ser un texto`                                      | `media_url` se envió con un tipo distinto de string                                                                            |
| `400`  | `media_url debe ser una URL https`                                 | `media_url` no empieza con `https://`                                                                                          |
| `400`  | `media_url no aplica: la plantilla no tiene encabezado multimedia` | Se envió `media_url` para una plantilla de tipo `text`                                                                         |
| `400`  | `media_url no es accesible: ...`                                   | El endpoint hizo un `HEAD` a `media_url` antes de enviar y no respondió `200` (archivo movido, URL rota, servidor caído, etc.) |
| `404`  | `Plantilla no encontrada`                                          | El `plantilla_id` no existe o pertenece a otra empresa                                                                         |

## Imagen (u otro medio) del encabezado

Si la plantilla tiene un encabezado multimedia (`type` distinto de `text`), por defecto se envía el archivo subido al crear la plantilla (dashboard → Plantillas → Crear plantilla → encabezado tipo **Medios**). Para usar un archivo distinto sin crear una plantilla nueva, manda `media_url` con la URL pública del archivo que quieres usar en su lugar — aplica solo a ese envío, la plantilla guardada no se modifica.

Si el archivo que quieres usar está en tu equipo o servidor local (no tiene una URL pública todavía), súbelo primero con [Subir Media](/plantillas-mensajes/subir-media) y usa la `media_url` que te devuelve.
