לאחר ששילבנו סמינרים מקוונים ב-LMS עם 2000 סטודנטים: המורה יצר פגישות ידנית, שכח להפעיל הקלטה, ונאלץ לבדוק נוכחות באמצעות צילומי מסך. לאחר אוטומציה באמצעות API, עלויות הניהול ירדו ב-8 שעות בשבוע. גישה זו לא רק חוסכת זמן אלא גם מבטלת טעויות אנוש — הסטודנטים מקבלים קישורים בזמן, ההקלטות זמינות מיד לאחר הסמינר, ויומן הנוכחות מתמלא אוטומטית.
כיצד לבחור פלטפורמת וידאו ל-LMS?
| פלטפורמה | API | אירוח עצמי | הקלטה | נוכחות | תכונות |
|---|---|---|---|---|---|
| Zoom | REST API, Webhooks | לא | ענן | באמצעות webhook | סטנדרטי, API רחב, הקלטה טובה |
| BigBlueButton | REST API (checksum) | כן | כן | יומנים מפורטים | מיועד לחינוך, לוח לבן, חדרי breakout |
| Jitsi Meet | REST API (Jibri) | כן | כן | באמצעות webhook | חינמי, שליטה מלאה |
| Daily.co | REST API + SDK | לא | לא | מובנה | שיחת וידאו הניתנת להטמעה ישירות ב-LMS |
| Whereby | REST API | לא | לא | לא | הטמעה פשוטה, iframe |
BigBlueButton — מומלץ ל-LMS חינוכי: לוח לבן מובנה, סקרים, חדרי breakout, הקלטה עם חלוקת משתתפים. אירוח עצמי. Zoom — אם הלקוחות כבר משתמשים בו ולא רוצים לשנות הרגלים. Daily.co — אם צריך להטמיע וידאו ישירות בממשק ה-LMS ללא ניווט לאתר חיצוני.
כיצד לאוטומט יצירת סמינרים מקוונים?
אינטגרציה עם Zoom API היא אחת הדרכים הפשוטות ביותר. להלן דוגמה למחלקת JavaScript שיוצרת פגישה עם הגדרות הקלטה אוטומטית וחדר המתנה.
class ZoomIntegration { constructor(accountId, clientId, clientSecret) { this.tokenUrl = 'https://zoom.us/oauth/token'; this.apiUrl = 'https://api.zoom.us/v2'; this.credentials = { accountId, clientId, clientSecret }; } async getAccessToken() { const response = await fetch(this.tokenUrl, { method: 'POST', headers: { 'Authorization': `Basic ${Buffer.from(`${this.credentials.clientId}:${this.credentials.clientSecret}`).toString('base64')}`, 'Content-Type': 'application/x-www-form-urlencoded', }, body: `grant_type=account_credentials&account_id=${this.credentials.accountId}`, }); const data = await response.json(); return data.access_token; } async createMeeting({ topic, startTime, durationMin, agenda, hostEmail }) { const token = await this.getAccessToken(); const response = await fetch(`${this.apiUrl}/users/${hostEmail}/meetings`, { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ topic, type: 2, start_time: startTime.toISOString(), duration: durationMin, agenda, settings: { host_video: true, participant_video: false, waiting_room: true, auto_recording: 'cloud', mute_upon_entry: true, approval_type: 0, }, }), }); return response.json(); } } עבור BigBlueButton הגישה שונה — היא משתמשת בבקשות חתומות עם checksum. דוגמה ב-PHP:
class BigBlueButtonService { private string $url; private string $secret; public function createMeeting(string $meetingId, string $name, array $options = []): array { $params = array_merge([ 'meetingID' => $meetingId, 'name' => $name, 'record' => 'true', 'autoStartRecording' => 'false', 'allowStartStopRecording' => 'true', 'webcamsOnlyForModerator' => 'false', 'lockSettingsDisableMic' => 'false', ], $options); $queryString = http_build_query($params); $checksum = sha1('create' . $queryString . $this->secret); $params['checksum'] = $checksum; $response = Http::get("{$this->url}/api/create", $params); return $response->json(); } public function getJoinUrl(string $meetingId, string $fullName, string $role, string $userId): string { $password = $role === 'moderator' ? $this->moderatorPw : $this->attendeePw; $params = "meetingID={$meetingId}&fullName=" . urlencode($fullName) . "&password={$password}&userID={$userId}"; $checksum = sha1('join' . $params . $this->secret); return "{$this->url}/api/join?{$params}&checksum={$checksum}"; } } מה מספק מעקב נוכחות באמצעות Webhooks?
מעקב אוטומטי באמצעות webhooks פותר את בעיית זיוף הנוכחות. Zoom Webhooks שולחים אירועי class ZoomIntegration { constructor(accountId, clientId, clientSecret) { this.tokenUrl = 'https://zoom.us/oauth/token'; this.apiUrl = 'https://api.zoom.us/v2'; this.credentials = { accountId, clientId, clientSecret }; } async getAccessToken() { const response = await fetch(this.tokenUrl, { method: 'POST', headers: { 'Authorization': `Basic ${Buffer.from(`${this.credentials.clientId}:${this.credentials.clientSecret}`).toString('base64')}`, 'Content-Type': 'application/x-www-form-urlencoded', }, body: `grant_type=account_credentials&account_id=${this.credentials.accountId}`, }); const data = await response.json(); return data.access_token; } async createMeeting({ topic, startTime, durationMin, agenda, hostEmail }) { const token = await this.getAccessToken(); const response = await fetch(`${this.apiUrl}/users/${hostEmail}/meetings`, { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ topic, type: 2, start_time: startTime.toISOString(), duration: durationMin, agenda, settings: { host_video: true, participant_video: false, waiting_room: true, auto_recording: 'cloud', mute_upon_entry: true, approval_type: 0, }, }), }); return response.json(); } } ו-class BigBlueButtonService { private string $url; private string $secret; public function createMeeting(string $meetingId, string $name, array $options = []): array { $params = array_merge([ 'meetingID' => $meetingId, 'name' => $name, 'record' => 'true', 'autoStartRecording' => 'false', 'allowStartStopRecording' => 'true', 'webcamsOnlyForModerator' => 'false', 'lockSettingsDisableMic' => 'false', ], $options); $queryString = http_build_query($params); $checksum = sha1('create' . $queryString . $this->secret); $params['checksum'] = $checksum; $response = Http::get("{$this->url}/api/create", $params); return $response->json(); } public function getJoinUrl(string $meetingId, string $fullName, string $role, string $userId): string { $password = $role === 'moderator' ? $this->moderatorPw : $this->attendeePw; $params = "meetingID={$meetingId}&fullName=" . urlencode($fullName) . "&password={$password}&userID={$userId}"; $checksum = sha1('join' . $params . $this->secret); return "{$this->url}/api/join?{$params}&checksum={$checksum}"; } } . BigBlueButton מספק יומנים מפורטים באמצעות Recording API. אנו שומרים את זמן הכניסה והיציאה של כל סטודנט, מחשבים את משך הנוכחות, ומייצרים דוח.
app.post('/webhooks/zoom', async (req, res) => { const { event, payload } = req.body; if (event === 'meeting.participant_joined') { await db.webinarAttendance.upsert({ webinarId: payload.object.id, userId: await findUserByEmail(payload.object.participant.email), joinedAt: new Date(payload.object.participant.join_time), }); } if (event === 'meeting.participant_left') { await db.webinarAttendance.update({ webinarId: payload.object.id, userId: await findUserByEmail(payload.object.participant.email), }, { leftAt: new Date(payload.object.participant.leave_time), durationMin: payload.object.participant.duration, }); } res.status(200).json({ status: 'ok' }); }); הקלטות סמינרים מקוונים
לאחר סיום הסמינר, Zoom/BBB מייצרים הקלטה. תהליך:
- Webhook
meeting.participant_joined→ קבלת קישור הורדה - הורדה והעלאה ל-S3 (Zoom שומר הקלטות לזמן מוגבל)
- יצירת שיעור וידאו ב-LMS עם קישור ההקלטה
- הודעה לסטודנטים שהחמיצו את הסמינר
async function processWebinarRecording(meetingId, downloadUrl, token) { const s3Key = `recordings/${meetingId}.mp4`; const response = await fetch(downloadUrl, { headers: { Authorization: `Bearer ${token}` } }); await s3.upload({ Bucket: process.env.S3_BUCKET, Key: s3Key, Body: response.body }).promise(); const videoUrl = `https://${process.env.CDN_DOMAIN}/${s3Key}`; await db.webinars.update({ meetingId }, { recordingUrl: videoUrl }); await notifyAbsentStudents(meetingId, videoUrl); } שיחת וידאו מוטמעת באמצעות Daily.co
אם צריך להטמיע וידאו ישירות ב-LMS ללא ניווט לדף חיצוני:
import DailyIframe from '@daily-co/daily-js'; function WebinarRoom({ roomUrl, token }) { const callFrame = useRef(null); useEffect(() => { callFrame.current = DailyIframe.createFrame({ url: roomUrl, token, iframeStyle: { width: '100%', height: '600px' }, }); callFrame.current.on('participant-counts-updated', ({ present }) => { trackAttendance(present); }); callFrame.current.join(); return () => callFrame.current.destroy(); }, [roomUrl]); return <div id="daily-container" />; } תרחישי שימוש: השוואת פלטפורמות
| תרחיש | פלטפורמה מומלצת | סיבה |
|---|---|---|
| קורס עם 50+ סטודנטים, צורך בלוח לבן וסקרים | BigBlueButton | מיועד לחינוך, אירוח עצמי, סטטיסטיקות מפורטות |
| הדרכה ארגונית, כבר משתמשים ב-Zoom | Zoom | אין צורך בהגירה, API סטנדרטי |
| הטמעת וידאו ישירות בממשק | Daily.co | SDK קל משקל, ללא ניווט לאתר חיצוני |
טעויות אינטגרציה נפוצות
הרחבת רשימה
- Webhooks לא מוגדרים — הפגישה נוצרת אך אירועים לא מתקבלים.
- חוסר טיפול בניסיונות חוזרים בשגיאות API (rate limit).
- אזור זמן לא נלקח בחשבון בעת תזמון פגישות.
- הקלטה לא מועלית אם webhook של
meeting.participant_leftלא מעובד. - סיסמאות מנחה ומשתתף מוחלפות ב-BigBlueButton.
מה כלול בעבודה
- אינטגרציית API של הפלטפורמה הנבחרת (Zoom/BBB/Jitsi).
- יצירת סמינרים מקוונים אוטומטית לפי לוח זמנים.
- שליחת קישורים לסטודנטים (אימייל/התראות).
- הקלטת סמינר והעלאה ל-S3/CDN.
- מעקב נוכחות עם דוחות.
- תיעוד API והוראות למנהלים.
- חודש תמיכה טכנית.
תהליך עבודה
- ניתוח דרישות: בחירת פלטפורמה, הגדרת API, הסכמה על תוכנית זרימת נתונים.
- עיצוב: עיצוב מטפלי webhook, סכמות אחסון להקלטות ונוכחות.
- יישום: אינטגרציה דרך API, קוד, כתיבת בדיקות.
- בדיקות: אימות יצירת פגישות, webhooks, הקלטה, נוכחות.
- פריסה והדרכה: פריסה על השרת, מתן הוראות למנהלים.
לוחות זמנים משוערים
אינטגרציית Zoom API: יצירת פגישות, שליחת קישורים לסטודנטים, נוכחות בסיסית — 4–5 ימים. הקלטת סמינר עם העלאה ל-S3 והתראות — 2–3 ימים. BigBlueButton באירוח עצמי עם אינטגרציה מלאה והטמעה ב-LMS — 7–10 ימים. וידאו מוטמע של Daily.co — 3–4 ימים.
ניסיון ואחריות
ביצענו מעל 30 אינטגרציות עם Zoom, BigBlueButton ו-Jitsi עבור LMS על Laravel, Node.js ו-Python. המהנדסים שלנו מוסמכים ב-Zoom API. אנו מבטיחים תאימות לכל LMS מודרני ומספקים חודש תמיכה לאחר הפריסה.
להערכת זמן ועלות מדויקת, צרו קשר — נבחר את הפלטפורמה האופטימלית למשימות שלכם.
ראו תיעוד רשמי: Zoom REST API, BigBlueButton API.







