Meeting SDK Type and Version
“@zoomus/websdk”: “^2.17.0”
Meeting SDK Component View
Description
I’m trying to integrate SDK into my app (react on frontend, nestJS on backend).
Generating signature
generateSignature(meetingNumber: string, role: number): string {
const iat = Math.round(new Date().getTime() / 1000) - 30;
const exp = iat + 60 * 60 * 2;
const oHeader = { alg: 'HS256', typ: 'JWT' };
const oPayload = {
appKey: this.configService.get('ZOOM_MEETING_SDK_KEY'),
sdkKey: this.configService.get('ZOOM_MEETING_SDK_KEY'),
mn: meetingNumber,
role,
iat,
exp,
tokenExp: iat + 60 * 60 * 2,
};
const sHeader = JSON.stringify(oHeader);
const sPayload = JSON.stringify(oPayload);
const signature = KJUR.jws.JWS.sign(
'HS256',
sHeader,
sPayload,
this.configService.get('ZOOM_MEETING_SDK_SECRET'),
);
console.log(signature);
return signature;
}
Getting Oauth Token and Creating meeting:
async createMeeting(
topic: string,
): Promise<{ meetingId: string; password: string }> {
const endpoint = `${this.baseURL}/users/me/meetings`;
const token = await this.getToken();
const headers = {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
};
const startTime = new Date();
startTime.setMinutes(startTime.getMinutes() + 1);
const body = {
topic,
type: 2, // 2 for Scheduled Meeting
start_time: startTime.toISOString(),
duration: 60, // Duration in minutes
settings: {
join_before_host: true, // Enable 'Join Before Host'
waiting_room: false,
host_video: true,
participant_video: true,
},
};
try {
const response = await this.httpService
.post(endpoint, body, { headers })
.toPromise();
console.log(response.data);
return {
meetingId: response.data.id.toString(),
password: response.data.password,
};
} catch (error) {
console.log(error);
throw new Error(`Failed to create Zoom meeting: ${error.message}`);
}
}
async getToken(): Promise<any> {
const url = `https://zoom.us/oauth/token?grant_type=account_credentials&account_id=${this.configService.get(
'ZOOM_OAUTH_ACCOUNT_ID',
)}`;
const authHeader = `Basic ${Buffer.from(
`${this.configService.get(
'ZOOM_OAUTH_CLIENT_ID',
)}:${this.configService.get('ZOOM_OAUTH_CLIENT_SECRET')}`,
).toString('base64')}`;
try {
const response = await this.httpService
.post(url, null, {
headers: {
Authorization: authHeader,
'Content-Type': 'application/x-www-form-urlencoded',
},
})
.pipe(map((res) => res.data))
.toPromise();
return response.access_token;
} catch (error) {
throw new Error(`Error while fetching Zoom token: ${error.message}`);
}
}
Joining meeting with SDK:
const VideoCall = () => {
const client = ZoomMtgEmbedded.createClient();
const user = useAppSelector(getUserSelector);
const meetingNumber = '84039451194';
const passWord = 'xMFkW4';
const role = 0;
const userName = user.firstName || 'Test';
const userEmail = user.email || 'test@example.com';
const [requestSignature, { data: signatureRes }] = useGetSignatureMutation();
function startMeeting(signature: string) {
const meetingSDKElement = document.getElementById('meetingSDKElement');
const meetingSDKChatElement = document.getElementById(
'meetingSDKChatElement'
);
if (!meetingSDKElement) {
return;
}
try {
client.init({
debug: true,
zoomAppRoot: meetingSDKElement,
language: 'en-US',
customize: {
meetingInfo: [
'topic',
'host',
'mn',
'pwd',
'telPwd',
'invite',
'participant',
'dc',
'enctype',
],
video: {
popper: {
disableDraggable: true,
},
isResizable: false,
viewSizes: {
default: {
width: 1000,
height: 600,
},
ribbon: {
width: 300,
height: 700,
},
},
},
chat: {
popper: {
disableDraggable: true,
anchorElement: meetingSDKChatElement,
placement: 'top',
},
},
toolbar: {
buttons: [
{
text: 'Custom Button',
className: 'CustomButton',
onClick: () => {
console.log('custom button');
},
},
],
},
},
});
client.join({
signature,
sdkKey: process.env.NX_ZOOM_KEY,
meetingNumber,
password: passWord,
userName,
userEmail,
success: () => {
console.error('success');
},
error: () => {
console.error('error');
},
});
} catch (error) {
console.log('join', error);
}
}
const getSignature = async (e: React.MouseEvent<HTMLElement>) => {
e.preventDefault();
try {
await requestSignature({
meetingNumber,
role,
})
.unwrap()
.then((res) => {
console.log('RES', res);
startMeeting(res.signature);
})
.catch((error) => {
console.error(error);
});
} catch (error) {
console.log(error);
}
};
return (
<>
<h1>Zoom Meeting</h1>
{/* For Component View */}
<div id="meetingSDKElement">
{/* Zoom Meeting SDK Component View Rendered Here */}
</div>
<button onClick={getSignature}>Join Meeting</button>
<div id="meetingSDKChatElement"></div>
</>
);
};
type or paste code here
Error?
After I’m pressing Join meeting user connects, but app is crashing with error
{
“type”: “INVALID_PARAMETERS”,
“reason”: “userId is not correct”
}
Also, after that if I tried to press Leave Meeting and got an error
{
“type”: “IMPROPER_MEETING_STATE”,
“reason”: “closed”
}
Troubleshooting Routes
I walked through documentation again, since user is joining, I guess signature is generating fine.
Also, I did everything on sample app first, same errors.
Thinking problem is somewhere in meeting params, but can’t figure out.
I’ve got meeting details from API, if it helps:
{
"uuid": "+CDYlTo0ToCq0m5hHjhRKw==",
"id": 84039451194,
"host_id": "O9ijUpr2TB-ZX3jw3PH3mw",
"host_email": "dkononov.zp@gmail.com",
"assistant_id": "",
"topic": "hi",
"type": 2,
"status": "started",
"start_time": "2023-10-13T09:21:00Z",
"duration": 60,
"timezone": "Europe/Kiev",
"agenda": "",
"created_at": "2023-10-13T09:21:00Z",
"start_url": "https://us05web.zoom.us/s/84039451194?zak=eyJ0eXAiOiJKV1QiLCJzdiI6IjAwMDAwMSIsInptX3NrbSI6InptX28ybSIsImFsZyI6IkhTMjU2In0.eyJhdWQiOiJjbGllbnRzbSIsInVpZCI6Ik85aWpVcHIyVEItWlgzanczUEgzbXciLCJpc3MiOiJ3ZWIiLCJzayI6IjAiLCJzdHkiOjEsIndjZCI6InVzMDUiLCJjbHQiOjAsIm1udW0iOiI4NDAzOTQ1MTE5NCIsImV4cCI6MTY5NzE5NjE2NywiaWF0IjoxNjk3MTg4OTY3LCJhaWQiOiJHUWNmNHlCN1ROYWwtZ3BjTDJsYTlBIiwiY2lkIjoiIn0.ALIiTnrd56lT2A3Ua8GnqospKdHhlyIoHimUvOR0ZgE",
"join_url": "https://us05web.zoom.us/j/84039451194?pwd=zHN2y5Nk8DHtsFJPgbDkhaetLLi4JH.1",
"password": "xMFkW4",
"h323_password": "751674",
"pstn_password": "751674",
"encrypted_password": "zHN2y5Nk8DHtsFJPgbDkhaetLLi4JH.1",
"settings": {
"host_video": true,
"participant_video": true,
"cn_meeting": false,
"in_meeting": false,
"join_before_host": true,
"jbh_time": 0,
"mute_upon_entry": false,
"watermark": false,
"use_pmi": false,
"approval_type": 2,
"audio": "voip",
"auto_recording": "none",
"enforce_login": false,
"enforce_login_domains": "",
"alternative_hosts": "",
"alternative_host_update_polls": false,
"close_registration": false,
"show_share_button": false,
"allow_multiple_devices": false,
"registrants_confirmation_email": true,
"waiting_room": false,
"request_permission_to_unmute_participants": false,
"registrants_email_notification": true,
"meeting_authentication": false,
"encryption_type": "enhanced_encryption",
"approved_or_denied_countries_or_regions": {
"enable": false
},
"breakout_room": {
"enable": false
},
"internal_meeting": false,
"continuous_meeting_chat": {
"enable": false,
"auto_add_invited_external_users": false
},
"participant_focused_meeting": false,
"push_change_to_calendar": false,
"alternative_hosts_email_notification": true,
"show_join_info": false,
"device_testing": false,
"focus_mode": false,
"enable_dedicated_group_chat": false,
"private_meeting": false,
"email_notification": true,
"host_save_video_order": false,
"sign_language_interpretation": {
"enable": false
},
"email_in_attendee_report": false
},
"pre_schedule": false
}
What am I missing?