Saltar a contenido

Consultar mensajes y cuentas

Además de enviar, la API te deja leer: el estado de un mensaje puntual, listados con filtros para reconciliar en lote, y tus cuentas de WhatsApp. Todo con la misma autenticación x-api-key y siempre acotado a tu cuenta.

Tip

Para enterarte de los cambios de estado en tiempo real no hagas polling: usá webhooks. Estos endpoints brillan para reconciliar (ej.: "todos mis mensajes sent de las últimas 48 h") o como plan B.

GET /messages/{id}

Devuelve un mensaje tuyo. {id} puede ser el messageId de Arplyx o tu propio externalId — usá el que tengas a mano.

curl https://api.arplyx.com/messages/turno-4812-recordatorio \
  -H "x-api-key: ak_live_xxxxxxxx..."

Respuesta 200:

{
  "messageId": "b7a19c4d-…",
  "externalId": "turno-4812-recordatorio",
  "recipient": "+15550100124",
  "channel": "whatsapp_meta",
  "status": "read",
  "attemptCount": 1,
  "lastErrorCode": null,
  "broadcastId": null,
  "whatsappAccountId": "9d2f81b3-…",
  "createdAt": "2026-07-04T12:00:00.000Z",
  "sentAt": "2026-07-04T12:00:02.000Z",
  "deliveredAt": "2026-07-04T12:00:04.000Z",
  "readAt": "2026-07-04T12:01:10.000Z",
  "failedAt": null,
  "providerMessageId": "wamid.HBgLMTU1NTAxMDAxMjQVAgARGBI…",
  "expiresAt": "2026-07-05T12:00:00.000Z",
  "sandbox": false,
  "processing": {
    "queueState": "done",
    "attemptCount": 1,
    "maxAttempts": 5,
    "nextAttemptAt": null,
    "lastAttemptAt": "2026-07-04T12:00:02.000Z"
  },
  "error": null
}
Campo Descripción
status Ver ciclo de vida. Un 201 al enviar no prueba entrega: este campo sí.
sentAt / deliveredAt / readAt / failedAt Timestamp de cada transición; null si (aún) no ocurrió.
providerMessageId El id del proveedor (el wamid de Meta) cuando el envío fue aceptado; null antes de eso. Sirve para correlacionar con los recibos de Meta.
attemptCount Intentos de envío realizados.
lastErrorCode Código del último error de envío (null si no hubo). Se mantiene por compatibilidad; el detalle está en error.
error null si no hubo error. Si lo hubo: code (código de Arplyx, ver catálogo de errores de envío), message y provider con el detalle saneado de Meta cuando existe: code, subcode, message, fbtraceId, source (send_attempt o status_webhook). Nunca incluye tokens ni payloads completos.
processing Estado operativo del worker: queueState, attemptCount, maxAttempts, nextAttemptAt (cuándo se reintenta, si corresponde) y lastAttemptAt.
expiresAt Cuándo se purga el registro (ver vida útil).
sandbox true si se envió con una clave de sandbox (no cuenta para la cuota).
broadcastId Presente si el mensaje nació de un broadcast.

Errores: 404 message_not_found si el id no existe, no es tuyo o el mensaje ya fue purgado por la retención de tu plan (3–30 días según plan). Diseñá tu reconciliación asumiendo que los mensajes viejos desaparecen.

GET /messages (listado)

Lista tus mensajes, los más recientes primero, con filtros y paginación por cursor.

curl "https://api.arplyx.com/messages?status=sent&since=2026-07-02T00:00:00Z&limit=100" \
  -H "x-api-key: ak_live_xxxxxxxx..."

Parámetros de query (todos opcionales):

Parámetro Descripción
status pending, queued, sent, delivered, read o failed.
externalId Un externalId exacto.
providerMessageId Un wamid exacto: útil para encontrar el mensaje a partir de un recibo de Meta.
channel whatsapp_meta.
whatsappAccountId Solo mensajes de esa cuenta.
since / until Rango sobre createdAt (ISO 8601).
limit 1–100, default 50.
cursor El nextCursor de la página anterior.

Respuesta 200:

{
  "messages": [ { "…mismo shape que GET /messages/{id}…" } ],
  "nextCursor": "MTc1MTYzMDQwMDAwMHxiN2ExOWM0ZA"
}
  • nextCursor es null cuando no hay más páginas. Es un cursor opaco: pasalo tal cual, no lo construyas.
  • Un cursor mal formado responde 400 invalid_cursor.

Ejemplo de reconciliación — "¿qué pasó con todo lo que quedó sent en las últimas 48 h?":

curl "https://api.arplyx.com/messages?status=sent&since=$(date -u -d '48 hours ago' +%FT%TZ)" \
  -H "x-api-key: ak_live_xxxxxxxx..."

GET /whatsapp-accounts

Lista tus cuentas de WhatsApp vinculadas, con el whatsappAccountId que necesitás para enviar.

curl https://api.arplyx.com/whatsapp-accounts \
  -H "x-api-key: ak_live_xxxxxxxx..."

Respuesta 200:

{
  "accounts": [
    {
      "id": "9d2f81b3-…",
      "type": "META_OFFICIAL",
      "status": "CONNECTED",
      "phoneNumber": "+15550100124",
      "displayName": "Estudio Pilates Centro",
      "connectedAt": "2026-06-11T14:30:00.000Z",
      "channel": "whatsapp_meta",
      "lastErrorCode": null,
      "meta": {
        "phoneNumberId": "1234567890",
        "wabaId": "9876543210",
        "wabaVerification": "verified",
        "verifiedName": "Estudio Pilates Centro"
      },
      "sendPolicy": { "mode": "PRODUCTION", "testRecipientsCount": null },
      "webhook": { "integrationId": null, "callbackUrl": "https://api.arplyx.com/webhooks/whatsapp" },
      "capabilities": {
        "text": { "supported": true, "enabled": true },
        "media": { "supported": true, "enabled": true },
        "template": { "supported": true, "enabled": true },
        "namedTemplateParameters": { "supported": true, "enabled": true, "scope": "body" },
        "templateManagement": { "supported": true, "enabled": false, "verifiedAt": null },
        "statusWebhooks": { "supported": true, "enabled": true }
      }
    }
  ]
}
Campo Valores
type META_OFFICIAL o WHATSAPP_DIRECT
status PENDING, AUTHENTICATING, CONNECTED, DISCONNECTED, BANNED, ERROR
channel El valor a usar al enviar: whatsapp_meta o whatsapp_direct.
lastErrorCode Último error de la cuenta (por ejemplo AUTH_REJECTED), null si no hay.
meta Solo Meta Official: phoneNumberId, wabaId, wabaVerification (verified, unverifiable o unreachable, según lo que pudo comprobar el token al vincular) y verifiedName. null en Direct.
sendPolicy Solo Meta Official: mode DISABLED (nada sale), TEST (solo a los destinatarios de prueba; testRecipientsCount dice cuántos hay, nunca cuáles), PRODUCTION (a cualquier destinatario) o GLOBAL (cuenta anterior a las políticas). En TEST, un envío a otro destinatario termina failed con SANDBOX_BLOCKED.
webhook Solo Meta Official: integrationId de la app propia (o null si usa la app compartida) y la callbackUrl que debe estar configurada en Meta.
capabilities Por capacidad, supported (lo que Arplyx sabe hacer con ese tipo de cuenta) y enabled (lo habilitado para esta cuenta y plan). namedTemplateParameters.scope es siempre body. templateManagement.enabled indica si el catálogo de plantillas está disponible.

GET /whatsapp-accounts/{accountId}/templates

Lista el catálogo de plantillas de una cuenta Meta Official, leído en vivo desde su WABA. Requiere plan Starter o superior, una API key con templateAccess read o manage, y que el operador de Arplyx haya cargado la credencial de gestión de la cuenta.

curl "https://api.arplyx.com/whatsapp-accounts/9d2f81b3-…/templates?status=APPROVED&limit=50" \
  -H "x-api-key: ak_live_xxxxxxxx..."
Parámetro Descripción
status APPROVED, PENDING, REJECTED, PAUSED, DISABLED, IN_APPEAL.
name Filtro por nombre (contiene).
limit / cursor Paginación; nextCursor es null cuando Meta no tiene más.

Cada plantilla trae id (en Meta), name, language, category, status, rejectedReason, parameterFormat (NAMED o POSITIONAL), parameterCount, components tal como los devuelve Meta y qualityScore cuando existe.

POST /whatsapp-accounts/{accountId}/templates

Crea una plantilla solo con cuerpo de texto (BODY) en la WABA de la cuenta. Requiere templateAccess manage. Meta la deja en PENDING hasta revisarla; la aprobación no la decide Arplyx.

{
  "name": "turno_recordatorio",
  "language": "es_AR",
  "category": "UTILITY",
  "parameterFormat": "NAMED",
  "body": "Hola {{nombre}}, te recordamos tu turno el {{fecha}}.",
  "examples": [{ "name": "nombre", "text": "Juan" }, { "name": "fecha", "text": "13/10" }]
}

Reglas: name en minúsculas, números y guion bajo; variables nombradas {{nombre}} o posicionales {{1}} sin mezclar; un ejemplo por variable. Header, footer, botones y medios no se crean desde Arplyx. Errores: 409 template_already_exists, 422 template_rejected_by_meta (Meta rechazó la definición; el cuerpo trae el detalle saneado), 403 template_access_insufficient (la clave no tiene templateAccess suficiente), 422 template_management_unavailable (sin credencial de gestión), 503 meta_unavailable / meta_unreachable, 429 meta_rate_limited.

Mayúsculas vs. minúsculas

Ojo al parsear: type usa el formato del modelo interno (META_OFFICIAL, mayúsculas), mientras que el campo channel al enviar usa minúsculas (whatsapp_meta). La correspondencia es META_OFFICIAL → whatsapp_meta.