# Guide to Cisco Meraki Webhooks: Features and Best Practices

Cisco Meraki webhook alerts notify your systems when something happens on a Meraki network: motion is detected, a setting changes, access points go down, a sensor reading crosses a threshold. If you're building monitoring, alerting, or automation on Meraki, webhooks are how you react without polling the Dashboard API.

This guide covers how Meraki webhooks work, the alerts you'll handle, the unusual verification model (a shared secret carried in the request body, not a header), custom templates, and the best practices for production.

## What are Cisco Meraki webhooks?

Meraki Dashboard sends webhook alerts as HTTP POSTs to an HTTP server (endpoint) you configure. Each payload describes an alert with a human-readable `alertType` and a machine-readable `alertTypeId`.

The verification model is what makes Meraki unusual: there's no signature header. Instead, a plaintext `sharedSecret` field is carried inside the JSON body, and you compare it against the secret you configured. Generic "verify the signature header" logic finds nothing to check.

## Cisco Meraki webhook features

| Feature | Details |
| --- | --- |
| Configuration | Dashboard > Network-wide > Alerts > Webhooks / HTTP servers |
| Verification | Plaintext `sharedSecret` field in the JSON body (compare to your configured value) |
| Transport security | TLS (HTTPS, CA-trusted cert; no self-signed) is the real protection |
| Payload | `alertType`, `alertTypeId`, `version`, `sentAt`, `occurredAt`, `organizationId`, `networkId`, `deviceSerial`, `alertData` |
| Custom templates | Liquid template language; can reshape headers and body |
| Delivery | ~90s after the event; "Send test" posts a sample |
| Auto-disable | Receiver disabled after >100 failed attempts in 24h |
| Alert catalog | `GET /organizations/{organizationId}/webhooks/alertTypes` |
| SDK | `meraki` (pip) is a Dashboard-API client; no webhook verification (there's no signature) |

## Common alerts

Meraki alerts pair a human label (`alertType`) with a machine id (`alertTypeId`):

| alertType | alertTypeId | Fires when |
| --- | --- | --- |
| Motion detected | `motion_alert` | A camera detects motion |
| Settings changed | `settings_changed` | A configuration setting changes |
| Sensor change detected | `sensor_alert` | A sensor reading crosses a threshold |
| APs went down | `stopped_reporting` | Access points stop reporting |

Branch on `alertTypeId` (stable) rather than `alertType` (a display label). The live catalog for your organization is available via `GET /organizations/{organizationId}/webhooks/alertTypes`.

## Setting up Cisco Meraki webhooks

Configure an HTTP server under Dashboard > Network-wide > Alerts > Webhooks / HTTP servers: set the URL, a shared secret, and optionally a custom payload template. Use "Send test" to post a sample. The endpoint must be HTTPS with a CA-trusted certificate (self-signed certs are rejected).

## Securing Cisco Meraki webhooks

There's no signature to verify. Meraki includes the `sharedSecret` you configured as a field in the JSON body; compare it (in constant time) against your stored value, and rely on TLS for transport authenticity.

```javascript
const crypto = require("crypto");

const SHARED_SECRET = process.env.MERAKI_SHARED_SECRET;

function secretMatches(received) {
  const a = Buffer.from(received || "");
  const b = Buffer.from(SHARED_SECRET);
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

app.post("/webhook", express.json(), (req, res) => {
  if (!secretMatches(req.body.sharedSecret)) {
    return res.sendStatus(401);
  }

  res.sendStatus(200); // acknowledge fast
  processQueue.add(req.body); // process by alertTypeId, async
});

```

The same check in Python:

```python
import hmac
import os

SHARED_SECRET = os.environ["MERAKI_SHARED_SECRET"]

@app.post("/webhook")
def webhook():
    if not hmac.compare_digest(request.json.get("sharedSecret", ""), SHARED_SECRET):
        return "", 401
    # process by alertTypeId, async
    return "", 200

```

Two caveats: the shared secret is optional and travels in plaintext (inside TLS), so it's a lightweight check, not a cryptographic signature; and if you enable a Liquid payload template, the body shape (and even where the secret lands) can change, so verify against your actual template output.

## Cisco Meraki webhook limitations and pain points

### The secret is a body field, not a signature

The Problem: There's no HMAC or signature header. Verification is a plaintext string compare on `payload.sharedSecret`. Any code expecting a signature header does nothing, and the secret is only as strong as TLS keeping the body confidential.

Why It Happens: Meraki's model is a shared-secret body field plus TLS, not payload signing.

Workarounds:

* Compare `payload.sharedSecret` in constant time, require HTTPS with a trusted cert, and treat the check as authentication-lite.

How Hookdeck Can Help: Hookdeck gives you a dedicated ingestion URL and can enforce its own verification and filtering in front of your endpoint, adding a layer beyond a plaintext body secret.

### Custom Liquid templates reshape the payload

The Problem: If a custom template is enabled, the payload (and header) structure can change completely, so code assuming the default schema, or a fixed location for `sharedSecret`, breaks.

Why It Happens: Meraki lets you fully reshape the payload with Liquid templates.

Workarounds:

* Verify against your actual template output, and keep the secret field in a known place if you template the body.

How Hookdeck Can Help: Hookdeck's transformations normalize payloads before they reach your app, so downstream code sees a consistent shape regardless of Meraki templates.

### Auto-disable after failures

The Problem: A receiver is disabled after more than 100 failed attempts in 24 hours. A flaky endpoint silently stops receiving alerts.

Why It Happens: Meraki prunes receivers that consistently fail.

Workarounds:

* Acknowledge fast so transient issues don't accumulate; monitor receiver status and re-enable.

How Hookdeck Can Help: Hookdeck always accepts deliveries and absorbs downstream failures itself, keeping the receiver active while it retries to your service.

### Delivery latency and duplicates

The Problem: Alerts arrive roughly 90 seconds after the event, and can repeat, so don't treat them as instant or exactly-once.

Why It Happens: Meraki batches and retries alert delivery.

Workarounds:

* Dedupe on `alertId`/`occurredAt`, and design for ~90s latency.

How Hookdeck Can Help: Hookdeck deduplicates deliveries at the edge, so repeats don't double-process. See our [guide to webhook idempotency](/webhooks/guides/implement-webhook-idempotency).

## Best practices

### Compare the sharedSecret body field in constant time

Check `payload.sharedSecret` against your configured value with a constant-time comparison, and require HTTPS with a CA-trusted certificate.

### Branch on `alertTypeId`

Route on the stable `alertTypeId`, not the human `alertType` label.

### Account for templates

If you use a Liquid template, verify against its actual output shape.

### Acknowledge fast and dedupe

Return 200 quickly, process off a queue, and dedupe so retries and the ~90s latency don't cause double-processing. See [why to process webhooks asynchronously](/webhooks/guides/why-implement-asynchronous-processing-webhooks).

## Conclusion

Cisco Meraki webhook alerts are verified not by a signature but by a plaintext `sharedSecret` field inside the body, with TLS as the real transport protection, and Liquid templates that can reshape the payload entirely. Compare the secret in constant time, branch on `alertTypeId`, account for templates, and dedupe.

[Hookdeck](https://hookdeck.com) adds verification and filtering beyond the body secret, normalizes templated payloads, deduplicates, and durably queues every alert at the edge, so your app processes trustworthy, consistent events.

[Get started with Hookdeck](https://dashboard.hookdeck.com/signup) for free and handle Cisco Meraki webhooks reliably in minutes.