Leer conversaciones e historial de mensajes

Traé a tu sistema las conversaciones que cambiaron y el historial de mensajes de cada contacto, paginando sin perder nada.

Vas a sincronizar las conversaciones de WhatsApp de tu cuenta con tu sistema: qué conversaciones tuvieron movimiento y qué se dijo en cada una. Usa Listar conversaciones con updated_since, Listar contactos para encontrar a un contacto por su teléfono y Listar los mensajes de un contacto para traer su historial.

Al terminar esta guía, tu sistema trae solo lo que cambió desde la última sincronización, recorre todas las páginas con el cursor y guarda el historial de mensajes de cada contacto sin duplicados.

Antes de empezar

  • Una clave con conversations:read. Todo lo de esta guía es lectura. Si todavía no tenés una, seguí la guía rápida.
  • La clave en la variable FC_API_KEY, entre comillas si la guardás en un .env (lleva un |).
  • Opcional: el receptor de Recibir los mensajes de WhatsApp en tu sistema, para enterarte en el momento de cada mensaje nuevo y pedir solo ese historial.

1. Listá las conversaciones que cambiaron

Listar conversaciones devuelve las conversaciones de la cuenta, con filtros. Con updated_since pedís solo las que cambiaron desde una fecha; con perPage (de 1 a 100, 25 si no lo mandás), el tamaño de cada página.

curl -G "https://api.funnelchat.com/api/v1/conversations" \
  --data-urlencode "updated_since=2026-10-01T00:00:00Z" \
  --data-urlencode "perPage=50" \
  -H "Authorization: Bearer $FC_API_KEY" \
  -H "Accept: application/json"

La respuesta trae data (una conversación por elemento), links y meta. Para paginar te importa meta (según la especificación):

{
  "meta": {
    "path": "https://api.funnelchat.com/api/v1/conversations",
    "per_page": 50,
    "next_cursor": "…",
    "prev_cursor": null
  }
}

Otros filtros que acepta, combinables con updated_since: deviceId (el id de uno de tus números), unreadMessages, activeConversation, advisorId, contactId y kanbanSettingId, entre otros. La página de Listar conversaciones en la referencia los lista todos.

Dos detalles que la especificación no fija

  • El formato de updated_since. La especificación lo declara como texto, sin formato. En los ejemplos usamos una fecha ISO 8601 en UTC; antes de depender de ella, confirmá con tu clave que filtra como esperás.
  • Los campos de cada conversación. data es una lista de objetos sin esquema documentado. Leé los campos de una respuesta real y tolerá que cambien: la v0 cambia sin aviso.

2. Recorré todas las páginas con el cursor

Este listado pagina por cursor: no hay números de página ni total. Para pedir la página siguiente, mandá cursor con el valor de meta.next_cursor, el mismo perPage y los mismos filtros. Cuando meta.next_cursor llega en null, no hay más páginas.

# La segunda página: el cursor es el meta.next_cursor de la respuesta anterior
curl -G "https://api.funnelchat.com/api/v1/conversations" \
  --data-urlencode "updated_since=2026-10-01T00:00:00Z" \
  --data-urlencode "perPage=50" \
  --data-urlencode "cursor=$NEXT_CURSOR" \
  -H "Authorization: Bearer $FC_API_KEY" \
  -H "Accept: application/json"

Armá vos la URL de cada página, con los mismos parámetros, en lugar de depender de los enlaces de links: así no importa qué parámetros conserven.

3. Encontrá al contacto

El historial se pide por contacto, con su id de la API. Si partís de un teléfono, por ejemplo el data.contact.phone de un evento message.received, buscalo con Listar contactos:

  • Quitale el + antes de buscar. Los eventos traen el teléfono con + y la API lo guarda sin él.
  • Quedate con el que tenga ese phone exacto. La búsqueda por phone también devuelve contactos cuyo teléfono contiene el número buscado.
  • Mandá siempre perPage.

El detalle está en El teléfono en los eventos y en la API.

curl -G "https://api.funnelchat.com/api/v1/contacts" \
  --data-urlencode "phone=5491100000000" \
  --data-urlencode "perPage=25" \
  -H "Authorization: Bearer $FC_API_KEY" \
  -H "Accept: application/json"

Respuesta de ejemplo (recortada a un contacto, a algunos de sus campos y sin links):

{
  "data": [
    {
      "id": 102578466,
      "name": "Ana Pérez",
      "email": "",
      "phone": "5491100000000",
      "whatsapp_id": "",
      "has_phone": true,
      "country_code": "",
      "status": 1,
      "created_at": "2026-10-04T21:23:45.000000Z",
      "active_conversation": 0,
      "unread_messages": 0
    }
  ],
  "meta": {
    "current_page": 1,
    "from": 1,
    "last_page": 1,
    "path": "https://api.funnelchat.com/api/v1/contacts",
    "per_page": 25,
    "to": 1,
    "total": 1
  }
}

4. Traé el historial de mensajes del contacto

Listar los mensajes de un contacto devuelve sus mensajes, paginados por cursor como en el paso 2: perPage (de 1 a 100), cursor para la página siguiente y updated_since para pedir solo lo nuevo. {contactId} es el id del paso anterior.

curl -G "https://api.funnelchat.com/api/v1/contacts/102578466/messages" \
  --data-urlencode "perPage=100" \
  -H "Authorization: Bearer $FC_API_KEY" \
  -H "Accept: application/json"

Respuesta de ejemplo (recortada a un mensaje, a algunos de sus campos y sin links; … marca valores cuyo formato la especificación no documenta):

{
  "data": [
    {
      "id": 734512,
      "uid": "…",
      "chat_id": "…",
      "contact_id": 102578466,
      "device_id": 4521,
      "text": "Hola, quiero más información",
      "file": "",
      "time": "…",
      "reference_message_uid": null,
      "deleted_at": null,
      "reactions": []
    }
  ],
  "meta": {
    "path": "https://api.funnelchat.com/api/v1/contacts/102578466/messages",
    "per_page": 100,
    "next_cursor": "…",
    "prev_cursor": null
  }
}

Cada mensaje trae también own, type, status y origin, entre otros. Guardalos por su id (un entero): si un mensaje vuelve a llegar en otra sincronización, actualizalo en lugar de duplicarlo.

5. Mantenelo al día

Con los pasos anteriores ya tenés todo para una sincronización incremental:

  1. Primera carga: recorré Listar conversaciones sin updated_since para saber qué conversaciones hay, y traé el historial completo de cada contacto que te interese (pasos 3 y 4).
  2. Cada vez que sincronices: anotá la hora en que empezás y pedí solo lo cambiado desde la sincronización anterior, con updated_since. Pedí con un margen de unos minutos hacia atrás: los repetidos los descartás por id.
  3. En el momento: si tenés el receptor de message.received, cuando llega un mensaje buscá al contacto por teléfono (paso 3) y pedí sus mensajes con updated_since (paso 4). Dejá la sincronización periódica como respaldo, por si tu receptor estuvo caído más que los reintentos.

Si falla

Qué vesQué pasóQué hacer
401Falta la clave, no existe o fue revocada.Revisá la cabecera Authorization: Bearer con la clave completa.
403 con error: "permission_denied"A la clave le falta conversations:read.Creá una clave con ese permiso.
403 sin errorLo rechazó la autorización propia de conversations, no el portero.Leé message.
404 en los mensajesNo hay un contacto con ese id en la cuenta.Volvé a buscarlo por teléfono (paso 3).
422Un parámetro no pasó la validación, por ejemplo perPage fuera de 1 a 100 o un valor de orden que el listado no admite.errors dice qué parámetro corregir (por ejemplo errors.perPage).
500 en las conversaciones, con error: "No se pudieron cargar las conversaciones"Falló la carga del listado.Reintentá más tarde, con la misma página.
503El portero no pudo evaluar la llamada (gate_unavailable).Esperá lo que indica Retry-After y reintentá.

Decidí por el código HTTP y por error, no por message: su texto cambia según el dominio. El detalle está en Errores.

Relacionado

En esta página