Mensajes
Envía notificaciones de servicio (pedido enviado, cita confirmada, nómina disponible...) a tus clientes y empleados por el chat de la app de xYago, desde un perfil de empresa verificado. La entrega es solo por la red de xYago: si la persona aún no tiene la app, el mensaje la espera hasta 7 días.
Antes de enviar
- En el panel → API Developer → Remitentes, crea tu remitente (su id,
p. ej.
tiendaexpress, nombre visible, logo, sitio web y categoría) y envíalo a revisión. xYago lo verifica y lo aprueba. - Crea una plantilla por cada tipo de aviso, con sus textos en
es,eny/odey variables numeradas{{1}},{{2}}... Envíala a revisión: xYago la aprueba. Solo se admiten avisos de servicio (categoríautility), nunca publicidad. Sin enlaces en el texto: para enlazar, añade un botón (hasta 3 botones de respuesta rápida o de enlace; ver Plantillas y botones). - Activa el producto Mensajes y crea una API key con el scope
messages:write(ymessages:readpara consultar).
Con GET /senders y GET /templates compruebas por API el estado
de revisión de tus remitentes y plantillas.
Enviar un mensaje
curl -X POST 'https://api.xyago.com/v1/messages' \
-H "Authorization: Bearer $XYAGO_API_KEY" \
-H "Idempotency-Key: pedido-TE-48213-enviado" \
-H "Content-Type: application/json" \
-d '{"to": "+573005550123", "sender_id": "tiendaexpress", "template": "pedido_enviado",
"language": "es", "variables": ["Valentina", "TE-48213"], "reference": "CLI-000123"}'
Respuesta 202:
{
"id": "7a1c9e35-2b4d-4f6a-8c0e-1d3f5a7b9c21",
"status": "sent",
"to_masked": "+57 ••• ••• 0123",
"sender_id": "tiendaexpress",
"template": "pedido_enviado",
"language": "es",
"reference": "CLI-000123",
"failure_code": null,
"created_at": "2026-11-04T15:00:00Z",
"sent_at": "2026-11-04T15:00:01Z",
"delivered_at": null,
"read_at": null,
"expires_at": null
}
variables: valores de{{1}}..{{n}}en orden. Son texto plano (máx. 256 caracteres, sin enlaces ajenos a tu dominio); su número tiene que coincidir convariables_countde la plantilla (422 template_variables_mismatch).language: si la plantilla no tiene ese idioma se usa su idioma por defecto. Los botones salen en el mismo idioma que el texto.reference(opcional, máx. 64): tu id del cliente. Aparece en el panel y sirve para filtrarGET /messages?reference=....button_variables(solo si la plantilla tiene un botón de enlace con variable): valor de esa variable por índice del botón, p. ej.{"0": "TE-48213"}(422 invalid_button_variablessi falta o sobra). Ver Botones.
Estados
| Estado | Significado |
|---|---|
accepted | Recibido por la API (estado transitorio). |
pending_install | El teléfono aún no usa xYago: el mensaje espera hasta 7 días (expires_at). |
sent | Guardado en el chat del destinatario. |
delivered | Llegó a un dispositivo del destinatario. |
read | El destinatario abrió el chat. |
failed | No se entregará. failure_code: recipient_not_on_xyago (no instaló xYago en 7 días), undeliverable, sender_suspended, invalid_message. |
Consulta un envío con GET /messages/{id} o lista los tuyos con
GET /messages?status=&sender_id=&reference=; mejor aún, suscríbete a los
webhooks.
Destinatarios sin xYago (pending_install)
Si el teléfono todavía no usa xYago, la API no falla: responde 202 con
status: "pending_install". xYago guarda el mensaje cifrado y lo entrega en
cuanto esa persona instale la app y verifique su número (recibes
message.sent). Si no lo hace en 7 días el envío termina en failed
con recipient_not_on_xyago (recibes message.failed) y el texto se
borra. Para que lleguen antes, invita a tus usuarios.
Si el destinatario no puede recibir mensajes de tu remitente la API
responde 409 undeliverable. No reintentes ese envío.
Idempotency-Key (obligatoria)
Cada POST /messages lleva la cabecera Idempotency-Key (8-128
caracteres A-Z a-z 0-9 . _ : -), única por envío: el id del aviso en tu
sistema o un UUID. Si la respuesta no llega (timeout, 502,
503), repite la petición con la misma clave y el
mismo cuerpo:
| Repetición | Respuesta |
|---|---|
| Misma clave, mismo cuerpo | 200 con el envío original y la cabecera Idempotent-Replayed: true (o el mismo error si había fallado). Nunca se envía dos veces. |
| Misma clave, otro cuerpo | 409 idempotency_key_reused. |
Las claves son por entorno: la misma clave en sandbox y en live son envíos distintos.
Límites
Además del límite de peticiones por minuto de la API key, cada remitente tiene topes
para evitar spam: mensajes por minuto (el límite del producto en el panel), mensajes por
destinatario y día (10) y destinatarios nuevos por día (1.000). Al superarlos la API
responde 429 rate_limited con Retry-After. Si xYago detecta que
muchos envíos van a teléfonos sin xYago, pausa los envíos del remitente a destinatarios
nuevos (403 new_recipients_paused) hasta revisarlo contigo.
Si los límites no se pueden comprobar en ese momento, por seguridad no se
envía nada: 503 limits_unavailable. Reintenta con la misma
Idempotency-Key.
Webhooks
Suscríbete en el panel a message.sent, message.delivered,
message.read, message.failed, message.button_clicked
(clic en un botón), sender.status_changed
y template.status_changed (ver Webhooks). El
data es el mismo objeto que devuelve GET /messages/{id}:
{
"created_at": "2026-03-02T15:00:04Z",
"data": {
"id": "3e5a7c91-4b6d-4e8f-a0c2-5d7f9b1e3a64",
"status": "sent",
"to_masked": "+57 ••• ••• 0187",
"sender_id": "tiendaexpress",
"template": "pedido_enviado",
"language": "es",
"reference": "CLI-000087",
"failure_code": null,
"created_at": "2026-11-04T15:00:00Z",
"sent_at": "2026-11-05T08:10:00Z",
"delivered_at": null,
"read_at": null,
"expires_at": "2026-11-11T15:00:00Z"
},
"environment": "live",
"id": "evt_4f9c2b7a1d3e4c5b8a6f0e1d2c3b4a59",
"type": "message.sent"
}
Sandbox
Con una clave xy_test_ los mensajes son reales (llegan a la
app), pero solo a tus números de prueba: hasta 5, que tienen que usar
xYago. Añádelos en el panel → Sandbox; cada uno recibe en xYago un código de 6
dígitos de xYago Sandbox que escribes en el panel para confirmarlo. En sandbox
puedes usar cualquier remitente de tu cuenta y plantillas aprobadas o en
draft; mientras tu remitente no esté aprobado, los mensajes llegan desde
xYago Sandbox con el nombre visible de tu remitente como prefijo, p. ej.
[Sandbox · Tienda Express] Hola Valentina, …. Enviar a otro
número responde 422 sandbox_recipient_not_allowed.