Enviar mensajes
POST /messages — encola un mensaje de WhatsApp para un destinatario. La respuesta es inmediata (el envío real lo hace el worker de Arplyx); el estado se sigue desde el portal o vía los estados del mensaje.
Request
{
"externalId": "pedido-10045",
"channel": "whatsapp_meta",
"to": { "type": "phone", "phoneE164": "+15550100123" },
"content": { "type": "text", "text": "Hola! Tu pedido fue confirmado." },
"whatsappAccountId": "0b8e2c1a-...",
"metadata": { "orderId": 10045 },
"ttlSeconds": 86400
}
Campos
| Campo | Tipo | Requerido | Default | Detalle |
|---|---|---|---|---|
externalId |
string | Sí | — | Tu identificador único (1–200 caracteres). Base de la idempotencia. |
channel |
string | No | whatsapp_meta |
whatsapp_meta. |
to.type |
string | Sí | — | Siempre phone. |
to.phoneE164 |
string | Sí | — | Número en formato E.164: + seguido de 7 a 15 dígitos (ej.: +15550100123). |
content.type |
string | Sí | — | text, template, image o document (ver abajo). |
content.text |
string | Sí para text |
— | Cuerpo del mensaje, 1–10.000 caracteres. |
whatsappAccountId |
string (UUID) | Depende | — | Solo si tenés más de una cuenta Meta conectada. Debe ser una cuenta tuya (si no: 422). |
metadata |
object | No | — | Datos arbitrarios tuyos; se guardan junto al mensaje y se ven en el portal. |
ttlSeconds |
int | No | 604800 (7 días) |
Vigencia del mensaje en cola. Máximo 30 días; además se recorta por la retención de tu plan (Free: 3 días). |
Mensajes de plantilla (template)
Las plantillas (HSM de Meta, solo canal whatsapp_meta) son lo que te permite iniciar conversaciones — enviar fuera de la ventana de 24 h, sin que el usuario haya escrito primero.
{
"externalId": "pedido-10045",
"channel": "whatsapp_meta",
"content": {
"type": "template",
"template": {
"name": "pedido_confirmado",
"language": "es_AR",
"components": { "body": ["Juan", "10045"] }
}
},
"to": { "type": "phone", "phoneE164": "+15550100123" }
}
nameylanguage: nombre y código de idioma de la plantilla, tal como figuran en tu WhatsApp Manager.components.body(ycomponents.header): los valores de las variables ({{1}},{{2}}…) en orden. En el ejemplo,{{1}}= "Juan" y{{2}}= "10045".
Las plantillas se crean en Meta
La plantilla tiene que estar creada y aprobada en tu WhatsApp Manager antes de usarla; Arplyx la envía por nombre. La aprobación y el costo por conversación corren por tu cuenta de Meta (sos dueño de la WABA).
Disponible en planes pagos
El envío de plantillas (mensajería proactiva) está disponible desde el plan Starter. En el plan Free, Meta solo responde dentro de la ventana de 24 h: un intento de enviar una plantilla devuelve 403 templates_not_available.
Imágenes y documentos
Además de texto, podés enviar una imagen (JPEG o PNG) o un documento (PDF, Office, texto plano) por cualquiera de los dos canales. El archivo se referencia de una de dos formas, excluyentes: por URL pública HTTPS (el proveedor lo descarga en el momento del envío) o por mediaId de un archivo que subiste antes con POST /media. Disponible en todos los planes; cuenta como un mensaje más contra tu cuota.
{
"externalId": "pedido-10045-foto",
"channel": "whatsapp_meta",
"to": { "type": "phone", "phoneE164": "+15550100123" },
"content": {
"type": "image",
"image": { "url": "https://cdn.tuempresa.com/pedidos/10045/foto.jpg" },
"caption": "Tu pedido salió a reparto."
},
"whatsappAccountId": "TU_ACCOUNT_ID"
}
{
"externalId": "factura-A-0001-00012345",
"channel": "whatsapp_meta",
"to": { "type": "phone", "phoneE164": "+15550100123" },
"content": {
"type": "document",
"document": {
"url": "https://cdn.tuempresa.com/facturas/A-0001-00012345.pdf",
"filename": "Factura A-0001-00012345.pdf"
},
"caption": "Te adjunto la factura de este mes."
},
"whatsappAccountId": "TU_ACCOUNT_ID"
}
| Campo | Tipo | Requerido | Detalle |
|---|---|---|---|
content.image.url / content.document.url |
string | Uno de los dos | URL pública HTTPS (sin login, sin host privado), hasta 2048 caracteres. Tiene que responder directamente con el archivo; se siguen hasta 3 redirects. |
content.image.mediaId / content.document.mediaId |
string (UUID) | Uno de los dos | Id devuelto por POST /media. Si no existe, no es tuyo o no es una imagen cuando el tipo es image: 422 invalid_media. |
content.caption |
string | No | Texto que acompaña al archivo, hasta 1024 caracteres. |
content.document.filename |
string | No | Nombre con el que el destinatario ve el archivo (hasta 255 caracteres). Default: el nombre subido o el último segmento de la URL. |
Límites y formatos
- Imágenes: JPEG o PNG, hasta 5 MB. Se detecta el formato por el contenido, no por la extensión.
- Documentos: PDF, Word, Excel, PowerPoint o texto plano, hasta 20 MB. Meta acepta solo esa lista.
- Si la URL no se puede descargar (404, tamaño excedido, formato inválido), el mensaje pasa a
failedconlastErrorCode: MEDIA_UNAVAILABLEy no se reintenta. Corregí la URL y volvé a enviar con unexternalIdnuevo.
Ventana de 24 h en Meta Official
Una imagen o un documento es un mensaje libre, igual que el texto: por whatsapp_meta solo llega dentro de la ventana de 24 h. Fuera de ella seguís necesitando una plantilla.
Respuesta
201 Created (mensaje nuevo) o 200 OK (repetición idempotente — mismo externalId y payload):
{
"messageId": "7f9b3c30-...",
"externalId": "pedido-10045",
"status": "pending",
"queued": true
}
El messageId es el ID interno de Arplyx; te sirve para ubicar el mensaje en el portal. Los errores posibles (400, 401, 409, 422, 429) están catalogados en Errores y estados.
Ejemplos
curl -X POST https://api.arplyx.com/messages \
-H "x-api-key: $ARPLYX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"externalId": "pedido-10045",
"channel": "whatsapp_meta",
"to": { "type": "phone", "phoneE164": "+15550100123" },
"content": { "type": "text", "text": "Hola! Tu pedido fue confirmado." },
"whatsappAccountId": "TU_ACCOUNT_ID"
}'
const response = await fetch('https://api.arplyx.com/messages', {
method: 'POST',
headers: {
'x-api-key': process.env.ARPLYX_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
externalId: 'pedido-10045',
channel: 'whatsapp_meta',
to: { type: 'phone', phoneE164: '+15550100123' },
content: { type: 'text', text: 'Hola! Tu pedido fue confirmado.' },
whatsappAccountId: 'TU_ACCOUNT_ID',
}),
})
const data = await response.json()
if (!response.ok) throw new Error(`${response.status}: ${data.error}`)
console.log(data.messageId, data.status)
import os
import requests
response = requests.post(
'https://api.arplyx.com/messages',
headers={'x-api-key': os.environ['ARPLYX_API_KEY']},
json={
'externalId': 'pedido-10045',
'channel': 'whatsapp_meta',
'to': {'type': 'phone', 'phoneE164': '+15550100123'},
'content': {'type': 'text', 'text': 'Hola! Tu pedido fue confirmado.'},
'whatsappAccountId': 'TU_ACCOUNT_ID',
},
timeout=10,
)
response.raise_for_status()
print(response.json())
Para enviar por Meta Official, usá "channel": "whatsapp_meta" y omití whatsappAccountId si tenés una sola cuenta Meta conectada. Recordá la ventana de 24 horas del canal oficial para texto libre.
Reintentos automáticos
Si el proveedor falla con un error transitorio (red, 5xx, rate limit), Arplyx reintenta solo, con backoff exponencial, hasta 5 intentos por defecto. No reenvíes vos por tu cuenta: usá el mismo externalId si querés re-disparar de forma segura.