Courier (trycourier)
raw JSON → 7.9.0 verified Tue May 12 auth: no python install: verified quickstart: stale
Python SDK for Courier notification API (multi-channel: email, SMS, push, in-app). Current version is 7.9.0. Install name is trycourier (pip install trycourier) but import name changed to courier in v5+ (from courier.client import Courier). The SDK was completely rewritten with Fern code generation in v5, breaking all v4 code.
pip install trycourier Common errors
error ModuleNotFoundError: No module named 'trycourier.client' ↓
cause The import path for the Courier SDK changed from `trycourier.client` to `courier.client` starting from version 5.0.0.
fix
from courier.client import Courier
error AttributeError: 'Courier' object has no attribute 'send_message' ↓
cause The method for sending notifications was renamed from `send_message` (or `send`) to `send_notification` in SDK version 5.0.0.
fix
client.send_notification(recipient_id="RECIPIENT_ID", event_id="EVENT_ID", data={"key": "value"})
error TypeError: send_notification() missing 2 required positional arguments: 'recipient_id' and 'event_id' ↓
cause The `send_notification` method in SDK v5+ requires explicit `recipient_id` and `event_id` arguments, replacing the single `message` dictionary from older versions.
fix
client.send_notification(recipient_id="YOUR_RECIPIENT_ID", event_id="YOUR_EVENT_ID", data={"key": "value"})
error courier.exceptions.CourierAuthError: Not Authorized ↓
cause The Courier API key used for authentication is missing, invalid, or lacks the necessary permissions.
fix
Ensure the
COURIER_AUTH_TOKEN environment variable is correctly set or pass a valid authorization_token when initializing the Courier client. Warnings
breaking Install name (trycourier) and import name (courier) differ since v5. pip install trycourier then from courier.client import Courier. LLMs frequently generate from trycourier import Courier which raises ImportError on v5+. ↓
fix pip install trycourier then import from courier: from courier.client import Courier
breaking Complete API rewrite in v5 using Fern code generation. v4 API (Courier(auth_token=), client.send(event=, recipient=, data=)) is completely gone. All v4 code raises ImportError or AttributeError on v5+. ↓
fix Migrate to: from courier.client import Courier; client = Courier(authorization_token=...); client.send(message=courier.TemplateMessage(template=..., to=courier.UserRecipient(...)))
breaking auth_token= parameter renamed to authorization_token= in v5. Passing auth_token= raises TypeError. ↓
fix Replace Courier(auth_token='...') with Courier(authorization_token='...') or set COURIER_AUTH_TOKEN env var.
breaking Resource-scoped methods introduced in v5. Old flat methods like courier.deleteBrands() replaced with courier.brands.delete(). All flat method calls raise AttributeError. ↓
fix Use resource-scoped API: client.brands.delete(...), client.lists.get(...), etc.
gotcha The COURIER_AUTH_TOKEN environment variable is read automatically if authorization_token= is not passed. Useful for 12-factor apps but can cause silent auth failures if the wrong env var is set. ↓
fix Set COURIER_AUTH_TOKEN in your environment, or pass authorization_token= explicitly. Verify with: python -c "import os; print(os.environ.get('COURIER_AUTH_TOKEN'))"
Install compatibility verified last tested: 2026-05-12
python os / libc status wheel install import disk
3.10 alpine (musl) - - - 36.3M
3.10 slim (glibc) - - - 36M
3.11 alpine (musl) - - - 39.5M
3.11 slim (glibc) - - - 39M
3.12 alpine (musl) - - - 31.0M
3.12 slim (glibc) - - - 31M
3.13 alpine (musl) - - - 30.6M
3.13 slim (glibc) - - - 30M
3.9 alpine (musl) - - - 35.6M
3.9 slim (glibc) - - - 35M
Imports
- Courier wrong
# Old v4 import pattern (broken in v5+): from trycourier import Courier client = Courier(auth_token='YOUR_TOKEN') client.send( event='notification-id', recipient='recipient-id', data={'name': 'Alice'} )correct# Current v5+ API (import from courier, not trycourier) from courier.client import Courier import courier client = Courier(authorization_token='YOUR_COURIER_AUTH_TOKEN') response = client.send( message=courier.ContentMessage( to=courier.UserRecipient(email='user@example.com'), content=courier.ElementalContent( version='2020-01-01', elements=[courier.ElementalNode_Text(content='Hello!')] ), routing=courier.Routing(method='all', channels=['email']) ) ) print(response.request_id)
Quickstart stale last tested: 2026-04-23
# pip install trycourier
from courier.client import Courier
import courier
client = Courier(
authorization_token='YOUR_COURIER_AUTH_TOKEN'
# or set env var COURIER_AUTH_TOKEN
)
# Send using a template (workflow)
response = client.send(
message=courier.TemplateMessage(
template='your-template-id', # template ID from Courier dashboard
to=courier.UserRecipient(
email='user@example.com',
user_id='user-123'
),
data={
'name': 'Alice',
'action_url': 'https://yourapp.com'
}
)
)
print('Request ID:', response.request_id)
# Async client
from courier.client import AsyncCourier
import asyncio
async def send():
async with AsyncCourier(authorization_token='YOUR_TOKEN') as client:
await client.send(message=courier.TemplateMessage(
template='your-template-id',
to=courier.UserRecipient(email='user@example.com')
))
asyncio.run(send())