Configuración detallada
1. Crear app Server-to-Server OAuth
- https://marketplace.zoom.us > Develop > Build App
- Tipo de app: Server-to-Server OAuth
- Credenciales de la app: copia el Account ID, Client ID, Client Secret
2. Scopes necesarios
meeting:read:admin— listar meetingsmeeting:write:admin— crear/actualizar/eliminar meetingsrecording:read:admin— acceder a grabacionesuser:read:admin— información de los hosts
3. Event Subscriptions (webhook)
- App > Feature > Event Subscriptions
- URL de suscripción:
https://[tenant].studeia.com/api/webhooks/video/zoom - Autenticación: Webhook secret token (cópialo en Studeia)
- Eventos a suscribir:
- Meeting > Meeting Started
- Meeting > Meeting Ended
- Meeting > Participant Joined / Left
- Recording > Recording Completed
- Recording > Recording Transcript Completed
4. Configurar en Studeia
Settings > Video Provider > Zoom > Add:
- Account ID
- Client ID
- Client Secret
- Webhook Secret Token (del paso 3)
- Set as default (opcional — usa Zoom para todas las LiveClasses sin override)
Studeia almacena todo cifrado con AES-256-GCM.
Cómo funciona
Admin/Profesor crea LiveClass en Studeia (videoProvider=zoom)
↓
Studeia ZoomAdapter.createMeeting()
→ Server-to-Server OAuth token (cached Redis 55 min)
→ POST https://api.zoom.us/v2/users/{userId}/meetings
→ Devuelve meetingId + joinUrl + startUrl + password
↓
Studeia guarda en LiveClass.providerMeetingId / providerJoinUrl / providerData
↓
El alumno accede mediante /live-classes/[id] > clic en "Entrar"
→ joinMethod=external (nueva pestaña) — Zoom NO soporta iframe (X-Frame-Options)
→ Abre la app/web de Zoom
↓
Durante el meeting: los webhooks notifican a Studeia
→ meeting.started → LiveClass.actualStartTime
→ participant.joined → LiveClassAttendance
→ meeting.ended → LiveClass.actualEndTime
↓
Tras finalizar el meeting (~5-30 min de procesamiento en Zoom):
→ webhook recording.completed
→ Studeia actualiza LiveClass.recordingUrl
→ webhook recording.transcript_completed
→ Studeia crea LiveClassTranscription con VTT parseado
Cron fallback
Los webhooks de Zoom son poco fiables (retrasos, expiración de suscripciones, fallos de red). Studeia ejecuta /api/cron/recording-sync cada 15 min:
- Busca LiveClasses completadas hace más de 15 min sin recordingUrl
- Para cada una, llama a
adapter.getRecordings(meetingId)mediante la API de Zoom - Si encuentra resultados, actualiza recordingUrl + crea LiveClassTranscription
Ingesta RAG de la transcripción
Tras la aprobación de la transcripción por parte del profesor:
/institution/courses/[id]/transcriptions/[tid]/approve- El texto de la transcripción se convierte en chunks + embeddings + ContentBlock
- Metadata:
{ source: "live_class_transcript", liveClassId, courseId } - El tutor de IA cita: "En la clase en vivo del día X, la profesora explicó que..."
Solución de problemas
"401 Unauthorized" al crear un meeting
Token expirado. Verificar logs:
- Server-to-Server OAuth token cached Redis 55 min (renovación automática)
- Si persiste: rotar el Client Secret en Zoom Marketplace + actualizar en Studeia
El webhook no llega
- Verificar que la URL del webhook sea accesible públicamente (curl externo)
- Validar la firma HMAC SHA-256 (Studeia registra un warning si hay mismatch)
- Zoom reintenta 3 veces con backoff — si falla las 3 veces, el evento del webhook se pierde (el cron lo recupera)
Grabación sin VTT
El VTT solo se genera si Zoom Cloud Recording está habilitado (no Local Recording). Verificar User > Settings > Recording > Cloud recording activado.
Costos
- Studeia: sin costo adicional (incluido en cualquier plan)
- Zoom: facturación directa de Zoom (licencia por host). Studeia no revende Zoom.