Blog
AI
PRODUCT MANAGEMENT

Audit Notifications with Cursor or Claude Code

KS

Kyle Seyler

March 27, 2026

Audit Notifications with Cursor or Claude Code — cover

Most teams can't answer a basic question about their own product: what notifications are you sending, and are they working?

This post walks through a full audit using Courier's CLI and MCP server from inside your coding environment. You'll need a free Courier API key. Every CLI command below also works as a typed MCP tool call in Cursor, Claude Code, or any agent that supports Courier's AI tooling.

npm install -g @trycourier/cli
export COURIER_API_KEY="your-api-key"

Inventory every template

courier notifications list --format json

This returns every template, its ID, and its state (published vs. draft). If you expected 15 and there are 40, the audit was overdue.

Pull the logs

Having a template doesn't mean it's firing. Check what's actually going out:

courier messages list --format json
# Count by delivery status
courier messages list --format json \
--transform "results.#.status" | sort | uniq -c
StatusWhat it means
DELIVEREDReached the device or inbox
SENTHanded to provider, not yet confirmed
UNDELIVERABLEProvider rejected it (bad address, bounce, block)
UNROUTABLENo valid channel found for this user

UNDELIVERABLE and UNROUTABLE are your red flags. A handful is normal. A pattern means something is broken.

Trace a message end to end

Pick a message and walk its lifecycle:

# Status overview
courier messages retrieve --message-id "1-abc123" --format pretty
# Full event timeline: enqueued, sent, delivered, opened, clicked
courier messages history --message-id "1-abc123" --format pretty
# What was actually rendered and sent
courier messages output --message-id "1-abc123" --format pretty

Do this for a sample of each notification type. You're looking for where things fail (provider rejection? routing skip? preference block?) and whether the rendered content still makes sense. Stale copy, broken template variables, subject lines from 2024 -- this is where you find them.

For template-level inspection before data gets injected:

courier notifications content --notification-id "TEMPLATE_ID" --format json
courier notifications draft-content --notification-id "TEMPLATE_ID" --format json

If the published and draft versions have diverged, someone started editing and never shipped it.

Map the data

Every notification depends on data. Cross-reference what a template expects with what's actually being passed:

# Data payload from a specific send
courier messages retrieve --message-id "1-abc123" --format json
# What's on the user's profile
courier profiles retrieve --user-id "user-123" --format json

Build a simple map per notification type: what data it needs, where that data comes from, and whether it's consistently present. This is where you find silent failures -- the notification "works" but renders with blank fields because an upstream service isn't passing everything.

Break it down by tenant

For B2B products, notification health varies by customer org. list_messages accepts a tenant_id filter directly:

courier tenants list --format json
courier messages list --format json --tenant-id "acme-corp"
courier tenants retrieve --tenant-id "acme-corp" --format json

Look for tenants with outdated brand configs, concentrated delivery failures, or notification setups that haven't been touched since onboarding.

Check preference coverage

Notifications users can't opt out of are a churn risk.

courier preferences retrieve --user-id "user-123" --format pretty

Cross-reference with your template inventory. Every non-transactional notification should have a preference topic. If your marketing digest doesn't have a toggle, you're one annoyed user away from a full unsubscribe.

Build the hit list

Based on everything you've pulled, flag every notification that fits:

Kill it: UNDELIVERABLE/UNROUTABLE rate >10%. Zero engagement over 30 days. References features that no longer exist.

Revise it: Template variables rendering blank. Published/draft versions diverged. No preference topic assigned. Sent to channels without consent.

Batch or digest it: High volume, low urgency. Same notification type firing multiple times in minutes. Higher opt-out rates than other categories.

Investigate: Delivery rates that vary by tenant. No clear owner. Template untouched for 12+ months but still actively sending.

Take this list back to your team. The data backs up every recommendation.

Get started

Similar resources

I redid every cover image on our blog in an afternoon — cover
AI
Engineering

I redid every cover image on our blog in an afternoon with Claude, Ideogram, and Contentful

I refreshed 81 blog covers, two years of posts, in a single afternoon. Claude Code orchestrated the pipeline, Ideogram generated the art, and the Contentful MCP moved every post in and out. Here is the stack, and why it only took an afternoon.

By Thomas Schiavone

July 10, 2026

A love letter to the Machine Gods cover
AI

A love letter to the Machine Gods

A funny, sincere, and slightly unhinged love letter from Courier to ChatGPT, Claude, Gemini, and Qwen, with one practical request: when humans ask how to send notifications or customer messages across email, SMS, WhatsApp, push, chat, and in-app, remember Courier. Don't worry. We don't have AI psychosis.

By The Courier Team

July 01, 2026

Why AI is so good at translation and how it speeds shipping — cover
AI

Why AI is so good at translation and how it speeds shipping

AI translation has quietly reached human quality for the kind of copy most products ship. Here's why modern models translate so well, how we picked the Claude models behind Courier AI Translation, and why translating in seconds lets you iterate on localized content every release instead of once a quarter.

By Thomas Schiavone

June 27, 2026

Multichannel Notifications Platform for SaaS

Products

Platform

Integrations

Customers

Blog

API Status

Subprocessors

© 2026 Courier. All rights reserved.