requestId, and the message moves through a status lifecycle you track in the logs.
How it works
The status lifecycle
A message’s status only advances, never backward. Two independent systems drive it. Provider confirmation producesDELIVERED. Courier tracking produces OPENED and CLICKED, so engagement can arrive before or without a delivery confirmation.
Open a message in the to see its provider response.
Send API responses
A successful send returns arequestId you use to track the message:
message and a type:
The most common
400 on /send is Either 'content' or 'template' must be defined. Send one, not both. Next most common are a missing to, or a list_id/audience_id that does not exist. A 413 means the request exceeded the 6 MB payload limit. Host attachments externally and pass URLs in data rather than base64.
Limits
is not rate-limited by request count, so you can send at volume. Its request body caps at 6 MB, as does . Every other endpoint caps at 1 MB. A few management endpoints are rate-limited per workspace. Their responses carryX-RateLimit-Limit and X-RateLimit-Remaining so you can pace requests. Exceeding a limit returns 429 Too Many Requests:
Endpoints not listed here are not request-count limited today.
Send limits
Send limits cap how many messages a user, topic, or tenant receives in a window. They are a separate feature from API rate limits. A message blocked by one shows asTHROTTLED in the log instead of delivering.
The Developer plan’s 10,000-sends-per-period cap produces the same THROTTLED status. That drop happens after the API has already returned 202, so there is no synchronous error and the requestId looks healthy. A THROTTLED message you did not configure a limit for usually means the plan cap.
Why a message is UNROUTABLE
UNROUTABLE is one status with several causes. Open the message in and read its reason:
The timeline then shows one attempt per provider, each with its own
reason for being skipped:
To audit in bulk, list the failures over the API:
Debug other statuses
- Stuck at
SENT: delivery tracking is not configured for that channel, not a failure. See delivery tracking. FILTERED: preferences, send conditions, or routing removed the message. Check the recipient’s .UNDELIVERABLE: the provider rejected it. The timeline shows the provider’s error.
message:updated .
Delivery tracking is per provider
DELIVERED only appears when the provider tells Courier the message landed. That reporting is off until you set it up, per provider. Until then a healthy send stops at SENT. This is the most common reason a working integration looks broken.
A provider reports in one of four ways:
Providers absent from this table send no delivery confirmation, so their messages stop at
SENT by design. Where both a webhook and polling are offered, prefer the webhook. It is real time and needs no extra provider permissions.
Limits & behavior
- Status is monotonic. A message never moves backward. Engagement can still follow a terminal delivery status.
/sendis not count-rate-limited. A few management endpoints are. Send limits govern message volume and produceTHROTTLED.- The
/sendpayload cap is 6 MB. Other endpoints cap at 1 MB. Pass attachment URLs indatainstead of inlining large files.
FAQ
What does UNROUTABLE mean?
What does UNROUTABLE mean?
Courier found no valid route: the recipient had no address for the routed channel, or no channel was configured for the send. Check the recipient’s profile and the send’s routing.
My message is stuck at SENT. Did it fail?
My message is stuck at SENT. Did it fail?
Usually not.
SENT means Courier handed it to the provider and got no delivery confirmation back. That usually means delivery tracking is not set up for that channel.Is the Send API rate-limited?
Is the Send API rate-limited?
Not by request count. You can send at volume. A few management endpoints are limited (see the table above). Send limits (per user, topic, or tenant) govern message volume and mark blocked messages
THROTTLED.Why did I get a 413?
Why did I get a 413?
The request exceeded the body-size cap: 6 MB on
/send and /automations/invoke, 1 MB on every other endpoint. Host attachments externally and pass their URLs in data. Base64 inflates size by about a third.