Zoom Connector
Connector-Status: Geplant Noch nicht gebaut. Tajo betreibt diesen Connector heute nicht.
Illustration · Beispieldaten
Sync-Beispiel
Quelle
Zoom
Connector-Status: Geplant
Ziel
Ihr anderes Tool
Connector-Status: Eigenes Tool
Feldzuordnung
| Quellfeld | Zielfeld | Beispielwert |
|---|---|---|
record.id | source_id | record_1042 |
record.updated_at | updated_at | 2026-10-18T08:00:00Z |
record.value | value | sample_value |
- Entwerfen
- Einen Datensatz prüfen
- Diese Version freigeben
Der Status gilt für einzelne Connectoren und garantiert nicht, dass dieser Sync bereit ist. Felder zur Veranschaulichung. Prüfen Sie vor dem Sync das tatsächliche Schema und die Berechtigungen.
Verbinde Zoom über Tajo mit Brevo, um Meeting-Teilnehmende und Webinar-Attendees automatisch als Kontakte zu synchronisieren, Post-Meeting-Follow-up-Sequenzen auszulösen und Engagement-Metriken für deine Marketing-Automationen zu tracken.
Überblick
| Eigenschaft | Wert |
|---|---|
| Plattform | Zoom |
| Kategorie | Video Conferencing (Custom) |
| Einrichtungsaufwand | Mittel |
| Offizielle Integration | Nein |
| Synchronisierte Daten | Teilnehmende, Events, Webinare, Kontakte |
| Authentifizierung | OAuth 2.0 / Server-to-Server OAuth |
Funktionen
- Teilnehmer:innen-Synchronisation - Erstelle Brevo-Kontakte automatisch aus Meeting-Teilnehmenden
- Webinar-Attendee-Erfassung - Synchronisiere Webinar-Registrant:innen und -Attendees
- Meeting-Event-Trigger - Löse Automationen bei Meeting-Start, -Ende und Recording-Events aus
- Engagement-Tracking - Tracke Teilnahmedauer und Participation-Metriken
- Webinar-Follow-up - Löse gezielte E-Mail-Sequenzen basierend auf Webinar-Teilnahme aus
- Recording-Benachrichtigungen - Verschicke Aufzeichnungs-Links über Brevo-E-Mail-Kampagnen
Voraussetzungen
Bevor du beginnst, stelle sicher, dass du Folgendes hast:
- Ein Zoom-Konto (Pro-Plan oder höher)
- Eine Zoom Server-to-Server OAuth App oder OAuth App über den Zoom App Marketplace
- Ein Brevo-Konto mit API-Zugriff
- Ein Tajo-Konto mit Connector-Berechtigungen
Authentifizierung
Server-to-Server OAuth (empfohlen)
# Create a Server-to-Server OAuth app at marketplace.zoom.usexport ZOOM_ACCOUNT_ID=your_account_idexport ZOOM_CLIENT_ID=your_client_idexport ZOOM_CLIENT_SECRET=your_client_secret// Get access token via Server-to-Server OAuthconst tokenResponse = await fetch('https://zoom.us/oauth/token', { method: 'POST', headers: { 'Authorization': `Basic ${Buffer.from( `${process.env.ZOOM_CLIENT_ID}:${process.env.ZOOM_CLIENT_SECRET}` ).toString('base64')}`, 'Content-Type': 'application/x-www-form-urlencoded' }, body: new URLSearchParams({ grant_type: 'account_credentials', account_id: process.env.ZOOM_ACCOUNT_ID })});
const { access_token } = await tokenResponse.json();OAuth 2.0 (User-Level)
// Authorization URL for user-level OAuthconst authUrl = 'https://zoom.us/oauth/authorize?' + new URLSearchParams({ client_id: process.env.ZOOM_CLIENT_ID, redirect_uri: 'https://your-app.com/callback', response_type: 'code' });
// Exchange code for tokensconst tokenResponse = await fetch('https://zoom.us/oauth/token', { method: 'POST', headers: { 'Authorization': `Basic ${Buffer.from( `${process.env.ZOOM_CLIENT_ID}:${process.env.ZOOM_CLIENT_SECRET}` ).toString('base64')}`, 'Content-Type': 'application/x-www-form-urlencoded' }, body: new URLSearchParams({ grant_type: 'authorization_code', code: authorizationCode, redirect_uri: 'https://your-app.com/callback' })});Konfiguration
Grundeinrichtung
connectors: zoom: enabled: true account_id: "${ZOOM_ACCOUNT_ID}" client_id: "${ZOOM_CLIENT_ID}" client_secret: "${ZOOM_CLIENT_SECRET}"
sync: participants: true webinars: true recordings: true
webhook: secret_token: "${ZOOM_WEBHOOK_SECRET}" verification_token: "${ZOOM_VERIFICATION_TOKEN}"
lists: meeting_participants: 15 webinar_attendees: 16 webinar_registrants: 17Feld-Mapping
field_mapping: email: email name: FIRSTNAME join_time: MEETING_JOIN_DATE duration: MEETING_DURATION webinar_title: WEBINAR_NAME attendance_status: ATTENDANCE_STATUS registration_source: UTM_SOURCEAPI-Endpoints
| Endpoint | Methode | Beschreibung |
|---|---|---|
https://api.zoom.us/v2/users | GET | Nutzer:innen auflisten |
https://api.zoom.us/v2/users/{userId}/meetings | GET | Meetings auflisten |
https://api.zoom.us/v2/meetings/{meetingId} | GET | Meeting-Details abrufen |
https://api.zoom.us/v2/past_meetings/{meetingId}/participants | GET | Teilnehmende vergangener Meetings auflisten |
https://api.zoom.us/v2/users/{userId}/webinars | GET | Webinare auflisten |
https://api.zoom.us/v2/webinars/{webinarId}/registrants | GET | Webinar-Registrant:innen auflisten |
https://api.zoom.us/v2/webinars/{webinarId}/participants | GET | Webinar-Teilnehmende auflisten |
https://api.zoom.us/v2/meetings/{meetingId}/recordings | GET | Meeting-Aufzeichnungen abrufen |
https://api.zoom.us/v2/webhooks | POST | Webhooks abonnieren |
Code-Beispiele
Connector initialisieren
import { TajoClient } from '@tajo/sdk';
const tajo = new TajoClient({ apiKey: process.env.TAJO_API_KEY, brevoApiKey: process.env.BREVO_API_KEY});
await tajo.connectors.connect('zoom', { accountId: process.env.ZOOM_ACCOUNT_ID, clientId: process.env.ZOOM_CLIENT_ID, clientSecret: process.env.ZOOM_CLIENT_SECRET});Meeting-Teilnehmende synchronisieren
// Retrieve past meeting participantsconst response = await fetch( `https://api.zoom.us/v2/past_meetings/${meetingId}/participants`, { headers: { 'Authorization': `Bearer ${accessToken}`, 'Content-Type': 'application/json' } });
const { participants } = await response.json();
for (const participant of participants) { if (participant.user_email) { await tajo.contacts.sync({ email: participant.user_email, attributes: { FIRSTNAME: participant.name, MEETING_DURATION: participant.duration, MEETING_JOIN_DATE: participant.join_time, ATTENDANCE_STATUS: 'attended' }, listIds: [15] }); }}Webinar-Attendees synchronisieren
// Get webinar attendees and sync to Brevoconst attendeesResponse = await fetch( `https://api.zoom.us/v2/past_webinars/${webinarId}/participants`, { headers: { 'Authorization': `Bearer ${accessToken}` } });
const { participants: attendees } = await attendeesResponse.json();
for (const attendee of attendees) { await tajo.contacts.sync({ email: attendee.user_email, attributes: { FIRSTNAME: attendee.name, WEBINAR_NAME: webinarTitle, ATTENDANCE_STATUS: 'attended', MEETING_DURATION: attendee.duration }, listIds: [16] });}Zoom-Webhooks verarbeiten
app.post('/webhooks/zoom', async (req, res) => { // Handle Zoom URL validation challenge if (req.body.event === 'endpoint.url_validation') { const hashForValidation = crypto .createHmac('sha256', process.env.ZOOM_WEBHOOK_SECRET) .update(req.body.payload.plainToken) .digest('hex');
return res.json({ plainToken: req.body.payload.plainToken, encryptedToken: hashForValidation }); }
// Verify webhook signature const message = `v0:${req.headers['x-zm-request-timestamp']}:${JSON.stringify(req.body)}`; const hash = crypto .createHmac('sha256', process.env.ZOOM_WEBHOOK_SECRET) .update(message) .digest('hex'); const signature = `v0=${hash}`;
if (req.headers['x-zm-signature'] !== signature) { return res.status(401).send('Unauthorized'); }
const { event, payload } = req.body;
await tajo.connectors.handleWebhook('zoom', { topic: event, payload: payload });
res.status(200).send('OK');});Rate Limits
| Kategorie | Limit | Hinweise |
|---|---|---|
| Light-API-Aufrufe | 30 Anfr./Sek. | GET User, Meeting-Infos |
| Medium-API-Aufrufe | 20 Anfr./Sek. | Teilnehmende, Webinare auflisten |
| Heavy-API-Aufrufe | 10 Anfr./Sek. | Reports, Aufzeichnungen |
| Tageslimit | 5.000+ | Abhängig vom Tariflevel |
Rate-Limit-Header
Zoom liefert die Header X-RateLimit-Limit, X-RateLimit-Remaining und Retry-After. Implementiere Backoff-Logik basierend auf diesen Headern, um 429-Fehler zu vermeiden.
Fehlerbehebung
| Problem | Ursache | Lösung |
|---|---|---|
| 401 Unauthorized | Token abgelaufen | Server-to-Server OAuth-Token erneuern |
| Fehlende Teilnehmende | Meeting noch nicht beendet | Auf vollständige Daten nach Meeting-Ende warten |
| Webhook-Validierung schlägt fehl | Falsches Secret | Webhook-Secret im Zoom Marketplace prüfen |
| Keine E-Mail-Daten | Gast-Teilnehmende | Registrierung aktivieren, um E-Mails zu erfassen |
| Rate Limit 429 | Zu viele Anfragen | Exponential Backoff implementieren |
Debug-Modus
connectors: zoom: debug: true log_level: verbose log_webhooks: trueBest Practices
- Server-to-Server OAuth nutzen - Einfachere Authentifizierung ohne Nutzer:innen-Interaktion
- Webinar-Registrierung aktivieren - Erforderlich, um E-Mail-Adressen der Attendees zu erfassen
- Nach Meeting-Ende verarbeiten - Teilnehmende-Daten sind erst nach Meeting-Ende vollständig
- Nach Event-Typ segmentieren - Weise unterschiedliche Brevo-Listen für Meetings vs. Webinare zu
- Engagement-Metriken tracken - Nutze Dauer und Join-Zeit fürs Lead Scoring
- Recording-Follow-ups senden - Automatisiere die Zustellung von Aufzeichnungs-Links über Brevo
Sicherheit
- OAuth 2.0 - Server-to-Server- oder User-Level-OAuth-Authentifizierung
- Webhook-Verifizierung - HMAC-SHA256-Signatur-Validierung
- URL-Validierung - Challenge-Response-Verifizierung für Webhook-Endpoints
- Gescopte Berechtigungen - Fordere minimal erforderliche OAuth-Scopes an
- Token-Rotation - Server-to-Server-Tokens laufen automatisch ab (1 Stunde)
- Verschlüsselter Transport - TLS 1.2+ für alle API-Kommunikationen