Cisco Meraki REST API calls with Python’s requests library

In the previous articles, I’ve described how to execute REST API calls using Postman software. This time we will dive into Python.

Tools

To run REST API calls we will use Python3 with the requests library. It’s not installed by default, so make sure it’s present before jumping further.

Environment

We will use the Cisco Meraki Always on sandbox. It’s a free lab environment that everybody can access to test various Meraki functionalities.

The base URL for API calls will be https://api.meraki.com/api/v1

For authentication we will use a API key, at the time of this article writing, API key is: 6bec40cf957de430a6f1f2baa056b99a4fac9ea0

You can find Cisco Meraki API documentation here.

API Calls

The following chapters are containing python source code. If you’re interested in running those scripts on your local machine, you can easily access them on the GitLab repository.

Organizations

We will start with script that gathers information about all organizations.

import requests
import json

BASE_URL = 'https://api.meraki.com/api/v1'
headers = { 'X-Cisco-Meraki-API-Key': '6bec40cf957de430a6f1f2baa056b99a4fac9ea0' }
RESOURCE = '/organizations'

call_response = requests.get(BASE_URL + RESOURCE, headers=headers)
if call_response.status_code != 200:
    print(f'Failed to get organizations')
    exit(1)
parsed_response = json.loads(call_response.text)

for organization in parsed_response:
    print('ID: {id}, Name: {name}'.format(id=organization['id'], name=organization['name']))

First of all, we’re importing the necessary libraries. Requests will be used for REST API calls. The API call returns a JSON string, so the JSON library will be used for conversion to the python data structures.

BASE_URL variable contains a URL to the Cisco Meraki environment. Our API call URL’s will be created by appending the appropriate string.

We will use the API key for authorization. In the headers dictionary, there is one key/value pair with authorization details.

RESOURCE variable determines the resource that we want to access with the REST API call. You can find a complete list of available options in the official documentation.

Since we have all necessary information, let’s execute our first REST API call!

We want to execute a GET request, that’s why we’re using a get method from the requests library. The first argument is the combination of the basic URL with a specified resource, that we want to access. The resulting string is as follows.

https://api.meraki.com/api/v1/organizations

A second argument is a dictionary with authorization details. We’re passing it explicitly as a header.

Let’s pause here for a second before jumping to the following line codes.

After execution of the REST API call, we’re receiving following object.

The requests.Response object was returned by the GET method. As we can see, there is a response code 200, which determines, that the call was successful. The call_response variable now has plenty of properties, but we will focus on the text, which returns the REST API response in the Unicode text.

Since the response is encoded in the JSON format, it’s convenient to convert it to the native python structures. It can be easily accomplished using the JSON library. The loads method takes the JSON string and converts it to the python data structures. After decoding, the parse_response variable is a list with dictionary elements.

From now on, the data can be easily accessed via native python utilities. Let’s loop through all organizations first. The single organization is built of a dictionary with keys of id, name, and url.

Let’s say that we want to print just id and name of the organization. Since it’s a dictionary, we can access the data with the standard Python syntax.

The output from the script is as follows.

ID: 681155, Name: DeLab
ID: 566327653141842188, Name: DevNetAssoc
ID: 575334852396582607, Name: 123456
ID: 575334852396582606, Name: TriDeptrai
ID: 575334852396582605, Name: My organization
ID: 575334852396582604, Name: thanh
ID: 575334852396582603, Name: 123456
ID: 575334852396582602, Name: My organization
ID: 575334852396582601, Name: 123
ID: 575334852396582600, Name:vnPro
ID: 575334852396582591, Name: Ftreqah organization
ID: 575334852396582590, Name: Ftreqah organization
ID: 575334852396582587, Name:vnPro
ID: 549236, Name: DevNet Sandbox
ID: 52636, Name: Forest City - Other
ID: 865776, Name: Cisco Live US 2019
ID: 463308, Name: DevNet San Jose

Networks

Now let’s jump to networks. In Meraki, an organization can have assigned one or more networks. Let’s say that we want to print all organizations and networks.

import requests
import json

BASE_URL = 'https://api.meraki.com/api/v1'
headers = { 'X-Cisco-Meraki-API-Key': '6bec40cf957de430a6f1f2baa056b99a4fac9ea0' }
RESOURCE = '/organizations'

call_response = requests.get(BASE_URL + RESOURCE, headers=headers)
if call_response.status_code != 200:
    print(f'Failed to get organizations')
    exit(1)
organizations = json.loads(call_response.text)

for organization in organizations:
    RESOURCE = '/organizations/{id}/networks'.format(id=organization['id'])
    call_response = requests.get(BASE_URL + RESOURCE, headers=headers)
    if call_response.status_code != 200:
        print('Failed to get networks for organization {organization}'.format(organization=organization["name"]))
        continue
    networks = json.loads(call_response.text)

    if len(networks) > 0:
        print('Printing networks for organization {name}:'.format(name=organization['name']))

        for network in networks:
            print('\tID: {id}, Name: {name}, TimeZone: {timezone}'.format(id=network['id'],
                                                                  name=network['name'],
                                                                  timezone=network['timeZone']))
    else:
        print('There are no networks assigned to organization {name}'.format(name=organization['name']))

First of all, we have to grab a list of organizations. After that, we have to loop through each organization(first for loop) and grab an organization id. Now we can build an API call gathering all networks assigned to a specified organization.

Down below you can find a syntax of the REST API call, that returns a list of networks assigned to a particular organization.

https://api.meraki.com/api/v1/organizations/{organization_id}/networks

If a particular organization has assigned networks, we’re looping through them and printing information in the second for loop. On the screenshot below you can find attributes of each network.

In this case, we want to print a network id, name, and time zone. In the following snippet, you can find the result.

Printing networks for organization DeLab
        ID: L_566327653141843049, Name: Lyoli, Timezone: America/New_York
        ID: L_566327653141846927, Name: Vegas Apartment, Timezone: America/Los_Angeles
        ID: L_566327653141856854, Name: DNEAlertsNet, Timezone: America/Los_Angeles
        ID: L_783626335162466320, Name: DevNetLab, Timezone: America/Los_Angeles
        ID: L_783626335162466514, Name: DevNetLab2, Timezone: America/Los_Angeles
        ID: L_783626335162466515, Name: DevNetLab3, Timezone: America/Los_Angeles
        ID: N_566327653141899127, Name: Nolan, Timezone: America/Los_Angeles
        ID: N_566327653141902646, Name: Lyoli MDM, Timezone: America/Los_Angeles
Printing networks for organization DevNetAssoc
        ID: L_566327653141858539, Name: DevNetAssoc1, Timezone: America/Los_Angeles
        ID: L_566327653141858540, Name: DevNetAssoc2, Timezone: America/Los_Angeles
        ID: L_566327653141858541, Name: DevNetAssoc3, Timezone: America/Los_Angeles
        ID: L_566327653141858542, Name: DevNetAssoc4, Timezone: America/Los_Angeles
        ID: L_566327653141858543, Name: DevNetAssoc5, Timezone: America/Los_Angeles
Printing networks for organization Hi Cory
        ID: L_573083052582908089, Name: San Jose Lab, Timezone: America/Los_Angeles
        ID: L_573083052582981640, Name: OTG Test Network, Timezone: America/Los_Angeles
        ID: L_573083052582987951, Name: WinNet1, Timezone: America/Los_Angeles
        ID: L_573083052582987953, Name: WinNet2, Timezone: America/Los_Angeles
        ID: N_573083052583231323, Name: Cisco Live Network2, Timezone: America/Los_Angeles
        ID: N_573083052583231354, Name: Cisco Live Network3, Timezone: America/Los_Angeles
        ID: N_573083052583231356, Name: Cisco Live Network4, Timezone: America/Los_Angeles
        ID: N_573083052583231376, Name: Another Device Name, Timezone: America/Los_Angeles
        ID: N_573083052583232041, Name: Cisco Live Network77, Timezone: America/Los_Angeles
        ID: N_573083052583236732, Name: ll, Timezone: America/Los_Angeles
        ID: N_573083052583236733, Name: jj, Timezone: America/Los_Angeles
        ID: N_573083052583236734, Name: hh, Timezone: America/Los_Angeles
        ID: N_573083052583236735, Name: uu, Timezone: America/Los_Angeles
Printing networks for organization organization with name changed
        ID: L_573083052582985912, Name: New_name, Timezone: America/Los_Angeles
        ID: L_573083052582990676, Name: New Apartment, Timezone: America/Los_Angeles
Printing networks for organization Jacks_test_net
        ID: L_573083052582993027, Name: Main Office, Timezone: America/Los_Angeles
        ID: N_573083052583225773, Name: NewLong Island Office, Timezone: America/Los_Angeles
Printing networks for organization New Meraki Org
        ID: L_573083052582989294, Name: Long Island Office test, Timezone: America/Los_Angeles
        ID: L_573083052582989297, Name: LongCKtest, Timezone: America/Los_Angeles
        ID: N_573083052583233224, Name: rhb-vmx-test-nw, Timezone: America/Los_Angeles
        ID: N_573083052583235085, Name: vMX Test, Timezone: America/Los_Angeles
        ID: N_573083052583235087, Name: newTest, Timezone: America/Los_Angeles
        ID: N_573083052583236066, Name: test7, Timezone: America/Los_Angeles
        ID: N_573083052583237700, Name: my automated network, Timezone: America/Los_Angeles
        ID: N_573083052583237701, Name: my new automated network, Timezone: America/Los_Angeles
        ID: N_573083052583238204, Name: my brand new automated network, Timezone: America/Los_Angeles
        ID: N_573083052583249835, Name: my new automated network10, Timezone: America/Los_Angeles
[...]

Devices

The last example is pretty similar to the previous one. In this case, we’re listing devices, that are assigned to each network.

import requests
import json

BASE_URL = 'https://api.meraki.com/api/v1'
headers = {'X-Cisco-Meraki-API-Key': '6bec40cf957de430a6f1f2baa056b99a4fac9ea0'}
RESOURCE = '/organizations'

call_response = requests.get(BASE_URL + RESOURCE, headers=headers)
if call_response.status_code != 200:
    print(f'Failed to get organizations')
    exit(1)
organizations = json.loads(call_response.text)

for organization in organizations:
    RESOURCE = '/organizations/{id}/networks'.format(id=organization['id'])
    call_response = requests.get(BASE_URL + RESOURCE, headers=headers)
    if call_response.status_code != 200:
        print('Failed to get networks for organization {organization}'.format(organization=organization["name"]))
        continue
    networks = json.loads(call_response.text)

    for network in networks:
        RESOURCE = '/networks/{id}/devices'.format(id=network['id'])
        call_response = requests.get(BASE_URL + RESOURCE, headers=headers)
        if call_response.status_code != 200:
            print('Failed to get devices for {network}'.format(network=network["name"]))
            continue
        devices = json.loads(call_response.text)

        if len(devices) > 0:
            print('Devices assigned to network {network}'.format(network=network['name']))

            for device in devices:
                if 'name' in device:
                    print('\tName: {name}, Model: {model}, Serial: {serial}'.format(name=device['name'],
                                                                                    model=device['model'],
                                                                                    serial=device['serial']))
                else:
                    print('\tModel: {model}, Serial: {serial}'.format(model=device['model'],
                                                                      serial=device['serial']))
        else:
            print('There are no devices assigned to the network {network}'.format(network=network['name']))

To list devices assigned to a particular network, we need to gather all networks. We’re doing it the same way as in the previous example. After we have a network id’s, we’re ready to list devices for each network. The API call to accomplish this is the following.

https://api.meraki.com/api/v1/networks/{network_id}/devices

After the API call execution, we have a list of devices. The attributes of each device are as follows.

Since we have all the necessary information, we can print the information. We’re grabbing the name, model, and serial of each network device. The result of the script is down below.

Devices assigned to network Lyoli
	Name: BigCat, Model: MX250, Serial: Q2SW-SWQ2-HZ9L
	Name: 1st Floor AP, Model: MR52, Serial: Q2LD-GYL3-KEHX
	Name: 2nd Floor AP, Model: MR52, Serial: Q2LD-AN9B-S6AJ
	Name: Sun Room, Model: MR84, Serial: Q2EK-UKGM-XSD9
	Name: Office AP, Model: MR52, Serial: Q2LD-ZWCZ-UA77
	Name: Basement AP, Model: MR52, Serial: Q2LD-3Y7V-7Y2X
	Model: MV12W, Serial: Q2GV-LDX2-53ZA
	Name: Big Office Switch, Model: MS250-48FP, Serial: Q2QW-W2W4-MCNR
	Name: Bedroom Switch, Model: MS220-8P, Serial: Q2HP-WEUW-2PQD
	Name: Basement switch, Model: MS220-8P, Serial: Q2HP-225A-XA5C
Devices assigned to network Vegas Apartment
	Model: MV71, Serial: Q2CV-V49B-RCMZ
	Name: Alex’s MR32, Model: MR32, Serial: Q2JD-7RNY-EB7Z
	Name: Alex's MR84 - 1, Model: MR84, Serial: Q2EK-2LYB-PCZP
	Name: Vegas Balcony MR84, Model: MR84, Serial: Q2EK-D4XP-235S
	Model: MR84, Serial: Q2EK-ACGE-URXL
	Name: Vegas Living Room MR84, Model: MR84, Serial: Q2EK-3UBE-RRUY
	Model: MX65, Serial: Q2QN-Y5ED-P57W
Devices assigned to network Nolan
	Model: MR52, Serial: Q2LD-X2S2-AG2U
	Model: MR52, Serial: Q2LD-N2U5-D83H
There are no devices assigned to the network Lyoli MDM
[...]

Summary

As you can probably deduce, REST API calls are a powerful tool in the network engineer hands. They can be used in a variety of different ways. Do you have a network device stocktaking? You can easily gather all the necessary information and save it in a convenient way. It’s just one use case that can save you a lot of work and time.

Share

2 thoughts on “Cisco Meraki REST API calls with Python’s requests library

  1. Hi, I was excited to try out this script which is exactly what I needed but when I tried it seems its is going on loop. I am not sure what is the cause though. Any ideas? Thank you.

Leave a Reply

Your email address will not be published. Required fields are marked *