{"id":164,"date":"2020-05-25T23:29:20","date_gmt":"2020-05-25T23:29:20","guid":{"rendered":"http:\/\/duff.io\/?p=164"},"modified":"2022-01-05T17:04:28","modified_gmt":"2022-01-05T17:04:28","slug":"using-the-zoom-api-to-deal-with-webinar-panelists","status":"publish","type":"post","link":"https:\/\/duff.io\/?p=164","title":{"rendered":"Using the Zoom API to deal with webinar panelists"},"content":{"rendered":"\n<p>In response to the pandemic my school is using Zoom Webinars for various performances. Our student Improv group has done a number of performances. The cast all need to be &#8220;panelists&#8221; in Zoom parlance, and when you duplicate a Webinar it does not duplicate the panelists. That&#8217;s a pain since there are a lot of panelists, and for each you need a name and e-mail address.<\/p>\n\n\n\n<p>I finally got tired of dealing with it and spent a few minutes figuring out the Zoom API. If I ever have a little more time, I&#8217;ll make a Google Apps Manager (GAM) knock off that I&#8217;ll call ZAM! In the meantime, perhaps someone else will find this helpful.<\/p>\n\n\n\n<p>First, Zoom has <a href=\"https:\/\/marketplace.zoom.us\/docs\/api-reference\/zoom-api\">good documentation of its API<\/a>. To start, you will need to <a href=\"https:\/\/marketplace.zoom.us\/docs\/guides\/build\">build an app to get credentials<\/a>. For my scripts, I&#8217;m using JSON Web Tokens (JWT) for authentication. I found <a href=\"https:\/\/devforum.zoom.us\/t\/jwt-documentation\/3881\/11\">this post<\/a> in the Zoom Dev Forums helpful as a starting point. <\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Get information on a Zoom user<\/h4>\n\n\n\n<p>Here is a short Python script to get information on a user to give a little idea on how to use the API.<\/p>\n\n\n\n<pre class=\"wp-block-syntaxhighlighter-code\">import jwt   # pip3 install pyjwt --user\nimport http.client\nimport datetime\nimport json\nimport sys\n \napi_key = '********' # replace with credentials from\napi_sec = '********' # your app in Zoom Marketplace\n \n# generate JWT\npayload = {\n'iss': api_key,\n'exp': datetime.datetime.utcnow() + datetime.timedelta(hours=2)\n}\n \njwt_encoded = str(jwt.encode(payload, api_sec), 'utf-8')\n \n \n# call API: get user list\nconn = http.client.HTTPSConnection(\"api.zoom.us\")\nheaders = {\n'authorization': \"Bearer %s\" % jwt_encoded,\n'content-type': \"application\/json\"\n}\nemail = str(sys.argv[1])\nconn.request(\"GET\", \"\/v2\/users\/\" +  email, headers=headers)\nres = conn.getresponse()\nresponse_string = res.read().decode('utf-8')\n \nuser_json = json.loads(response_string)\njson_formatted_str = json.dumps(user_json, indent=2)\nprint(json_formatted_str)<\/pre>\n\n\n\n<p>You can use this like this:<\/p>\n\n\n\n<pre class=\"wp-block-syntaxhighlighter-code\"># python3.7 zoom-user.py user@domain.com\n\n{\n  \"id\": \"xxxxxxxxxxx\",\n  \"first_name\": \"John\",\n  \"last_name\": \"Smith\",\n  \"email\": \"user@domain.com\",\n  \"type\": 2,\n  \"role_name\": \"Admin\",\n  \"pmi\": 111111111,\n  \"use_pmi\": false,\n  \"personal_meeting_url\": \"https:\/\/myschool.zoom.us\/j\/111111111?pwd=UmVTASDFc3pXUTNpOFZNb34A09\",\n  \"timezone\": \"America\/Chicago\",\n  \"verified\": 0,\n  \"dept\": \"\",\n  \"created_at\": \"2020-04-13T02:42:31Z\",\n  \"last_login_time\": \"2020-05-22T19:38:06Z\",\n  \"last_client_version\": \"4.6.20561.0413(mac)\",\n  \"pic_url\": \"https:\/\/lh3.googleusercontent.com\/a-\/AOh14GgQadfagrA8l4U9fhsbZ1hOTMSvDxE3gGQ\",\n  \"host_key\": \"111861\",\n  \"jid\": \"3timqwabrvs00ayurhg_ha@xmpp.zoom.us\",\n  \"group_ids\": [\n    \"qCpDwoo5T1qS4cn8RSy8rQ\"\n  ],\n  \"im_group_ids\": [],\n  \"account_id\": \"fhsbZ1cOTMSvDxE3g\",\n  \"language\": \"en-US\",\n  \"phone_country\": \"\",\n  \"phone_number\": \"\",\n  \"status\": \"active\",\n  \"job_title\": \"\",\n  \"location\": \"\"\n}<\/pre>\n\n\n\n<p>Note: I&#8217;ve redacted\/change all of the ID and info above for obvious reasons.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Getting a list of all webinars panelists<\/h4>\n\n\n\n<p>This Python script lists all of the panelist names and email addresses.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted brush:python\">import jwt &nbsp; # pip3 install pyjwt --user\nimport http.client\nimport datetime\nimport json\nimport sys\n\napi_key = '********' # replace with credentials from\napi_sec = '********' # your app in Zoom Marketplace\n\n# generate JWT\npayload = {\n'iss': api_key,\n'exp': datetime.datetime.utcnow() + datetime.timedelta(hours=2)\n}\n\njwt_encoded = str(jwt.encode(payload, api_sec), 'utf-8')\n\n# call API: get webinar panelists\nconn = http.client.HTTPSConnection(\"api.zoom.us\")\nheaders = {\n'authorization': \"Bearer %s\" % jwt_encoded,\n'content-type': \"application\/json\"\n}\nwebinarid = str(sys.argv[1])\nconn.request(\"GET\", \"\/v2\/webinars\/\" + webinarid + \"\/panelists\", headers=headers)\nres = conn.getresponse()\nresponse_string = res.read().decode('utf-8')\nresponse_json = json.loads(response_string)\n\nfor panelist in response_json[\"panelists\"]:\n&nbsp; &nbsp; print(panelist[\"name\"],&nbsp; panelist[\"email\"])<\/pre>\n\n\n\n<p>Here is an example of the script in action listing panelists for webinar id 91119118113:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"># python3.7 zoom-webinar-panelists.py 91119118113\nJohn Smith jsmith@domain.com\nJane Smith jane.smith@anotherdomain.com<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Adding Panelists to a Webinar<\/h4>\n\n\n\n<p>Next is a Python script to add a panelist to a webinar. It takes the webinar ID, panelist name and email address as parameters.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted brush:python\">import jwt &nbsp; # pip3 install pyjwt --user\nimport http.client\nimport datetime\nimport json\nimport sys\n\napi_key = '********' # replace with credentials from\napi_sec = '********' # your app in Zoom Marketplace\n\n# generate JWT\npayload = {\n'iss': api_key,\n'exp': datetime.datetime.utcnow() + datetime.timedelta(hours=2)\n}\n\njwt_encoded = str(jwt.encode(payload, api_sec), 'utf-8')\n\n# call API: add panelist\nconn = http.client.HTTPSConnection(\"api.zoom.us\")\nheaders = {\n'authorization': \"Bearer %s\" % jwt_encoded,\n'content-type': \"application\/json\"\n}\n\nnum_arguments = len(sys.argv)-1\nwebinar = str(sys.argv[1])\nemail = sys.argv[num_arguments]\nname = \"\"\ni = 2\nwhile i &lt; num_arguments:\n&nbsp; &nbsp; name = name + sys.argv[i] + \" \"\n&nbsp; &nbsp; i = i+1\nname = name.rstrip()\nprint(name, email,webinar)\nbody = \"{\\\"panelists\\\":[{\\\"name\\\":\\\"\" + name + \"\\\",\\\"email\\\":\\\"\" + email + \"\\\"}]}\"\n\nwebinar = str(sys.argv[1])\nconn.request(\"POST\", \"\/v2\/webinars\/\" + webinar + \"\/panelists\", body, headers=headers)\nres = conn.getresponse()\nresponse_string = res.read().decode('utf-8')<\/pre>\n\n\n\n<p>Here is an exampling of using the script to add &#8220;John Q. Public&#8221; john.q.public@domain.com to webinar id 91119118113:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">python3.7 zoom-webinar-panelists-add.py 91119118113 John Q. Public john.q.public@domain.com\n\n{\"id\":\"91119118113\",\"updated_at\":\"2020-05-25T23:25:22Z\"}<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Closing Thoughts<\/h4>\n\n\n\n<p>Using these ideas in these two scripts, I can easily copy panelists from one webinar to another. Hopefully this is enough to get you started using the Zoom API. As I mentioned at the start, I think it would be awesome to have a tool like GAM but for Zoom. I&#8217;d much rather manage Zoom from the command line. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>In response to the pandemic my school is using Zoom Webinars for various performances. Our student Improv group has done a number of performances. The cast all need to be &#8220;panelists&#8221; in Zoom parlance, and when you duplicate a Webinar it does not duplicate the panelists. That&#8217;s a pain since there are a lot of [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[18,11],"tags":[],"class_list":["post-164","post","type-post","status-publish","format-standard","hentry","category-python","category-zoom"],"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/duff.io\/index.php?rest_route=\/wp\/v2\/posts\/164","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/duff.io\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/duff.io\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/duff.io\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/duff.io\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=164"}],"version-history":[{"count":2,"href":"https:\/\/duff.io\/index.php?rest_route=\/wp\/v2\/posts\/164\/revisions"}],"predecessor-version":[{"id":173,"href":"https:\/\/duff.io\/index.php?rest_route=\/wp\/v2\/posts\/164\/revisions\/173"}],"wp:attachment":[{"href":"https:\/\/duff.io\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=164"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/duff.io\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=164"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/duff.io\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=164"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}