If you pass --api-key on a command, it takes priority over the environment variable. This is useful for testing against a different workspace without changing your shell config. See Global Flags for all available flags.
You don’t need a template to send your first notification. Pass the content inline and Courier handles the rest.Send an email directly
courier send message \ --message.to.email "alex@example.com" \ --message.content.title "New comment on your design file" \ --message.content.body "Sara left a comment on Homepage Redesign: 'Love the new hero section — can we try a darker background?'"
Send across multiple channelsRoute a notification to email first, then fall back to SMS if email can’t be delivered. See channel priority for how Courier evaluates routing order.
courier send message \ --message.to.email "alex@example.com" \ --message.to.phone_number "+15551234567" \ --message.content.title "New login detected" \ --message.content.body "We noticed a new login to your account from {{city}}, {{country}}. If this wasn't you, reset your password immediately." \ --message.data '{"city": "San Francisco", "country": "US"}' \ --message.routing.method "single" \ --message.routing.channels '["email", "sms"]'
Send using a templateOnce you’ve built a template in the Courier dashboard, reference it by ID or alias.
Courier needs to know where to reach your users. Create profiles with their contact info so you can send by user_id instead of passing email and phone every time.Create a user profile
Every notification gets a message ID. Use it to check delivery status, inspect rendered content, or trace the full delivery timeline.Get the status of a sent notification
courier messages retrieve --message-id "1-abc123"
View the full delivery timelineSee every step a notification went through (queued, sent, delivered, opened, clicked) with timestamps.
courier messages history --message-id "1-abc123"
See what was actually renderedCheck the final content Courier sent to the provider, after all template variables and routing logic were applied.
When a user reports they didn’t get a notification, run these in sequence to narrow it down.Find the notificationPull recent notifications for a specific user.
courier messages list --format json \ --transform "results.#(recipient==user-123)"
Inspect the notificationCheck the status. Look for DELIVERED, SENT, UNDELIVERABLE, or UNROUTABLE.
Trace the delivery stepsThe history shows exactly where things went wrong: did the provider reject it? Did routing skip a channel? Did a preference rule block it?
courier messages history --message-id "1-abc123" --format pretty
Verify the user’s profileIf the notification is UNROUTABLE, the user’s profile is probably missing channel data.
Automations let you orchestrate multi-step notification sequences (delays, conditions, batching) without writing that logic in your app.Invoke a saved automation
Let users control what they receive. Preferences are enforced at send time; Courier won’t deliver a notification if the user has opted out of that topic.Check a user’s current preferences
The CLI works as a zero-config tool for AI agents in Cursor, Claude Code, Codex, and similar environments. Install once, set COURIER_API_KEY, and agents can run Courier operations directly via shell commands. Every command supports --format json for machine-readable output.