xYago APIv1

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

  1. 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.
  2. Crea una plantilla por cada tipo de aviso, con sus textos en es, en y/o de y variables numeradas {{1}}, {{2}}... Envíala a revisión: xYago la aprueba. Solo se admiten avisos de servicio (categoría utility), 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).
  3. Activa el producto Mensajes y crea una API key con el scope messages:write (y messages:read para 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
}

Estados

EstadoSignificado
acceptedRecibido por la API (estado transitorio).
pending_installEl teléfono aún no usa xYago: el mensaje espera hasta 7 días (expires_at).
sentGuardado en el chat del destinatario.
deliveredLlegó a un dispositivo del destinatario.
readEl destinatario abrió el chat.
failedNo 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ónRespuesta
Misma clave, mismo cuerpo200 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 cuerpo409 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.