Volver al blog
Desarrolladores

Paginación de la API de Waspy: page y cursor, y el error INVALID_CURSOR

Contactos y plantillas usan page y pageSize. Conversaciones, mensajes y el log de webhooks usan un cursor opaco. Si lo fabricás, la API responde 400 INVALID_CURSOR.

· 9 min
Paginación de la API de Waspy: page y cursor, y el error INVALID_CURSOR

Respuesta corta: la API v2 no pagina todo igual. Contactos y plantillas usan page y pageSize. Conversaciones, mensajes y el log de webhooks usan un cursor que tenés que copiar de meta.cursor. Si lo inventás, GET /conversations, GET /conversations/:id/messages y GET /webhooks/:id/deliveries responden 400 INVALID_CURSOR.

La tabla está en paginación. La API está en Scale y Enterprise: Planes y la API.

Los dos modelos

RecursoModeloParámetrosOrden
GET /api/v2/contactspagepage (default 1), pageSize (default 20, máx. 100)Creados, más nuevos primero
GET /api/v2/templatespageIgualCreados, más nuevos primero
GET /api/v2/conversationscursorcursor, limit (default 20, máx. 100)Más recientes primero
GET /api/v2/contacts/:id/conversationscursorcursor, limit (default 20, máx. 100)Más recientes primero
GET /api/v2/conversations/:id/messagescursorcursor, limit (default 50, máx. 100)Más antiguos primero
GET /api/v2/webhooks/:id/deliveriescursorcursor, limit (default 50, máx. 100), statusMás nuevos primero
meta de la página trae page, pageSize y total. meta del cursor trae cursor y hasMore. Los dos traen requestId.

Page: contactos y plantillas

curl -sS "https://api.waspytech.com/api/v2/contacts?page=2&pageSize=50" \
  -H "Authorization: Bearer $WASPY_API_KEY"

Hay otra página si page * pageSize < total. pageSize fuera de 1–100 no pasa el schema. El mismo par va en plantillas, junto con status y phoneNumberId si los usás. Cómo leer approved está en listar plantillas.

Este modelo sirve cuando la lista es bastante estable y te importa el total (“página 3 de 142”). En un inbox que se mueve mientras paginás, el offset se saltea o repite filas. Por eso los chats no usan page.

Cursor: no lo armes

La primera llamada no manda cursor.

curl -sS "https://api.waspytech.com/api/v2/conversations?limit=20" \
  -H "Authorization: Bearer $WASPY_API_KEY"

Si meta.hasMore es true, la siguiente es la misma URL con cursor igual al string que vino. No le saques caracteres, no le cambies la zona horaria, no reemplaces el id por el waMessageId.

Qué valida el servidor

En conversaciones, mensajes y deliveries el cursor pasa por un validador. Tiene que ser una fecha ISO que termine en Z (con o sin milisegundos), una barra vertical y un UUID. Si falta la barra, la fecha no matchea o el id no es un UUID, la respuesta es:

CampoValor
HTTP400
codeINVALID_CURSOR
messageCursor format is invalid
Eso está a propósito: un cursor mal formado, casteado directo en Postgres, se filtraba como 500. Un número de página, un offset=40 o un id suelto caen en este 400.

La doc de paginación muestra un ejemplo con forma fecha|uuid para que se vea el compuesto. Eso no es una invitación a construirlo. El valor que tenés que mandar es el de meta.cursor, opaco. La nota de la doc dice lo mismo: no lo modifiques ni lo armes a mano.

GET /contacts/:id/conversations también rechaza un cursor sin las dos partes (INVALID_CURSOR). Igual: copiá el que devolvió la llamada anterior.

Orden, para no mezclar la UI

Las conversaciones y el log de webhooks van de lo nuevo a lo viejo. Los mensajes de un chat van de lo viejo a lo nuevo, que es como se dibuja la bandeja: el cursor pide el tramo más antiguo. Si lo usás al revés, el hilo se arma cabeza abajo.

status en deliveries es success, failed o all (el default). El alta del webhook, el test y el replay están en gestionar webhooks.

Un recorrido corto

  1. GET /contacts?page=1&pageSize=100 hasta que page * pageSize alcance a total.
  2. Por cada contacto, GET /contacts/:id/conversations?limit=20 y seguí meta.cursor mientras hasMore sea true.
  3. Por cada conversación, GET /conversations/:id/messages?limit=50 del mismo modo. Scope messages:read.
  4. No persistás el cursor de ayer para “seguir desde ahí” mañana sin haberlo recibido en esa respuesta. Pedí la primera página de nuevo.

Scopes de lectura: contacts:read, templates:read, conversations:read, messages:read, webhooks:read.

Diez días de prueba, sin tarjeta, en el registro. La referencia de envío, que no pagina pero sí devuelve el id que después ves en el mensaje, está en messages.

Tu equipo atendiendo por WhatsApp en minutos

CRM facil pero potente. En 10 minutos tenes a tu equipo trabajando — no necesitas hablar con nadie.