Saltar al contenido principal

Webhooks

Plug-N-Meet puede notificar a su aplicación sobre diversos eventos enviando solicitudes de webhook a una URL especificada. Puede configurar esta URL en los ajustes del servidor o proporcionarla al crear una sala.

Recepción de Webhooks​

Las solicitudes de webhook se envían como solicitudes HTTP POST a las URLs que haya configurado, ya sea en el archivo config.yml del servidor o durante la creación de la sala. Cada evento de webhook se codifica como JSON y se incluye en el cuerpo de la solicitud.

La solicitud tendrá la cabecera Content-Type establecida en application/json. Asegúrese de que su servidor web esté configurado para aceptar cargas útiles con este tipo de contenido.

Plug-N-Meet utiliza el mismo patrón de seguridad que LiveKit. Para verificar que las solicitudes de webhook provienen de plugNmeet, cada solicitud incluye las cabeceras Authorization y Hash-Token que contienen un token JWT firmado. El token incluye un hash SHA256 de la carga útil. Para un ejemplo en PHP, consulte webhook.php.

Eventos​

Puede revisar aquí las definiciones de los eventos.

Todos los eventos de webhook incluyen los siguientes campos:

  • id: Un UUID que identifica el evento
  • createdAt: Marca de tiempo UNIX en segundos

Sala Creada​

interface CommonNotifyEvent {
event: 'room_created'
room: Room
}

Sala Iniciada​

interface CommonNotifyEvent {
event: 'room_started'
room: Room
}

Sala Finalizada​

interface CommonNotifyEvent {
event: 'room_finished'
room: Room
}

Participante Unido​

interface CommonNotifyEvent {
event: 'participant_joined'
room: Room
participant: ParticipantInfo
}

Participante Abandonó la Sala​

interface CommonNotifyEvent {
event: 'participant_left'
room: Room
participant: ParticipantInfo
}

Pista Publicada​

Solo se incluyen sid, identity y name en los objetos Room y Participant.

interface CommonNotifyEvent {
event: 'track_published'
room: Room
participant: ParticipantInfo
track: TrackInfo
}

Pista No Publicada​

Solo se incluyen sid, identity y name en los objetos Room y Participant.

interface CommonNotifyEvent {
event: 'track_unpublished'
room: Room
participant: ParticipantInfo
track: TrackInfo
}

Grabación Iniciada​

interface CommonNotifyEvent {
event: 'start_recording'
room: Room
recording_info: RecordingInfoEvent
}

Grabación Finalizada​

interface CommonNotifyEvent {
event: 'end_recording'
room: Room
recording_info: RecordingInfoEvent
}

Grabación Procesada​

interface CommonNotifyEvent {
event: 'recording_proceeded'
room: Room
recording_info: RecordingInfoEvent
}

RTMP Iniciado​

interface CommonNotifyEvent {
event: 'start_rtmp'
room: Room
recording_info: RecordingInfoEvent
}

RTMP Finalizado​

interface CommonNotifyEvent {
event: 'end_rtmp'
room: Room
recording_info: RecordingInfoEvent
}

Artefacto Creado​

Este evento único y unificado se activa cada vez que el sistema genera un nuevo artefacto, como una transcripción o un resumen de la reunión. Sustituye a múltiples webhooks individuales y más antiguos por un modelo más flexible y escalable.

Para obtener detalles sobre la estructura de la carga útil y los posibles tipos de artefactos, consulte la definición de protobuf.

interface CommonNotifyEvent {
event: 'artifact_created'
room: Room
room_artifact: RoomArtifactWebhookEvent
}

Analíticas procesadas​

interface CommonNotifyEvent {
event: 'analytics_proceeded'
room: Room
analytics: AnalyticsEvent
}

Ejemplo de Gestor de Webhook​

El siguiente pseudocódigo demuestra cómo gestionar los webhooks entrantes. Su aplicación debe inspeccionar la propiedad event para determinar la acción a realizar. El evento artifact_created es especial, ya que requiere verificar un campo anidado type para comprender la carga útil.

// Un mapeo del número del enum a una cadena legible por humanos.
// Consulte la definición de protobuf para obtener la lista completa y actualizada.
const ArtifactType = {
0: 'UNKNOWN_ARTIFACT',
2: 'MEETING_SUMMARY',
4: 'SPEECH_TRANSCRIPTION',
5: 'SPEECH_TRANSCRIPTION_USAGE',
};

function handleWebhook(payload) {
console.log(`Evento recibido: ${payload.event}`);
const sala = payload.room;

switch (payload.event) {
case 'room_started':
console.log(`La sala '${sala.name}' ha comenzado.`);
break;

case 'participant_joined':
console.log(`El usuario '${payload.participant.name}' se unió a la sala '${sala.name}'.`);
break;

case 'artifact_created':
manejarArtefactoCreado(payload);
break;

case 'room_finished':
console.log(`La sala '${sala.name}' ha finalizado.`);
break;

default:
console.log(`Se recibió un evento no gestionado: ${payload.event}`);
}
}

// Un gestor dedicado para el evento 'artifact_created'
function handleArtifactCreated(payload) {
const artefacto = payload.room_artifact;
const tipoArtefacto = ArtifactType[artefacto.type] || 'UNKNOWN_ARTIFACT';

console.log(`Se creó un nuevo artefacto de tipo '${tipoArtefacto}'.`);

switch (tipoArtefacto) {
case 'MEETING_SUMMARY':
case 'SPEECH_TRANSCRIPTION':
// Estos son artefactos basados en archivos.
if (artefacto.metadata && artefacto.metadata.file_info) {
const infoArchivo = artefacto.metadata.file_info;
console.log(`Archivo disponible en: ${infoArchivo.file_path}`);
// Su lógica aquí: por ejemplo, descargar el archivo, vincularlo a una grabación.
}
break;

case 'SPEECH_TRANSCRIPTION_USAGE':
// Este es un artefacto basado en el uso.
if (artefacto.metadata && artefacto.metadata.duration_usage) {
const uso = artefacto.metadata.duration_usage;
console.log(`Uso de transcripción registrado: ${uso.duration_sec} segundos.`);
// Su lógica aquí: por ejemplo, actualizar los registros de facturación.
}
break;

default:
console.log(`Se recibió un tipo de artefacto no gestionado: ${tipoArtefacto}`);
}
}

// Ejemplo de carga útil entrante para 'artifact_created' (un resumen de la reunión)
const samplePayload = {
"event": "artifact_created",
"id": "EV_abc123",
"createdAt": 1761815000,
"room": {
"sid": "RM_zG9e4bY2pD-1761814595173",
"room_id": "room01",
"name": "Test Room"
},
"room_artifact": {
"type": 2, // Corresponde a MEETING_SUMMARY
"artifact_id": "ART_xyz789",
"metadata": {
"file_info": {
"file_path": "/path/to/summary.txt",
"file_size": 1024,
"mime_type": "text/plain"
}
}
}
};

// Debería llamar a su gestor con el cuerpo de la solicitud POST.
handleWebhook(samplePayload);