Chapter 11: Cisco Meraki Dashboard API Automation

Learning Objectives

11.1 Meraki Dashboard API Fundamentals

Pre-Check — What do you already know?

1. What is the primary authentication header used with the Meraki Dashboard API?

Authorization: Token <key>
X-Cisco-Meraki-API-Key: <key>
X-Auth-Token: <key>
API-Key: <key>

2. What is the Meraki API's per-organization steady-state rate limit?

100 requests/second
5 requests/second
10 requests/second
50 requests/second

3. Which HTTP status code does the Meraki API return when the rate limit is exceeded?

403 Forbidden
503 Service Unavailable
401 Unauthorized
429 Too Many Requests

4. What is the correct Meraki resource hierarchy from top to bottom?

Network → Organization → Device
Organization → Network → Device
Device → Network → Organization
Organization → Device → Network

5. Which Meraki Python SDK parameter enables dry-run mode (simulates calls without executing)?

dry_run=True
test_mode=True
simulate=True
preview=True

11.1.1 The Cloud-First Architecture

Cisco Meraki is a cloud-managed networking platform. Unlike traditional infrastructure where engineers SSH into devices to push CLI commands, every Meraki device communicates with the Meraki cloud. The Dashboard is the control plane — all configuration lives in the cloud and is pushed down to devices. This means a single API call can simultaneously configure hundreds of devices across geographically dispersed sites, because all of them share a common cloud control plane.

flowchart LR A["Automation Script\nPython / REST"] -->|"HTTPS API Request\nX-Cisco-Meraki-API-Key"| B["Meraki Cloud\napi.meraki.com/api/v1"] B -->|"Configuration Push\nCloud Tunnel"| C["MX Security\nAppliance"] B -->|"Configuration Push\nCloud Tunnel"| D["MS Switch"] B -->|"Configuration Push\nCloud Tunnel"| E["MR Access\nPoint"] B -->|"Configuration Push\nCloud Tunnel"| F["MG Cellular\nGateway"] subgraph Cloud["Cloud Control Plane"] B end subgraph OnPrem["On-Premises Devices"] C D E F end

11.1.2 Authentication and API Key Management

Every API request must carry an authentication credential. The Meraki API supports two header formats. The dedicated header X-Cisco-Meraki-API-Key is most common and explicit. A Bearer token format is also accepted. Never hardcode API keys in source files — store the key as an environment variable:

export MERAKI_DASHBOARD_API_KEY="your_key_here"

The official Meraki Python SDK reads MERAKI_DASHBOARD_API_KEY from the environment automatically if no key is passed at instantiation.

11.1.3 The Resource Hierarchy

The Meraki API is organized around a strict three-tier hierarchy: Organization → Network → Device. Most endpoints require either an organizationId or a networkId as a path parameter, and device-level endpoints require a serial number. Always discover IDs dynamically rather than hardcoding them.

flowchart LR O["Organization\norgId"] --> N1["Network A\nnetworkId"] O --> N2["Network B\nnetworkId"] N1 --> D1["MX Appliance\nserial"] N1 --> D2["MS Switch\nserial"] N1 --> D3["MR Access Point\nserial"] N2 --> D4["MS Switch\nserial"] N2 --> D5["MR AP\nserial"] E1["GET /organizations"] -.->|"no path params"| O E2["GET /organizations/{orgId}/networks"] -.->|"orgId required"| N1 E3["GET /networks/{networkId}/devices"] -.->|"networkId required"| D1

11.1.4 Rate Limiting — Token Bucket Model

The Meraki API enforces rate limits at 10 requests/second per organization (burst up to 30 in 2 seconds) and 100 requests/second per source IP. When the bucket empties, the API returns HTTP 429 Too Many Requests with a Retry-After header. The SDK handles this automatically.

11.1.5 The Meraki Python SDK

Install with pip install meraki. The SDK provides full endpoint coverage, automatic 429 retry, built-in pagination, request logging, preview (dry-run) mode, and async support via meraki.aio.AsyncDashboardAPI.

import meraki

# Reads MERAKI_DASHBOARD_API_KEY from environment automatically
dashboard = meraki.DashboardAPI()

# Preview (dry-run) mode — no changes applied
dashboard = meraki.DashboardAPI(simulate=True)

Interactive: Token Bucket Rate Limiter

TOKEN BUCKET
24 / 30
tokens available
HTTP 200 OK
Refills 10 tokens/sec at org scope. Empty bucket = HTTP 429.

Key Points — Section 11.1

Post-Check — Confirm your understanding

1. What is the primary authentication header used with the Meraki Dashboard API?

Authorization: Token <key>
X-Cisco-Meraki-API-Key: <key>
X-Auth-Token: <key>
API-Key: <key>

2. What is the Meraki API's per-organization steady-state rate limit?

100 requests/second
5 requests/second
10 requests/second
50 requests/second

3. Which HTTP status code does the Meraki API return when the rate limit is exceeded?

403 Forbidden
503 Service Unavailable
401 Unauthorized
429 Too Many Requests

4. What is the correct Meraki resource hierarchy from top to bottom?

Network → Organization → Device
Organization → Network → Device
Device → Network → Organization
Organization → Device → Network

5. Which Meraki Python SDK parameter enables dry-run mode (simulates calls without executing)?

dry_run=True
test_mode=True
simulate=True
preview=True

11.2 Configuration Automation

Pre-Check — What do you already know?

1. How many actions can an asynchronous Meraki Action Batch contain?

20
50
100
500

2. In Meraki wireless configuration, how are SSIDs created in the API?

POST to create a new SSID slot
PUT to update one of 15 pre-existing slots (0–14)
PATCH to partially modify a named SSID
GET to fetch and then PUT to a dynamic slot

3. Which switch port field controls whether a port is an access or trunk link in the Meraki API?

mode
portMode
type
linkType

4. What is a key advantage of Action Batches over individual API calls for bulk changes?

They bypass the rate limit entirely
They execute atomically — all succeed or all roll back
They support up to 1000 operations per batch
They do not require an API key

5. Which authMode value configures WPA2-Enterprise with an external RADIUS server?

wpa2-enterprise
radius-auth
8021x-radius
enterprise-dot1x

11.2.1 Action Batches — Bulk Atomic Operations

Action Batches group multiple write operations (POST, PUT, DELETE) into a single API call that executes atomically — either every action succeeds, or none do. Think of it like a database transaction. This is the primary mechanism for bulk configuration changes.

ConstraintValue
Max actions — synchronous batch20
Max actions — asynchronous batch100
Max concurrent batches per org5
Batch completion timeout10 minutes

Synchronous batches (up to 20 actions) wait for all actions to complete before returning an HTTP response. Asynchronous batches (up to 100 actions) return immediately with a batch_id; poll the status endpoint until completed or failed.

sequenceDiagram participant Script as Automation Script participant API as Meraki API participant Cloud as Meraki Cloud participant Device as Target Devices Note over Script,API: Synchronous Batch (up to 20 actions) Script->>API: POST /actionBatches synchronous:true confirmed:true API->>Cloud: Execute all actions Cloud->>Device: Push configuration Device-->>Cloud: Acknowledge Cloud-->>API: All actions complete API-->>Script: HTTP 200 — pass/fail result Note over Script,API: Asynchronous Batch (up to 100 actions) Script->>API: POST /actionBatches synchronous:false confirmed:true API-->>Script: HTTP 201 — batch_id (immediate) loop Poll every 2 seconds Script->>API: GET /actionBatches/{batch_id} API-->>Script: status: running end Cloud->>Device: Push all configurations Script->>API: GET /actionBatches/{batch_id} API-->>Script: status: completed

11.2.2 Switch Port Configuration

Switch ports are addressed by device serial and portId. The type field is either access or trunk. Use vlan for access ports, allowedVlans for trunks.

# Configure an access port
dashboard.switch.updateDeviceSwitchPort(
    serial="Q2AB-CDEF-GHIJ",
    portId="5",
    type="access",
    vlan=100,
    voiceVlan=200,
    poeEnabled=True
)

# Configure a trunk uplink
dashboard.switch.updateDeviceSwitchPort(
    serial="Q2AB-CDEF-GHIJ",
    portId="48",
    type="trunk",
    allowedVlans="100,200,300,400"
)

11.2.3 VLAN Configuration on MX Appliances

VLANs are scoped to a network and managed under /networks/{networkId}/appliance/vlans. The MX security appliance acts as the Layer 3 gateway. DHCP handling is set per VLAN.

dashboard.appliance.createNetworkApplianceVlan(
    networkId=network_id,
    id="100",
    name="Corporate",
    subnet="192.168.100.0/24",
    applianceIp="192.168.100.1",
    dhcpHandling="Run a DHCP server"
)

11.2.4 Wireless SSID Configuration

Each Meraki network supports up to 15 SSIDs (slots 0–14). All slots are pre-created in a disabled state — you update them, never create. The authMode field controls authentication: open, psk, 8021x-radius, 8021x-meraki, 8021x-google, or 8021x-entra.

# WPA2-Personal corporate SSID
dashboard.wireless.updateNetworkWirelessSsid(
    networkId=network_id,
    number="0",
    name="CorpWiFi",
    enabled=True,
    authMode="psk",
    wpaEncryptionMode="WPA2 only",
    psk="SecureP@ssword2025",
    ipAssignmentMode="Bridge mode",
    vlanId=100
)

# WPA2-Enterprise with external RADIUS
dashboard.wireless.updateNetworkWirelessSsid(
    networkId=network_id,
    number="1",
    name="Corp-Dot1x",
    enabled=True,
    authMode="8021x-radius",
    radiusServers=[{"host": "10.0.0.50", "port": 1812, "secret": "secret"}]
)

Interactive: API Endpoint Path Builder

Click a resource level to see the corresponding API endpoint path.

Organization
└─ Network SSID VLAN Clients
└─ Switch Port Device Uplink Status
▷ Click a resource above to see its API endpoint

Key Points — Section 11.2

Post-Check — Confirm your understanding

1. How many actions can an asynchronous Meraki Action Batch contain?

20
50
100
500

2. In Meraki wireless configuration, how are SSIDs created in the API?

POST to create a new SSID slot
PUT to update one of 15 pre-existing slots (0–14)
PATCH to partially modify a named SSID
GET to fetch and then PUT to a dynamic slot

3. Which switch port field controls whether a port is an access or trunk link in the Meraki API?

mode
portMode
type
linkType

4. What is a key advantage of Action Batches over individual API calls for bulk changes?

They bypass the rate limit entirely
They execute atomically — all succeed or all roll back
They support up to 1000 operations per batch
They do not require an API key

5. Which authMode value configures WPA2-Enterprise with an external RADIUS server?

wpa2-enterprise
radius-auth
8021x-radius
enterprise-dot1x

11.3 Monitoring and Alerting

Pre-Check — What do you already know?

1. In Meraki webhooks, what field in the payload should your server validate to prevent spoofed callbacks?

organizationId
sharedSecret
networkId
version

2. Which Meraki SDK class should you use for high-concurrency monitoring of many networks simultaneously?

meraki.DashboardAPI
meraki.ConcurrentAPI
meraki.aio.AsyncDashboardAPI
meraki.ParallelAPI

3. What is the primary advantage of webhooks over API polling for Meraki event monitoring?

Webhooks support more event types than polling
Webhooks eliminate rate limit pressure and provide real-time delivery
Webhooks bypass authentication requirements
Webhooks are faster because they use UDP instead of TCP

4. Which endpoint retrieves the online/offline status of all devices in an organization?

GET /organizations/{orgId}/devices/statuses
GET /organizations/{orgId}/devices/online
GET /organizations/{orgId}/devicesStatuses
GET /networks/{networkId}/devices/health

5. What SDK method is used to register a webhook HTTP server for a Meraki network?

dashboard.organizations.createOrganizationWebhook()
dashboard.networks.createNetworkWebhooksHttpServer()
dashboard.webhooks.registerEndpoint()
dashboard.networks.addWebhookListener()

11.3.1 Client and Device Monitoring

The MONITOR category provides read-only visibility into current and historical network state. Key monitoring patterns:

# List clients active in the last 24 hours
clients = dashboard.networks.getNetworkClients(
    networkId=network_id,
    timespan=86400  # seconds
)

# Device online/offline status across an org
statuses = dashboard.organizations.getOrganizationDevicesStatuses(
    organizationId=org_id
)
online = [d for d in statuses if d['status'] == 'online']
offline = [d for d in statuses if d['status'] == 'offline']

# MX uplink status
uplinks = dashboard.organizations.getOrganizationUplinksStatuses(
    organizationId=org_id
)

11.3.2 Webhooks — Event-Driven Alerting

Polling burns through your rate limit budget. Webhooks invert the model: Meraki pushes HTTPS POST notifications to your registered endpoint when alert conditions are met (device offline, client connects, firmware update, etc.). Always validate the sharedSecret field in every incoming payload to prevent spoofed callbacks.

sequenceDiagram participant Device as Meraki Device participant Cloud as Meraki Cloud participant Handler as Webhook Handler participant Action as Remediation Automation Device->>Cloud: Heartbeat lost / event triggered Cloud->>Cloud: Evaluate alert conditions Cloud->>Handler: HTTPS POST /meraki/webhook JSON payload with sharedSecret Handler->>Handler: Validate sharedSecret Handler-->>Cloud: HTTP 200 received:true Handler->>Action: Trigger remediation (notify NOC, re-provision) Note over Handler,Action: No polling needed — event delivery is real-time
# Register a webhook server
webhook = dashboard.networks.createNetworkWebhooksHttpServer(
    networkId=network_id,
    name="Automation-Controller",
    url="https://automation.example.com/meraki/webhook",
    sharedSecret="mysharedsecret123"
)

# Test the webhook endpoint
test = dashboard.networks.createNetworkWebhooksWebhookTest(
    networkId=network_id,
    url="https://automation.example.com/meraki/webhook",
    sharedSecret="mysharedsecret123"
)

11.3.3 Async SDK for High-Concurrency Monitoring

When retrieving data for dozens or hundreds of networks simultaneously, use meraki.aio.AsyncDashboardAPI with asyncio.gather() to issue all queries in parallel. This reduces a multi-minute sequential operation to seconds.

import asyncio
import meraki.aio

async def get_all_clients(org_id):
    async with meraki.aio.AsyncDashboardAPI(suppress_logging=True) as aiomeraki:
        networks = await aiomeraki.organizations.getOrganizationNetworks(
            organizationId=org_id
        )
        tasks = [
            aiomeraki.networks.getNetworkClients(networkId=n['id'], timespan=3600)
            for n in networks
        ]
        results = await asyncio.gather(*tasks, return_exceptions=True)
        return [c for r in results if not isinstance(r, Exception) for c in r]

clients = asyncio.run(get_all_clients("1234567890"))

11.3.4 API Usage Monitoring

Query your own API consumption programmatically to identify hot endpoints and avoid approaching rate limits. The Meraki Dashboard also includes a built-in API Analytics view under Organization → API & Webhooks.

from collections import Counter
api_requests = dashboard.organizations.getOrganizationApiRequests(
    organizationId=org_id, timespan=3600
)
code_counts = Counter(r['responseCode'] for r in api_requests)
# Identifies which endpoints generate the most 429s

Key Points — Section 11.3

Post-Check — Confirm your understanding

1. In Meraki webhooks, what field in the payload should your server validate to prevent spoofed callbacks?

organizationId
sharedSecret
networkId
version

2. Which Meraki SDK class should you use for high-concurrency monitoring of many networks simultaneously?

meraki.DashboardAPI
meraki.ConcurrentAPI
meraki.aio.AsyncDashboardAPI
meraki.ParallelAPI

3. What is the primary advantage of webhooks over API polling for Meraki event monitoring?

Webhooks support more event types than polling
Webhooks eliminate rate limit pressure and provide real-time delivery
Webhooks bypass authentication requirements
Webhooks are faster because they use UDP instead of TCP

4. Which endpoint retrieves the online/offline status of all devices in an organization?

GET /organizations/{orgId}/devices/statuses
GET /organizations/{orgId}/devices/online
GET /organizations/{orgId}/devicesStatuses
GET /networks/{networkId}/devices/health

5. What SDK method is used to register a webhook HTTP server for a Meraki network?

dashboard.organizations.createOrganizationWebhook()
dashboard.networks.createNetworkWebhooksHttpServer()
dashboard.webhooks.registerEndpoint()
dashboard.networks.addWebhookListener()

Your Progress

Answer Explanations