Capítulo 17 GET POST

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 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 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}}}]&timestamp=1532718316953

Cuerpo de callback sin procesar (getRaw=true)

domain=myserver.com&event=[{"envelope":{"name":"UserJoinedMeetingEvtMsg","routing":{"sender":"bbb-apps-akka"}},"core":{"header":{...},"body":{...}}}]&timestamp=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=[...]&timestamp=...).

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 2xx y HTTP 401 se 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ún 2xx/401 despué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 mediante retryIntervals).
  • 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 meetingID o eventID diferentes; 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-left para todos los usuarios aún conectados, porque BigBlueButton en sí no emite UserLeftMeetingEvtMsg al 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.
En bbbserver.de, los webhooks están disponibles con dos restricciones: (1) se requiere un 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

Sí. El paquete 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.

El sistema de webhooks reintenta la entrega con retroceso exponencial durante aproximadamente 5 minutos (12 intentos). Si todos los reintentos fallan, los hooks no permanentes se eliminan automáticamente. Los hooks permanentes continúan reintentándolo indefinidamente en intervalos de 60 segundos.

No. La detección de duplicados se basa únicamente en la URL de callback. Si registras la misma URL de nuevo, recibirás un duplicateWarning y el hook existente permanecerá sin cambios. Para supervisar reuniones específicas por separado, usa URLs de callback distintas.

No. Solo los mensajes enviados al chat público (MAIN-PUBLIC-GROUP-CHAT) activan un evento chat-group-message-sent. Los mensajes privados entre participantes no generan ningún evento de webhook.

Con 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.

No. Los hooks permanentes se configuran del lado del servidor mediante la opción 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.

HTTP 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.