How to Build an API Request in 3 Ways

Hands-on lab showing how to craft REST API requests using cURL, Python, and Postman in the Cisco Meraki Sandbox for the 200-901 DEVASC exam.


Cisco DevNet Associate course 021 Understanding and Using APIs – Construct a REST API request to accomplish a task given API documentation – Lab

Watch Full Demo on YouTube:

Introduction:

When you first begin working with REST APIs in the Cisco DevNet world, the documentation can feel a bit overwhelming. You’re introduced to concepts like endpoints, payloads, headers, authentication, HTTP verbs—and it’s not always obvious how all of these pieces fit together when building an actual request. That’s exactly why this lab exists.

In this part of the DevNet Associate series, we take a practical, hands-on approach to understanding API calls by building them directly from the official documentation. Instead of simply reading about endpoints or memorizing definitions, we’re going to interact with a live cloud environment and see how REST API requests behave in real time.

To keep things consistent and easy to follow, we’ll be using the Cisco Meraki Dashboard API inside the DevNet Sandbox. It’s a fully isolated environment that gives you your own virtual Meraki organization, where you can retrieve data, create configurations, update resources, and safely experiment with automation workflows.

What makes this lab especially valuable is that we’ll approach the same API calls from three different angles—cURL, Python, and Postman. Each tool reveals something different about how REST APIs work.

  • With cURL, you see the raw mechanics of an HTTP request.
  • With Python, you turn those requests into reusable automation.
  • And with Postman, you get a visual, interactive way to explore and test the API.

By the end of this walkthrough, you’ll not only understand how to read API documentation, but you’ll know exactly how to transform that documentation into real, functioning calls—no guesswork required.


🧪 Part 1 — Crafting REST API Requests with cURL

Before jumping into the commands, let’s quickly revisit what cURL actually is.
cURL stands for Client URL, and it’s a command-line tool used to send data to and from servers. It supports all common HTTP verbs like GET, POST, PUT, and DELETE, which makes it a perfect starting point for interacting with REST APIs.

The goal of this lab is to walk through a complete CRUD sequence using cURL:

  • GET → Retrieve organizations, networks, VLANs
  • POST → Create a new VLAN
  • PUT → Update an existing VLAN
  • PUT -> PATCH-style → Partially update VLAN attributes
  • DELETE → Remove a VLAN

We also leverage the -s flag to hide the progress meter and jq for beautiful JSON formatting.


🔹 Task 1 — GET All Organizations

We start with a simple GET request:

"""
curl -s -L \
  -H "X-Cisco-Meraki-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -X GET \
  "https://api.meraki.com/api/v1/organizations" | jq
"""

This returns a neatly formatted JSON object containing:

  • The organization ID
  • The organization name
  • The Meraki Dashboard
  • SAML authentication information
  • Licensing model
  • Cloud region
  • API access status

This first call confirms that your API key works and the organization is reachable.


🔹 Task 2 — GET All Networks in the Organization

Using the organization ID from the previous response:

"""
curl -s -L \
  -H "X-Cisco-Meraki-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -X GET \
  "https://api.meraki.com/api/v1/organizations/ORG_ID/networks" | jq
"""

The sandbox returns a single network:

  • Network ID
  • “branch office” as the network name
  • Supported product types (appliance, switch, wireless, sensor, etc.)
  • Time zone and URL
  • Configuration template info
  • Whether it’s virtual or physical

🔹 Task 3 — GET All VLANs in the Network

"""
curl -s -L \
  -H "X-Cisco-Meraki-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -X GET \
  "https://api.meraki.com/api/v1/networks/NETWORK_ID/appliance/vlans" | jq
"""

The default VLAN (ID 1) appears with:

  • Subnet and gateway
  • DHCP configuration
  • DNS handling
  • IPv6 settings (disabled in the sandbox)

🔹 Task 4 — POST to Create a New VLAN

"""
curl -s -L \
  -H "X-Cisco-Meraki-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -X POST \
  --data '{
    "id": 10,
    "name": "Student VLAN",
    "subnet": "192.168.10.0/24",
    "applianceIp": "192.168.10.1"
  }' \
"https://api.meraki.com/api/v1/networks/NETWORK_ID/appliance/vlans" | jq
"""

The response confirms that VLAN 10 is successfully created.


🔹 Task 5 — PUT to Update VLAN 20

"""
curl -s -L \
  -H "X-Cisco-Meraki-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -X PUT \
  --data '{
    "name": "Lab VLAN Updated",
    "subnet": "192.168.20.0/24",
    "applianceIp": "192.168.20.1"
  }' \
"https://api.meraki.com/api/v1/networks/NETWORK_ID/appliance/vlans/20" | jq
"""

PUT replaces the entire VLAN object with the updated values.


🔹 Task 6 — PATCH-Style Update

Meraki treats PUT like PATCH, so you can send only the field(s) you want to change:

"""
curl -s -L \
  -H "X-Cisco-Meraki-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -X PUT \
  --data '{ "name": "Lab VLAN Patched" }' \
"https://api.meraki.com/api/v1/networks/NETWORK_ID/appliance/vlans/20" | jq
"""

Only the VLAN name is updated—everything else stays untouched.


🔹 Task 7 — DELETE VLAN 20

"""
curl -s -L \
  -H "X-Cisco-Meraki-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -X DELETE \
  "https://api.meraki.com/api/v1/networks/NETWORK_ID/appliance/vlans/20"
"""

A successful delete returns HTTP 204 No Content, which simply means the VLAN is gone.


🧪 Part 2 — Performing REST API Calls in Python (VS Code)

Now that we’ve done everything manually with cURL, it’s time to automate it using Python.
For this lab, we create five scripts:

  • Meraki_API_GET.py
  • Meraki_API_POST.py
  • Meraki_API_PUT.py
  • Meraki_API_PATCH.py
  • Meraki_API_DELETE.py
  • secrets.py (to store the API key and network ID)

Each script handles one REST verb and mirrors the logic we used with cURL.


The secrets.py file is a small but important part of the automation workflow. Its purpose is to store sensitive information—such as your Meraki API key and the network ID you are working with—in a single, separate location rather than hardcoding those values directly into each script.

Inside the file, you’ll find two simple variables:

# secrets.py
API_KEY = "1ec9bb650a369cc6c2facb7e4722e6346938cd15"
NETWORK_ID = "L_669910444571380609"

The first variable, API_KEY, is what authenticates you when interacting with the Meraki Dashboard API. Without it, none of your requests would be authorized, and the API would simply reject them. Storing the key in a dedicated file keeps your scripts clean and makes it easy to update your key later without changing several files.

The second variable, NETWORK_ID, refers to the specific Meraki network you’re targeting in the lab environment. Since many API endpoints require this parameter, placing it in the secrets.py file prevents duplication and minimizes the chance of errors if the ID ever changes.

By importing this file into all your Python scripts, you centralize your sensitive information and avoid exposing it throughout your code. This approach is a common best practice in automation and programming—especially when working with APIs—to keep things organized, secure, and easy to maintain.


🔹 GET Script — Retrieve VLANs


This script is designed to perform a simple but essential task: retrieve all VLANs configured on a Meraki network using a REST API GET request. It mirrors the cURL command you ran earlier but wraps it in clean, reusable Python code.

# Meraki_API_GET.py
import requests
from pprint import pprint
import secrets

url = f"https://api.meraki.com/api/v1/networks/{secrets.NETWORK_ID}/appliance/vlans"

headers = {
    "X-Cisco-Meraki-API-Key": secrets.API_KEY,
    "Content-Type": "application/json"
}

response = requests.get(url, headers=headers)

if response.status_code == 200:
    pprint(response.json())
else:
    print(f"Error: {response.status_code} - {response.text}")

Let’s break down what each part of the script is doing.


1. Importing Required Libraries
import requests
from pprint import pprint
import secrets
  • requests: This is the Python library that allows you to send HTTP requests easily.
  • pprint: Short for “pretty print,” it formats the JSON output so it’s easier to read.
  • secrets: This imports your API_KEY and NETWORK_ID from the secrets.py file, keeping sensitive information out of the script.

2. Building the API URL
url = f"https://api.meraki.com/api/v1/networks/{secrets.NETWORK_ID}/appliance/vlans"

Here, we construct the URL dynamically using the NETWORK_ID stored in the secrets file.
This ensures that if you ever change networks, you only update the value in one place.

This endpoint specifically retrieves all VLANs on a Meraki MX appliance within that network.


3. Defining the HTTP Headers
headers = {
    "X-Cisco-Meraki-API-Key": secrets.API_KEY,
    "Content-Type": "application/json"
}

The script includes two critical headers:

  • X-Cisco-Meraki-API-Key: Authenticates your request. Without this, the API would reject the call.
  • Content-Type: application/json: Tells the server what format we expect to send and receive data in.

These headers are identical to the ones used in your cURL examples, just expressed in Python dictionary form.


4. Sending the GET Request
response = requests.get(url, headers=headers)

This line actually sends the HTTP GET request to the Meraki API.
The requests.get() method takes the URL and headers and returns a response object containing:

  • the HTTP status code
  • the JSON data returned by the API
  • metadata about the transaction

5. Handling the API Response
if response.status_code == 200:
    pprint(response.json())
else:
    print(f"Error: {response.status_code} - {response.text}")

This is simple error handling:

  • If the response status code is 200 OK, we pretty-print the JSON.
  • If not, we display the error message to help diagnose what went wrong.

This structure makes the script easy to test, debug, and expand later.


🔹 POST Script — Create a VLAN

This script takes the next step beyond simply retrieving data—it creates a brand-new VLAN on the Meraki network. Instead of just sending a request to read information, we’re now sending data to the API so it can build a new configuration for us.

# Meraki_API_POST.py
import requests
from pprint import pprint
import secrets 
url = f"https://api.meraki.com/api/v1/networks/{secrets.NETWORK_ID}/appliance/vlans"
headers = {
    "X-Cisco-Meraki-API-Key": secrets.API_KEY,
    "Content-Type": "application/json"
}

payload = {
    "id": 40,
    "name": "Lab VLAN 40",
    "subnet": "192.168.40.0/24",
    "applianceIp": "192.168.40.1"
}

response = requests.post(url, headers=headers, json=payload)
if response.status_code in [200, 201]:
    pprint(response.json())
else:
    print(f"Error: {response.status_code} - {response.text}")

1. Defining the Payload
payload = {
    "id": 40,
    "name": "Lab VLAN 40",
    "subnet": "192.168.40.0/24",
    "applianceIp": "192.168.40.1"
}

Unlike a GET request, a POST requires a payload—the actual information you want the API to create.
Here, we’re defining a new VLAN with:

  • id → VLAN number
  • name → Friendly label for the dashboard
  • subnet → The network assigned to this VLAN
  • applianceIp → The MX appliance’s gateway within that subnet

This structure mirrors the JSON body you would send in a cURL POST request.


2. Sending the POST Request
response = requests.post(url, headers=headers, json=payload)

This is the core of the script.
By passing the payload through the json argument, Python automatically converts the dictionary into properly formatted JSON before sending it.

The API receives the request, validates the data, and—if everything is correct—creates the new VLAN.


3. Handling the Response
if response.status_code in [200, 201]:
    pprint(response.json())
else:
    print(f"Error: {response.status_code} - {response.text}")

POST responses often return:

  • 201 Created → The resource was successfully created
  • 200 OK → Some APIs respond with 200 instead of 201

This script checks for both possibilities before printing the JSON.
If something goes wrong—such as an invalid VLAN ID or conflicting subnet—the API returns an error message, and the script displays that instead.


🔹 PUT Script — Update a VLAN

This script demonstrates how to update an existing VLAN using the PUT HTTP method. While POST creates new resources, PUT is typically used when you want to replace or update the configuration of something that already exists—in this case, VLAN 40.

# Meraki_API_PUT.py
import requests
from pprint import pprint
import secrets
VLAN_ID = 40
url = f"https://api.meraki.com/api/v1/networks/{secrets.NETWORK_ID}/appliance/vlans/{VLAN_ID}"
headers = {
    "X-Cisco-Meraki-API-Key": secrets.API_KEY,
    "Content-Type": "application/json"
}

payload = {
    "name": "Lab VLAN 40 Updated",
    "subnet": "192.168.40.0/24",
    "applianceIp": "192.168.40.1"
}

response = requests.put(url, headers=headers, json=payload)
if response.status_code == 200:
    pprint(response.json())
else:
    print(f"Error: {response.status_code} - {response.text}")

1. Specifying the VLAN to Update
VLAN_ID = 40
url = f"https://api.meraki.com/api/v1/networks/{secrets.NETWORK_ID}/appliance/vlans/{VLAN_ID}"

Unlike the POST script, the URL here includes the VLAN ID directly at the end.
This tells the Meraki API exactly which VLAN you intend to update.
PUT requests almost always require a specific resource identifier like this.


2. Updating the Configuration
payload = {
    "name": "Lab VLAN 40 Updated",
    "subnet": "192.168.40.0/24",
    "applianceIp": "192.168.40.1"
}

The payload contains the replacement values for the VLAN. Even if only one field changes, a PUT request traditionally expects the full configuration, not just the modified fields.

Here, we are updating the VLAN name while keeping the subnet and gateway IP the same.


3. Sending the PUT Request
response = requests.put(url, headers=headers, json=payload)

This line sends the updated VLAN configuration to the Meraki API.
PUT behaves like a full update—the API uses the new payload to overwrite the existing configuration.


4. Checking the API Response
if response.status_code == 200:
    pprint(response.json())
else:
    print(f"Error: {response.status_code} - {response.text}")

A successful PUT update returns:

  • 200 OK → The resource was updated successfully

If anything is wrong—such as an invalid payload or a nonexistent VLAN—the script prints the error returned by the API.


🔹 PATCH Script — Partial Update

This script demonstrates how to perform a partial update to a VLAN’s configuration. While traditional PUT requests replace the entire object, Meraki’s API allows you to send only the fields you want to modify—effectively using PUT as a PATCH-style operation.

In this example, we’re updating just one attribute of VLAN 40: its name.

# Meraki_API_PATCH.py
import requests
from pprint import pprint
import secrets

VLAN_ID = 40
url = f"https://api.meraki.com/api/v1/networks/{secrets.NETWORK_ID}/appliance/vlans/{VLAN_ID}"

headers = {
    "X-Cisco-Meraki-API-Key": secrets.API_KEY,
    "Content-Type": "application/json"
}
payload = {
    "name": "Lab VLAN 40 Patched"
}
response = requests.put(url, headers=headers, json=payload)

if response.status_code == 200:
    pprint(response.json())
else:
    print(f"Error: {response.status_code} - {response.text}")

1. Targeting the Specific VLAN
VLAN_ID = 40
url = f"https://api.meraki.com/api/v1/networks/{secrets.NETWORK_ID}/appliance/vlans/{VLAN_ID}"

Just like in the PUT script, the VLAN ID is placed directly in the URL so the API knows exactly which VLAN you’re modifying.


2. Providing Only the Field You Want to Update
payload = {
    "name": "Lab VLAN 40 Patched"
}

This is the defining characteristic of a PATCH-style update:
instead of sending the full VLAN configuration, you only send the field that needs to change.

Here, we’re replacing the name while leaving the subnet, gateway IP, DHCP settings, and everything else untouched.


3. Sending the Update
response = requests.put(url, headers=headers, json=payload)

Even though the method is still PUT, Meraki interprets this as a partial update because the payload is incomplete.
This behavior makes PUT flexible and convenient for quick edits.


4. Validating the Response
if response.status_code == 200:
    pprint(response.json())
else:
    print(f"Error: {response.status_code} - {response.text}")

A successful update returns:

  • 200 OK → The field was updated and the VLAN now reflects the new name

If the VLAN ID doesn’t exist or the payload is invalid, the script prints the error details.


🔹 DELETE Script — Remove a VLAN

This script represents the final stage of the REST workflow—removing an existing VLAN from the Meraki network. Unlike GET, POST, PUT, or PATCH, the DELETE method does not send configuration data or return a JSON body. Its purpose is simple: tell the API which resource should be removed, and if the request is valid, the API deletes it.

# Meraki_API_DELETE.py
import requests
from pprint import pprint
import secrets

VLAN_ID = 40

url = f"https://api.meraki.com/api/v1/networks/{secrets.NETWORK_ID}/appliance/vlans/{VLAN_ID}"

headers = {
    "X-Cisco-Meraki-API-Key": secrets.API_KEY,
    "Content-Type": "application/json"
}

response = requests.delete(url, headers=headers)

if response.status_code == 204:
    print(f"VLAN {VLAN_ID} deleted successfully.")
else:
    print(f"Error: {response.status_code} - {response.text}")
1. Identifying the VLAN to Delete
VLAN_ID = 40
url = f"https://api.meraki.com/api/v1/networks/{secrets.NETWORK_ID}/appliance/vlans/{VLAN_ID}"

Just like in the update scripts, the VLAN ID is included directly in the URL.
This lets the API know exactly which VLAN should be removed from the network.


2. Sending the DELETE Request
response = requests.delete(url, headers=headers)

The DELETE method is the simplest of all:

  • No payload
  • No JSON body
  • Only the URL and headers are required

This tells the Meraki API: “Remove VLAN 40 from this network.”


3. Interpreting the Response
if response.status_code == 204:
    print(f"VLAN {VLAN_ID} deleted successfully.")
else:
    print(f"Error: {response.status_code} - {response.text}")

A successful deletion returns:

  • 204 No Content → This is normal for a DELETE request

The API doesn’t return any JSON because there’s nothing to send back—the VLAN no longer exists.
Instead, the status code is your confirmation that the operation completed successfully.

If something goes wrong (for example, if the VLAN doesn’t exist or the request is invalid), the script prints the error message along with the HTTP status code.


🧪 Part 3 — Sending REST API Calls with Postman

Finally, we switch to Postman for a graphical, user-friendly way to explore the API.

Postman makes it incredibly easy to:

This is ideal if you’re learning, debugging, or comparing output across tools.

  • Build requests visually
  • Add headers
  • Modify JSON payloads
  • Test responses
  • Organize calls into collections

Tasks in Postman:

  1. Create a new collection
  2. Add individual requests (GET, POST, PUT, PATCH, DELETE)
  3. Add required headers
  4. Insert JSON bodies where needed
  5. Send requests and validate changes in the Meraki Dashboard

Postman gives you instant visual feedback and helps reinforce everything you’ve learned so far.

The image below demonstrates how you could create a GET request using Postman GUI:

If you are going to use (Post, Put or Patch) then you would need to create a body as shown below:


🧾Conclusion

By working through this lab, you’ve taken a major step toward becoming truly comfortable with REST APIs in a real engineering workflow. Instead of treating API documentation as something abstract or intimidating, you’ve now seen how to interpret it, translate it into real requests, and apply those requests across multiple tools.

Using cURL, you learned how to construct raw API calls directly from the command line, giving you a clear understanding of the mechanics behind every request. With Python, you elevated those same calls into practical automation—something you can build on and expand as your skills grow. And with Postman, you explored a visual approach that helps you prototype, test, and validate requests quickly and confidently.

These three perspectives give you a complete toolkit for working with REST APIs, whether you’re studying for the Cisco DevNet Associate, building network automation in production, or simply expanding your technical abilities. The more you practice, the more natural this process becomes—and you’ll soon find that reading API documentation and crafting requests becomes second nature.

You’re now equipped with the core skills needed to build, modify, and manage configurations through the Meraki Dashboard API and beyond. Keep experimenting, keep exploring, and most importantly, keep building—because this is exactly how you grow from understanding APIs to truly mastering them.

References:

DevNet Associate – Cisco

Cisco Certified DevNet Expert (v1.0) Equipment and Software List

DevNet Associate Exam Topics


Discover more from IEE

Subscribe to get the latest posts sent to your email.


Discover more from IEE

Subscribe now to keep reading and get access to the full archive.

Continue reading