Skip to main content
Los webhooks empujan eventos a tu servidor. El stream de eventos en tiempo real los empuja a tu front: un solo GET de larga duración que recibe cada evento en el momento, con replay garantizado si se corta la conexión. Usa el stream para mantener un dashboard vivo (saldos, payins que acreditan, payouts que liquidan, autorizaciones de tarjeta, alertas KYT para los admins). Usa webhooks para todo lo que deba sobrevivir a que cierren el navegador — los dos canales llevan los mismos eventos con el mismo payload y el mismo event_id, así no escribes dos mapeos.

Abrir el stream

El endpoint pide la misma credencial Authorization: Bearer que el resto de la API, así que el EventSource nativo del navegador (que no puede mandar headers) no sirve. Usa fetch leyendo el cuerpo como stream:
Respuesta
Cada frame de evento trae tres líneas:

Reconectar sin huecos

Si se corta la conexión, reconecta mandando el último cursor procesado. El servidor replaya desde el log todo lo que te perdiste antes de volver al vivo, así una red inestable nunca pierde un evento.
El replay tiene tope de 1.000 eventos. Si estuviste desconectado el tiempo suficiente para perderte más, el stream emite un evento de control replay_truncated y conviene reconciliar con ?snapshot=true o con GET /v1/events/history en vez de asumir continuidad.

Snapshot inicial

Abrir con ?snapshot=true envía primero el estado actual y después los deltas. Elimina la carrera clásica de “leo los endpoints REST, después me suscribo y pierdo lo que pasó en el medio”: el cursor se toma con la suscripción ya abierta, así nada se cae por la rendija.
El snapshot es estado absoluto, nunca deltas: aplicarlo dos veces es inocuo. Trae balances para una credencial de cuenta (los mismos campos de GET /v1/balances) y, para un admin de organización, los contadores de health operativa.

Filtrar por tipo de evento

?types= acota lo que recibes. Solo puede restringir lo que tu credencial ya ve, jamás ampliarlo. Un tipo desconocido se rechaza con 400 invalid_event_type en vez de dejarte esperando eventos que no llegan.

Alcance: cuenta vs admin de organización

Una cuenta nunca ve los eventos de otra cuenta ni la superficie de compliance org-wide. El stream jamás entrega un campo que esa misma credencial no pudiera leer por REST.

Eventos de control

Además de tus eventos de negocio, el stream emite eventos de protocolo. No llevan id: (salvo snapshot), así que no mueven tu cursor de replay. Cada 20 segundos llega un comentario : ping para que ningún proxy corte una conexión ociosa — ignora las líneas que empiezan con :.

Límites

Pasarse del límite de concurrencia devuelve 429 too_many_streams. Pasarse de la cuota de aperturas devuelve 429 rate_limited — esa cuenta intentos, así que un cliente que reconecta en bucle la quema aunque no tenga ningún stream abierto. Respeta siempre el retry: (3 s) más backoff exponencial.

Historial consultable

El mismo log que alimenta el stream se lee por REST — útil para auditoría, para una vista de “qué me perdí” o cuando el replay quedó truncado.
Un evento puntual por su id público:
El log de eventos guarda 90 días. Es un buffer de notificación, no el registro financiero: saldos, payins, payouts, transferencias y asientos del ledger son inmutables y siguen disponibles por el tiempo que exige la regulación en sus propios endpoints y en la cartola.

Errores

Lista completa en Errores.

Preguntas frecuentes

No. El stream vive mientras vive la pestaña; los webhooks llegan a tu backend aunque nadie esté mirando. Usa el stream para la UI y los webhooks para todo lo que dispare lógica de negocio (conciliación, contabilidad, notificaciones).
Sí — tras una reconexión el replay puede reentregar el evento del borde, y ambos canales (webhook y stream) comparten el mismo event_id. Deduplica por event_id y trata cada payload como estado absoluto.
Por diseño. Un stream sin tope de vida esconde conexiones filtradas. El servidor manda antes un evento de control reconnect, y reconectar con Last-Event-ID continúa exactamente donde ibas.
No. El stream no se configura: entrega todo lo que tu credencial puede ver. Las suscripciones de webhook solo controlan las entregas HTTP a tu servidor.
Revisa que tu cliente HTTP no esté bufereando la respuesta (en fetch, lee res.body como stream en vez de esperar res.text()) y que ningún proxy tuyo esté bufereando text/event-stream. CBPay ya desactiva el buffering de su lado.
Sí, con ?account_id=. El filtro solo opera dentro de tu propia organización; cualquier otra cosa devuelve 404.
Última modificación el 26 de julio de 2026