Call out functionality in the UI Toolkit

Hi,

I’m using the UI Toolkit to add the Zoom functionality in my app and that is working fine. I purchased the Audio conference subscription last week to be able to invite third parties by phone number.

In the release notes I see that the PSTN call out functionality is added but I cannot find any documentation how to add this to my configuration.

Hopefully someone can point me in the right direction because this is a crucial functionality in the workflow of my app.

Kind Regards,

Ferdi

Hi @idref10, which release notes are you referring to?

Hi,

For example:

I see, we’re working on adding UI for using PSTN within the UITookit on Web. In the meantime you can use the REST API for this:

const callInPtsn = () => {
        return fetch('https://api.zoom.us/v2/videosdk/sessions/{SESSIONID}/events', {
      method: 'PATCH',
      headers: {
        'Content-Type': 'application/json',
        "Authorization": "Bearer {VSDK_JWT}"
      },
  body: JSON.stringify({
    "method": "user.invite.callout",
    "params":{
        "invitee_name":"Your Name",
        "phone_number":"1234567890"
    }
}),
}).then(response => response.json())
  .then(data => console.log(data))
}

You can access the SESSIONID in the UI or use the webhook/REST API to get it:

Okay great, for now I’m going to use the REST API and in the meantime I’m waiting for an update according the UIToolkit.

Thanks for your response.

Kind Regards,

Ferdi

const {onCall, HttpsError} = require("firebase-functions/v2/https");
const {defineSecret} = require("firebase-functions/params");
const jwt = require("jsonwebtoken");

// Define Zoom Secrets
const zoomApiKey = defineSecret("ZOOM_SDK_KEY");
const zoomApiSecret = defineSecret("ZOOM_SDK_SECRET");

/**
 * Function to generate Zoom JWT Token
 */
exports.generateZoomToken = onCall(
    {secrets: [zoomApiKey, zoomApiSecret]},
    async (req, context) => {
      const {tpc, roleType} = req.data; // No spaces after '{' and before '}'

      // Validate inputs
      if (!tpc) {
        throw new HttpsError("invalid-argument", "Topic is required.");
      }

      // Define payload for JWT
      const payload = {
        app_key: zoomApiKey.value(),
        tpc: tpc, // Session Name
        version: 1,
        role_type: roleType || 0,
        iat: Math.floor(Date.now() / 1000) - 30,
        exp: Math.floor(Date.now() / 1000) + 60 * 60 * 2,
      };

      // Generate JWT Token
      const token = jwt.sign(payload, zoomApiSecret.value());

      return {token}; // Added trailing comma as needed
    },
);

exports.inviteByPhone = onCall(
    {secrets: [zoomApiKey, zoomApiSecret]},
    async (req, context) => {
      const {sessionId, inviteeName, phoneNumber} = req.data;

      // Validate inputs
      if (!sessionId || !inviteeName || !phoneNumber) {
        throw new HttpsError("invalid-argument", "Need args.");
      }

      try {
        // Generate JWT Token
        const payload = {
          app_key: zoomApiKey.value(),
          tpc: sessionId, // Assuming 'tpc' is used as session name
          version: 1,
          role_type: 0,
          iat: Math.floor(Date.now() / 1000) - 30,
          exp: Math.floor(Date.now() / 1000) + 60 * 60 * 2,
        };

        const token = jwt.sign(payload, zoomApiSecret.value());

        console.log("sessionId:::::", sessionId);
        console.log("TOKEN:::::", token);

        // Prepare the API endpoint
        const url = `https://api.zoom.us/v2/videosdk/sessions/${sessionId}/events`;

        // Make the API request to invite by phone
        const response = await fetch(url, {
          method: "PATCH",
          headers: {
            "Content-Type": "application/json",
            "Authorization": `Bearer ${token}`,
          },
          body: JSON.stringify({
            method: "user.invite.callout",
            params: {
              invitee_name: inviteeName,
              phone_number: phoneNumber,
            },
          }),
        });

        const data = await response.json();

        if (!response.ok) {
          console.error("Zoom API Error:", data);
          throw new HttpsError("internal",
              data.message || "Failed to invite by phone.");
        }

        return {success: true, data};
      } catch (error) {
        console.error("Error inviting by phone:", error);
        throw new HttpsError("internal",
            error.message || "An error occurred while inviting by phone.");
      }
    },
);

I have these 2 functions.

GenerateZoomToken i use to create the token to initiate the call which is working fine.

When I try to call the rest API I get the message Error inviting by phone: HttpsError: Invalid access token.

What Am I missing here?

Sorry for my questions but I found out that I was mixing up the different API keys with the SDK keys so I have the token creation working.

The only thing that I cannot fix is how to retrieve the Session Id with the UI Toolkit. I need this to call the endpoint and in my previous example I was using the session name which are obvious different.

The event listeners don’t give me the Session Id so I’,m wondering where I can find this.

Small update

I changed my workflow and I now first create the session with the API so I have the session ID. That works fine but now when i call the API for the events I get a response 400 bad request.

This is my API call

const url = `https://api.zoom.us/v2/videosdk/sessions/${sessionId}/events`;

        // Make the API request to invite by phone
        const response = await fetch(url, {
          method: "PATCH",
          headers: {
            "Content-Type": "application/json",
            "Authorization": `Bearer ${token}`,
          },
          body: JSON.stringify({
            method: "user.invite.callout",
            params: {
              invitee_name: inviteeName,
              phone_number: phoneNumber,
            },
          }),
        });

Another small update

I was using the phonenumber with a + instead of double zero and now it is working!