Webhooks – Eventos en tiempo real
Los webhooks de BigBlueButton permiten que tu aplicación reciba notificaciones HTTP POST en tiempo real cada vez que ocurren eventos de reunión. En lugar de consultar repetidamente getMeetings o getMeetingInfo, registras una URL de devolución de llamada y BigBlueButton te envía automáticamente los eventos. Este capítulo cubre los tres endpoints API de webhook, el formato de callback, los tipos de eventos, el comportamiento de reintento y la configuración del servidor.
Los webhooks requieren que el paquete bbb-webhooks esté instalado en el servidor. Varios detalles descritos en este capítulo no están cubiertos por la documentación oficial de BigBlueButton y se han determinado mediante análisis del código fuente. undocumented
Requisitos previos
El paquete bbb-webhooks debe instalarse en el servidor BigBlueButton antes de que los endpoints de webhook estén disponibles:
sudo apt-get install bbb-webhooks Si la aplicación de webhook no está en ejecución cuando se crea una reunión, no se establece ningún mapeo interno de la reunión. Como resultado, no se activará ningún callback para esa reunión.
hooks/create — Registrar un webhook
GET https://api-guide.bbbserver.com/bigbluebutton/api/hooks/create?<parameters>&checksum=replace-with-checksum La documentación oficial no especifica un método HTTP. El router de Express registra solo rutas GET; no se aceptan solicitudes POST. undocumented
| Parámetro | Tipo | Obligatorio | Predeterminado | Descripción |
|---|---|---|---|---|
callbackURL | String | Sí | — | La URL que recibirá callbacks de POST. La detección de duplicados se basa únicamente en esta URL; la misma URL no puede registrarse dos veces, ni siquiera con un meetingID o eventID diferente. |
meetingID | String | No | — | Restringe el hook a una reunión específica (ID externo de la reunión). Si se omite, el hook se convierte en un hook global que se activa para todas las reuniones. |
eventID | String | No | — | Lista de tipos de eventos separados por comas que se deben escuchar (p. ej. user-joined,meeting-ended). Si se omite, se entregan todos los eventos. El filtro no distingue entre mayúsculas y minúsculas. Disponible desde BBB 2.5. |
getRaw | Boolean | No | false | Cuando se establece en true, los callbacks contienen el mensaje Redis sin procesar en lugar de los datos de evento procesados. |
Respuesta exitosa
<response>
<returncode>SUCCESS</returncode>
<hookID>replace-with-hook-id</hookID>
<permanentHook>false</permanentHook>
<rawData>false</rawData>
</response> Registro duplicado
Si se registra de nuevo la misma callbackURL, la respuesta sigue devolviendo SUCCESS pero incluye un duplicateWarning. El hook existente se mantiene sin cambios — meetingID, eventID y getRaw no se actualizan.
<response>
<returncode>SUCCESS</returncode>
<hookID>replace-with-hook-id</hookID>
<messageKey>duplicateWarning</messageKey>
<message>There is already a hook for this callback URL.</message>
</response> Respuestas de error
messageKey | Descripción |
|---|---|
checksumError | El checksum no es válido o falta. |
missingParamCallbackURL | No se proporcionó el parámetro callbackURL. undocumented |
createHookError | Se produjo un error interno (p. ej., Redis inalcanzable). Consulta los registros del servidor. |
hooks/list — Listar webhooks registrados
GET https://api-guide.bbbserver.com/bigbluebutton/api/hooks/list?<parameters>&checksum=replace-with-checksum | Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
meetingID | String | No | Filtra por ID de reunión. El resultado incluye tanto los hooks de la reunión especificada como todos los hooks globales. Si se omite, se devuelven todos los hooks registrados. |
Respuesta exitosa
<response>
<returncode>SUCCESS</returncode>
<hooks>
<hook>
<hookID>replace-with-hook-id</hookID>
<callbackURL><![CDATA[https://api-guide.bbbserver.com/callbacks/webhook]]></callbackURL>
<meetingID><![CDATA[replace-with-meeting-id]]></meetingID>
<eventID>user-joined,meeting-ended</eventID>
<permanentHook>false</permanentHook>
<rawData>false</rawData>
</hook>
</hooks>
</response> El elemento <meetingID> solo aparece para hooks específicos de una reunión. Los hooks globales no tienen elemento <meetingID>. Del mismo modo, <eventID> solo aparece cuando se estableció un filtro de eventos durante la creación.
Respuestas de error
messageKey | Descripción |
|---|---|
checksumError | El checksum no es válido o falta. |
listHookError | Se produjo un error interno al listar los hooks. Revisa los registros del servidor. undocumented |
hooks/destroy — Eliminar un webhook
GET https://api-guide.bbbserver.com/bigbluebutton/api/hooks/destroy?<parameters>&checksum=replace-with-checksum | Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
hookID | String | Sí | El ID del hook que se va a eliminar (obtenido de hooks/create o hooks/list). |
Respuesta exitosa
<response>
<returncode>SUCCESS</returncode>
<removed>true</removed>
</response> Los hooks permanentes (configurados en el servidor mediante permanentURLs) no pueden eliminarse a través de la API. Si se intenta hacerlo, se devuelve un error destroyMissingHook como si el hook no existiera.
Respuestas de error
messageKey | Descripción |
|---|---|
checksumError | El checksum no es válido o falta. |
missingParamHookID | No se proporcionó el parámetro hookID. |
destroyMissingHook | El ID del hook no existe o pertenece a un hook permanente. |
destroyHookError | Se produjo un error interno al eliminar el hook. Revisa los registros del servidor. |
hooks/ping — Comprobación de estado
GET https://api-guide.bbbserver.com/bigbluebutton/api/hooks/ping Este endpoint de diagnóstico no requiere suma de verificación. Si la aplicación webhook es accesible, devuelve la cadena de texto sin formato bbb-webhooks API up! (no XML, tipo de contenido text/plain). undocumented
Formato de callback
Los callbacks de webhook se envían como solicitudes HTTP POST con tipo de contenido application/x-www-form-urlencoded. El cuerpo de la solicitud contiene tres campos:
| Campo | Descripción |
|---|---|
domain | El dominio del servidor (de la configuración del webhook). undocumented |
event | Un array JSON que contiene los datos del evento. Siempre es un array, incluso para un único evento. |
timestamp | Una marca de tiempo Unix en milisegundos en el momento del envío. |
Cuerpo de callback procesado (getRaw=false)
domain=myserver.com&event=[{"data":{"type":"event","id":"user-joined","attributes":{...},"event":{"ts":1532718316938}}}]×tamp=1532718316953 Cuerpo de callback sin procesar (getRaw=true)
domain=myserver.com&event=[{"envelope":{"name":"UserJoinedMeetingEvtMsg","routing":{"sender":"bbb-apps-akka"}},"core":{"header":{...},"body":{...}}}]×tamp=1532718316953 Cuando el servidor está configurado con multiEvent mayor que 1, varios eventos pueden agruparse en el array event dentro de un solo callback.
Validación de la suma de verificación del callback
En el modo predeterminado, cada URL de callback recibe un parámetro de consulta checksum que tu aplicación debe verificar:
https://api-guide.bbbserver.com/callbacks/webhook?checksum=replace-with-checksum La fórmula de validación es:
sha<algo>(<callback-URL-without-checksum> + <URL-encoded-body> + <shared-secret>) Toma la URL de callback registrada sin el parámetro checksum.
Añade el cuerpo completo de la solicitud codificado como URL (domain=...&event=[...]×tamp=...).
Añade el secreto compartido BBB.
Haz un hash de la cadena resultante con el algoritmo configurado (predeterminado: sha1, configurable mediante hookChecksumAlgorithm).
Modo Auth 2.0 / Bearer
Como alternativa, el servidor puede configurarse con auth2_0: true. En este modo, no se añade ningún parámetro checksum a la URL de callback. En su lugar, el secreto compartido se envía como un token Bearer en la cabecera Authorization: undocumented
Authorization: Bearer <shared-secret> Comportamiento del callback
- Códigos de estado HTTP aceptados: HTTP
2xxy HTTP401se consideran una entrega correcta. Todos los demás códigos de estado activan un reintento. undocumented - Redirecciones: Se siguen las respuestas HTTP
3xx(hasta 10 saltos). Solo si no se alcanza ningún2xx/401después de 10 redirecciones, el callback se considera fallido. - Tiempo de espera: Cada solicitud de callback tiene un tiempo de espera de 5 segundos (configurable mediante
requestTimeout). - Intervalos de reintento: En caso de fallo, los reintentos usan back-off exponencial:
100ms, 500ms, 1s, 2s, 4s, 8s, 10s, 30s, 60s, 60s, 60s, 60s(12 intentos durante aproximadamente 5 minutos, configurable medianteretryIntervals). - Después de agotar todos los reintentos: Los hooks no permanentes se eliminan automáticamente. Los hooks permanentes siguen reintentándolo indefinidamente a intervalos de 60 segundos (configurable mediante
permanentIntervalReset).
Tipos de eventos
Eventos de reunión
| ID del evento | Descripción |
|---|---|
meeting-created | Se creó una reunión. |
meeting-ended | Una reunión ha finalizado. Esto también activa eventos sintéticos user-left para todos los usuarios conectados. |
meeting-recording-started | La grabación ha comenzado. |
meeting-recording-stopped | La grabación se ha detenido. |
meeting-recording-unhandled | Evento de grabación no gestionado (respaldo cuando el estado de la grabación no es ni true ni false). |
meeting-screenshare-started | Se inició el uso compartido de pantalla (incluye datos del usuario presentador). |
meeting-screenshare-stopped | Se detuvo el uso compartido de pantalla (incluye datos del usuario propietario). |
meeting-presentation-changed | La presentación activa cambió (incluye presentation-id). |
Eventos de usuario
| ID del evento | Descripción |
|---|---|
user-joined | Un usuario se unió a la reunión (incluye indicador de invitado, datos de usuario, dirección IP, User-Agent). |
user-left | Un usuario salió de la reunión (incluye indicador de invitado). También se genera sintéticamente en meeting-ended. |
user-audio-voice-enabled | Audio habilitado (incluye indicadores listening-only, sharing-mic, muted). |
user-audio-voice-disabled | Audio desactivado. |
user-audio-muted | Se silenció al usuario. |
user-audio-unmuted | Se reactivó el audio del usuario. |
user-audio-unhandled | Evento de audio no controlado (alternativa). |
user-cam-broadcast-start | Cámara web iniciada (incluye stream-id). |
user-cam-broadcast-end | La cámara web se detuvo. |
user-presenter-assigned | Se asignó al usuario el rol de presentador. |
user-presenter-unassigned | Se retiró al usuario el rol de presentador. |
user-emoji-changed | Se cambió el emoji o la reacción del usuario (incluye el valor del emoji). |
user-raise-hand-changed | El usuario levantó o bajó la mano (incluye el booleano raise-hand). En versiones de BBB anteriores a 2.7, esto se genera sintéticamente a partir de user-emoji-changed. |
Eventos de chat y notas
| ID del evento | Descripción |
|---|---|
chat-group-message-sent | Se envió un mensaje en el chat público. Los mensajes de chat privado no generan eventos de webhook. |
transcript-updated | Transcripción actualizada (incluye transcript, locale, indicador final). |
pad-content | Cambió el contenido de las notas compartidas (incluye pad-id, rev, text). |
Eventos de encuesta
| ID del evento | Descripción |
|---|---|
poll-started | Se inició una encuesta (incluye la pregunta y las opciones de respuesta). |
poll-responded | Un participante respondió a una encuesta (incluye los ID de las respuestas). |
Eventos de grabación y reproducción (RAP)
| ID del evento | Descripción |
|---|---|
rap-archive-started | Se inició el archivado. |
rap-archive-ended | Archivado completado (incluye el indicador recorded y la duración). |
rap-sanity-started | Se inició la comprobación de integridad. |
rap-sanity-ended | Comprobación de integridad completada. |
rap-post-archive-started | Se inició el posarchivado. |
rap-post-archive-ended | Posarchivado completado. |
rap-process-started | Se inició el procesamiento. |
rap-process-ended | Procesamiento completado. |
rap-post-process-started | Se inició el posprocesamiento. |
rap-post-process-ended | Posprocesamiento completado. |
rap-publish-started | Se inició la publicación. |
rap-publish-ended | Publicación completada (incluye el objeto completo de grabación con metadatos, reproducción e información de descarga). |
rap-post-publish-started | Se inició la pospublicación. |
rap-post-publish-ended | Pospublicación completada. |
rap-published | Grabación publicada. |
rap-unpublished | Grabación despublicada. |
rap-deleted | Grabación eliminada. |
La mayoría de los eventos RAP incluyen record-id, success (booleano) y step-time. Los eventos con un campo workflow contienen además el nombre del flujo de trabajo de procesamiento.
Configuración del servidor
Las siguientes opciones se pueden configurar en /etc/bigbluebutton/bbb-webhooks.yml o config/default.yml. La mayoría de estas opciones no están cubiertas en la documentación oficial. undocumented
| Opción | Predeterminado | Descripción |
|---|---|---|
hookChecksumAlgorithm | sha1 | Algoritmo hash para checksums de callback (sha1, sha256, sha384, sha512). |
api.supportedChecksumAlgorithms | [sha1, sha256, sha384, sha512] | Algoritmos aceptados para las sumas de verificación entrantes de la API. |
api.port | 3005 | Puerto del servidor API de webhook. |
api.bind | 127.0.0.1 | Dirección de enlace del servidor API. |
includeEvents | [] | Filtro de eventos global del servidor: solo estos eventos se entregan a todos los hooks. Vacío significa todos los eventos. |
excludeEvents | [] | Filtro de eventos global del servidor: estos eventos se suprimen para todos los hooks. Vacío significa sin exclusiones. |
permanentURLs | [] | Lista de URL de hooks permanentes que se registran al inicio y no se pueden eliminar mediante la API. |
retryIntervals | [100,500,1000,...,60000] | Intervalos de reintento en milisegundos para callbacks fallidos. |
permanentIntervalReset | 60000 | Intervalo de reintento en milisegundos para hooks permanentes después de agotar todos los reintentos regulares. |
requestTimeout | 5000 | Tiempo de espera HTTP en milisegundos para las solicitudes de callback. |
multiEvent | 1 | Cuando se establece en un valor mayor que 1, varios eventos se agrupan en la matriz de eventos por callback. |
queueSize | 10000 | Tamaño máximo de la cola interna de eventos. |
bbb.auth2_0 | false | Habilita la autenticación mediante token Bearer en lugar de checksum en URL para callbacks. |
includeEvents y excludeEvents son filtros de todo el servidor que se aplican además del filtro eventID por hook. Un evento debe pasar ambos filtros para ser entregado.
Notas operativas
- Persistencia: Los hooks se almacenan en Redis y sobreviven a reinicios del servidor (se resincronizan al arrancar).
- Orden: Las callbacks se envían secuencialmente por hook, una a la vez, preservando el orden de los eventos.
- Unicidad de URL: La detección de duplicados se basa únicamente en la URL de callback. La misma URL no puede registrarse con filtros
meetingIDoeventIDdiferentes; prevalece el primer registro. - Limpieza de datos: Los mapeos internos de reuniones se eliminan después de una semana de inactividad (configurable mediante
mappings.timeout, por defecto: 604800000 ms). - Eventos sintéticos: Cuando termina una reunión, se generan automáticamente eventos
user-leftpara todos los usuarios aún conectados, porque BigBlueButton en sí no emiteUserLeftMeetingEvtMsgal finalizar una reunión. - Chats privados: Solo los mensajes del chat público generan eventos
chat-group-message-sent. Los mensajes privados se ignoran silenciosamente.
meetingID para cada hook; no se admiten hooks globales sin un meetingID; (2) los datos personales en los eventos se ofuscan automáticamente por privacidad (p. ej., las direcciones IP de los participantes no son visibles).Preguntas frecuentes
bbb-webhooks debe instalarse mediante apt-get install bbb-webhooks. Sin él, los endpoints hooks/create, hooks/list y hooks/destroy no están disponibles.duplicateWarning y el hook existente permanecerá sin cambios. Para supervisar reuniones específicas por separado, usa URLs de callback distintas.MAIN-PUBLIC-GROUP-CHAT) activan un evento chat-group-message-sent. Los mensajes privados entre participantes no generan ningún evento de webhook.getRaw=false (el valor predeterminado), recibes datos de evento procesados con una estructura estandarizada que contiene campos type, id y attributes. Con getRaw=true, recibes el mensaje Redis sin procesar tal como lo publica internamente BigBlueButton, que incluye campos envelope y core. El formato sin procesar es útil para depuración o cuando necesitas datos que no están incluidos en el formato procesado.permanentURLs y no pueden eliminarse a través de la API. Llamar a hooks/destroy en un hook permanente devuelve un error destroyMissingHook como si el hook no existiera.2xx y HTTP 401 se consideran ambos una entrega correcta. Todos los demás códigos de estado, incluidos 3xx (después de seguir hasta 10 redirecciones), 4xx (excepto 401) y 5xx, activan un reintento. Este comportamiento no está documentado en la documentación oficial de BigBlueButton.