# Mensajes

Con la API, un bot puede escribir a un contacto desde tu propio sistema: recordarle una cita, enviarle un recibo, responder desde un CRM. Para ello usa el método **sendMessage**: envía un texto, una imagen o un archivo de inmediato e indica si el mensaje salió.

El método **sendMessageToQueue** está obsoleto y se desactivará: usa sendMessage en las integraciones nuevas.

El mensaje se guarda en la conversación del contacto con el nombre «API»; puedes verlo en [Conversaciones y mensajes](https://support.cleverapp.pro/es/chatbots/messages/dialogs). No inicia el flujo del bot.

## sendMessage

Envía a un contacto un texto, una imagen o un archivo.

```endpoint
POST https://app.cleverapp.pro/api/v1/sendMessage
```

El contacto se indica de una de dos formas: por ID de contacto, `contact_id`, o por bot e ID en el canal, `bot_id`, `messenger` y `contact_external_id` juntos.

| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| `contact_id` | número | sí, sin `messenger` | ID del contacto |
| `bot_id` | número | sí, sin `contact_id` | ID del bot |
| `messenger` | cadena | sí, sin `contact_id` | Canal del contacto: `telegram`, `max`, `viber`, `vk` o `web` (chat del sitio web) |
| `contact_external_id` | cadena | sí, sin `contact_id` | ID del contacto en el canal, hasta 255 caracteres; ver más abajo |
| `text` | cadena | sí, sin `image` ni `file` | Texto del mensaje. Con una imagen o un archivo, pasa a ser el pie |
| `image` | cadena | sí, sin `text` ni `file` | Enlace a una imagen |
| `file` | cadena | sí, sin `text` ni `image` | Enlace a un archivo |
| `filename` | cadena | no | Nombre del archivo que ve el destinatario. Las letras no latinas se transliteran; cualquier carácter que no sea letra, dígito, `.`, `_` o `-` se reemplaza por `_` |

Qué pasar en `contact_external_id`:

| `messenger` | Valor |
|---|---|
| `telegram` | ID del usuario en Telegram (el campo `telegram_id` del contacto) o su teléfono |
| `max` | ID del usuario en MAX (el campo `max_user_id`) o el teléfono |
| `viber` | ID del usuario en Viber (el campo `viber_id`) o el teléfono |
| `vk` | ID del usuario en VK, `700123456` (también funciona la forma antigua `vk700123456`), o el teléfono |
| `web` | ID del visitante del chat del sitio web |

El teléfono se compara carácter por carácter con el número del contacto (el campo `phone` en las respuestas de los métodos de contactos). La opción más fiable es `contact_id`, que devuelven los métodos de [contactos](https://support.cleverapp.pro/es/api/contacts).

Si se pasan tanto `image` como `file`, se envía la imagen.

```bash title="Solicitud: texto"
curl -X POST "https://app.cleverapp.pro/api/v1/sendMessage" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"contact_id": 4815162, "text": "Emily, tu pedido n.º 1042 ya fue enviado."}'
```

```bash title="Solicitud: archivo por ID de Telegram"
curl -X POST "https://app.cleverapp.pro/api/v1/sendMessage" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "bot_id": 12345,
    "messenger": "telegram",
    "contact_external_id": "123456789",
    "file": "https://example.com/invoices/1042.pdf",
    "filename": "Factura 1042.pdf",
    "text": "Tu factura"
  }'
```

```json title="Respuesta 200"
{
  "success": true
}
```

```json title="Respuesta 404"
{
  "message": "Contact not found"
}
```

**Límite de envío.** No más de 10 mensajes cada 10 segundos a un mismo canal. El contador se lleva por cuenta y por separado para cada canal: los 10 segundos empiezan con el primer mensaje y luego el contador se reinicia. Las solicitudes rechazadas no cuentan ni alargan la ventana. Una respuesta `429` lleva el encabezado `Retry-After` con los segundos que hay que esperar antes de reintentar. El límite general de frecuencia de la API se aplica aparte: consulta [Límites](https://support.cleverapp.pro/es/api#límites).

Errores del método (los generales están en [Errores](https://support.cleverapp.pro/es/api#errores)):

| Código | Cuándo | Respuesta |
|---|---|---|
| `404` | El contacto o el bot no está entre los tuyos: no existe ese ID, pertenece a otra cuenta o se eliminó; no hay ningún contacto con ese `messenger` y `contact_external_id` en el bot | `{"message": "Contact not found"}` o `{"message": "Bot not found"}` |
| `422` | No hay `text`, `image` ni `file`; el enlace de `image` o `file` no es una URL; `contact_id` o `bot_id` no es un entero positivo | `{"message": "…", "errors": {…}}` |
| `429` | Se superó el límite de envío para este canal | `{"error": "Message sending limit reached for telegram"}` |
| `501` | El contacto viene de un canal al que ya no se admite el envío | `{"error": "Sending messages to … is not supported"}` |

Los textos de error llegan en el idioma del encabezado `Accept-Language`.

## sendMessageToQueue

> [!WARNING]
> Este método está obsoleto y se desactivará el 1 de diciembre de 2026: usa [sendMessage](https://support.cleverapp.pro/es/api/messages#sendmessage) en su lugar. Hasta entonces, cada respuesta del método lleva los encabezados `Deprecation: true` y `Sunset: Tue, 01 Dec 2026 00:00:00 GMT`. A partir del 1 de diciembre de 2026 (00:00 UTC), el método responde con el estado `410`: `{"error": "This API method was removed on 2026-12-01.", "code": "method_removed"}`.

Pone en una cola un mensaje de texto para un contacto. La cola se procesa una vez por minuto.

```endpoint
POST https://app.cleverapp.pro/api/v1/sendMessageToQueue
```

El contacto se busca entre los contactos de todos tus bots o, con `bot_id`, solo entre los de ese bot. Pasa al menos uno de `contact_id`, `bitrix_contact_id` o `phone`; si pasas varios, el contacto debe coincidir con todos. Si varios contactos coinciden con `phone` o `bitrix_contact_id` y no se pasa `bot_id`, el mensaje se pone en cola para uno de ellos: primero, un contacto de un canal al que el método puede enviar y que no ha bloqueado el bot; luego, uno cuyo campo `phone` (WhatsApp) coincida exactamente; luego, el de la conversación más reciente. Los encabezados de respuesta `X-Contact-Id` y `X-Contact-Ambiguous: true` muestran a quién fue el mensaje. Con `bot_id` no se elige: si también coinciden varios contactos de ese bot, el método responde con `422` y no pone el mensaje en cola; pasa `contact_id`.

| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| `contact_id` | número | uno de los tres | ID del contacto |
| `bitrix_contact_id` | número | uno de los tres | ID del contacto de Bitrix24 vinculado al contacto del bot |
| `phone` | cadena | uno de los tres | Teléfono del contacto, hasta 20 caracteres. Se quitan espacios, paréntesis, guiones y `+`; un `8` inicial se reemplaza por `7` |
| `bot_id` | número | no | ID del bot desde el que enviar. Pásalo cuando el número o el ID de Bitrix24 pertenece a contactos de varios de tus bots |
| `text` | cadena | sí | Texto del mensaje, hasta 1024 caracteres |
| `message_id` | cadena | no | Tu propio ID del mensaje, hasta 255 caracteres. Protege contra duplicados: una solicitud repetida con el mismo `message_id` al mismo contacto no vuelve a poner el mensaje en cola mientras el anterior espera o ya se envió; la respuesta es el mismo `201`. Tras un error de envío, una repetición vuelve a poner el mensaje en cola |

```bash title="Solicitud"
curl -X POST "https://app.cleverapp.pro/api/v1/sendMessageToQueue" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"contact_id": 4815162, "text": "Recordatorio: tu cita es mañana a las 11:00."}'
```

```json title="Respuesta 422"
{
  "error": "Contact not found"
}
```

```json title="Respuesta 422: se necesita contact_id"
{
  "message": "Several contacts of the bot match this data — specify contact_id.",
  "errors": {
    "contact_id": ["Several contacts of the bot match this data — specify contact_id."]
  }
}
```

Una respuesta correcta tiene el estado `201`, el cuerpo vacío y el ID del contacto elegido en el encabezado `X-Contact-Id`. El `phone` limpio debe coincidir carácter por carácter con el número del contacto. Para un contacto de un canal al que ya no se admite el envío, el método responde con `422`: `{"error": "Messenger is not supported"}`. Los contactos que se dieron de baja del bot o lo bloquearon no reciben mensajes de la cola: esos mensajes se quitan de la cola en su siguiente ejecución.
