Meraki API

So Cisco/Meraki has some pretty good documentation at using the Meraki API with Python. Short version is use pip to install Meraki (pip install meraki) and then in your shell set an environmental variable called MERAKI_DASHBOARD_API_KEY to your Meraki API key (export MERAKI_DASHBOARD_API_KEY=xxxxxxx) which can be enabled and found (see https://documentation.meraki.com/zGeneral_Administration/Other_Topics/The_Cisco_Meraki_Dashboard_API). Below is a little script to grab information about the APs in your network. You’ll need to specify the network name in the Meraki Dashboard. The script assumes there is only one organization, if you have more than one, you’ll have to loop through those to find the id of your organization. The script also makes calls to getDeviceWirelessRadioSettings and getDeviceWirelessStatus which provides more information about those APs, but I don’t make any efforts to format or do anything with the results.

import meraki

dashboard = meraki.DashboardAPI()
#name of my network that has APs
ap_network_name = "xyxy"

# Get orgs linked to API key
my_orgs = dashboard.organizations.getOrganizations()
# Get networks linked to org. Assuming there is only one org (true in my case)
my_networks = dashboard.organizations.getOrganizationNetworks(organizationId=my_orgs[0]["id"])
# Find the network ID of the network with my network name
for netw in my_networks:
	if (netw["name"] == ap_network_name):
		my_netw = netw["id"]

my_devices = dashboard.networks.getNetworkDevices(networkId=my_netw)

for a_device in my_devices:
	try:
		# Filter out the devices that aren't APs
		if(a_device["firmware"][:8] == "wireless"):
			# print some basic info on the APs
			print(a_device["name"],a_device["serial"],a_device["firmware"],a_device["model"],a_device["firmware"])
			serial = a_device["serial"]
			# get some info on the radio settings for the AP
			wireless = dashboard.wireless.getDeviceWirelessRadioSettings(serial)
			print(wireless)
			# get some more detailed info on the AP
			wifi_status = dashboard.wireless.getDeviceWirelessStatus(serial)
			print(wifi_status)
	except:
		print("error for", a_device["serial"])
# print(my_devices)

Using ThankView API to download videos

At the end of last year, my school used ThankView to record surprise videos for each graduating senior. We had 2-4 teachers record a short video reflecting on their relationship with the student and wishing them well. As I prepare to leave that job, I wanted to make sure the school had an archive of those videos outside of the ThankView website. I couldn’t figure out a good way to download all of the videos within the product (aside from one at a time). Lucikly, their API allows you to bulk download videos.

Here is the code I used to download all the videos into a directory called thankview:

import http.client
import urllib.request
import mimetypes
import json

conn = http.client.HTTPSConnection("api.thankview.com")
payload = ''
headers = {
  'Content-Type': 'application/json',
  'Authorization': 'Bearer *********'
}

for page in range(6):
  uri = "/api/video?limit=100&page=" + str(page)
  conn.request("GET", uri, payload, headers)
  res = conn.getresponse()
  data = res.read()
  conn.close()
  jsonResponse = json.loads(data)
  videos = jsonResponse["data"]["videos"]
  
  for video in videos:
    print("id: ", video["id"])
    print("title: ", video["title"])
    print("video_path: ", video["video_path"])
    filename = "thankview/" + str(video["id"]) + "-" + video["title"] + ".mp4"
    print(filename)
    try:
      urllib.request.urlretrieve(video["video_path"],filename)
    except:
      print("error")

Using the Zoom API to deal with webinar panelists

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 “panelists” in Zoom parlance, and when you duplicate a Webinar it does not duplicate the panelists. That’s a pain since there are a lot of panelists, and for each you need a name and e-mail address.

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’ll make a Google Apps Manager (GAM) knock off that I’ll call ZAM! In the meantime, perhaps someone else will find this helpful.

First, Zoom has good documentation of its API. To start, you will need to build an app to get credentials. For my scripts, I’m using JSON Web Tokens (JWT) for authentication. I found this post in the Zoom Dev Forums helpful as a starting point.

Get information on a Zoom user

Here is a short Python script to get information on a user to give a little idea on how to use the API.

import jwt   # pip3 install pyjwt --user
import http.client
import datetime
import json
import sys
 
api_key = '********' # replace with credentials from
api_sec = '********' # your app in Zoom Marketplace
 
# generate JWT
payload = {
'iss': api_key,
'exp': datetime.datetime.utcnow() + datetime.timedelta(hours=2)
}
 
jwt_encoded = str(jwt.encode(payload, api_sec), 'utf-8')
 
 
# call API: get user list
conn = http.client.HTTPSConnection("api.zoom.us")
headers = {
'authorization': "Bearer %s" % jwt_encoded,
'content-type': "application/json"
}
email = str(sys.argv[1])
conn.request("GET", "/v2/users/" +  email, headers=headers)
res = conn.getresponse()
response_string = res.read().decode('utf-8')
 
user_json = json.loads(response_string)
json_formatted_str = json.dumps(user_json, indent=2)
print(json_formatted_str)

You can use this like this:

# python3.7 zoom-user.py user@domain.com

{
  "id": "xxxxxxxxxxx",
  "first_name": "John",
  "last_name": "Smith",
  "email": "user@domain.com",
  "type": 2,
  "role_name": "Admin",
  "pmi": 111111111,
  "use_pmi": false,
  "personal_meeting_url": "https://myschool.zoom.us/j/111111111?pwd=UmVTASDFc3pXUTNpOFZNb34A09",
  "timezone": "America/Chicago",
  "verified": 0,
  "dept": "",
  "created_at": "2020-04-13T02:42:31Z",
  "last_login_time": "2020-05-22T19:38:06Z",
  "last_client_version": "4.6.20561.0413(mac)",
  "pic_url": "https://lh3.googleusercontent.com/a-/AOh14GgQadfagrA8l4U9fhsbZ1hOTMSvDxE3gGQ",
  "host_key": "111861",
  "jid": "3timqwabrvs00ayurhg_ha@xmpp.zoom.us",
  "group_ids": [
    "qCpDwoo5T1qS4cn8RSy8rQ"
  ],
  "im_group_ids": [],
  "account_id": "fhsbZ1cOTMSvDxE3g",
  "language": "en-US",
  "phone_country": "",
  "phone_number": "",
  "status": "active",
  "job_title": "",
  "location": ""
}

Note: I’ve redacted/change all of the ID and info above for obvious reasons.

Getting a list of all webinars panelists

This Python script lists all of the panelist names and email addresses.

import jwt   # pip3 install pyjwt --user
import http.client
import datetime
import json
import sys

api_key = '********' # replace with credentials from
api_sec = '********' # your app in Zoom Marketplace

# generate JWT
payload = {
'iss': api_key,
'exp': datetime.datetime.utcnow() + datetime.timedelta(hours=2)
}

jwt_encoded = str(jwt.encode(payload, api_sec), 'utf-8')

# call API: get webinar panelists
conn = http.client.HTTPSConnection("api.zoom.us")
headers = {
'authorization': "Bearer %s" % jwt_encoded,
'content-type': "application/json"
}
webinarid = str(sys.argv[1])
conn.request("GET", "/v2/webinars/" + webinarid + "/panelists", headers=headers)
res = conn.getresponse()
response_string = res.read().decode('utf-8')
response_json = json.loads(response_string)

for panelist in response_json["panelists"]:
    print(panelist["name"],  panelist["email"])

Here is an example of the script in action listing panelists for webinar id 91119118113:

# python3.7 zoom-webinar-panelists.py 91119118113
John Smith jsmith@domain.com
Jane Smith jane.smith@anotherdomain.com

Adding Panelists to a Webinar

Next is a Python script to add a panelist to a webinar. It takes the webinar ID, panelist name and email address as parameters.

import jwt   # pip3 install pyjwt --user
import http.client
import datetime
import json
import sys

api_key = '********' # replace with credentials from
api_sec = '********' # your app in Zoom Marketplace

# generate JWT
payload = {
'iss': api_key,
'exp': datetime.datetime.utcnow() + datetime.timedelta(hours=2)
}

jwt_encoded = str(jwt.encode(payload, api_sec), 'utf-8')

# call API: add panelist
conn = http.client.HTTPSConnection("api.zoom.us")
headers = {
'authorization': "Bearer %s" % jwt_encoded,
'content-type': "application/json"
}

num_arguments = len(sys.argv)-1
webinar = str(sys.argv[1])
email = sys.argv[num_arguments]
name = ""
i = 2
while i < num_arguments:
    name = name + sys.argv[i] + " "
    i = i+1
name = name.rstrip()
print(name, email,webinar)
body = "{\"panelists\":[{\"name\":\"" + name + "\",\"email\":\"" + email + "\"}]}"

webinar = str(sys.argv[1])
conn.request("POST", "/v2/webinars/" + webinar + "/panelists", body, headers=headers)
res = conn.getresponse()
response_string = res.read().decode('utf-8')

Here is an exampling of using the script to add “John Q. Public” john.q.public@domain.com to webinar id 91119118113:

python3.7 zoom-webinar-panelists-add.py 91119118113 John Q. Public john.q.public@domain.com

{"id":"91119118113","updated_at":"2020-05-25T23:25:22Z"}

Closing Thoughts

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’d much rather manage Zoom from the command line.