Reference
Message streams
Somebody who reports your newsletter as spam has said something about newsletters. Stopping their password reset because of it is a worse failure than the complaint. A stream is that separation.
Every account starts with one
Your account has a transactional stream from the moment it exists, and a send that names no stream lands there. You can create others and name one per send.
An unknown stream is refused, never defaulted. Naming a stream tells us which suppression list applies to the send. Quietly using a different one because the slug was mistyped is how a complaint stops protecting anybody.
What a stream does and does not escape
This is the part worth reading twice. Which suppressions a stream escapes is decided by the reason, not by the stream:
| Reason | Applies to | Why |
|---|---|---|
complaint, unsubscribe | The stream that earned it | They are statements about a kind of mail. This is the point of the feature. |
hard_bounce, spam_trap | Every stream, always | A dead mailbox is a fact about the address. Continuing to send to it from another stream is the fastest way to lose sending reputation. |
manual | Your choice; every stream by default | “Stop sending to this person” usually means all of it, so that is the safer reading. |
A stream is not a way around the suppression list. Ask us to confine a hard bounce to one stream and we will store it account-wide anyway. Never sending to a suppressed address is the rule this platform is built on, and a feature that punched a hole in it would not be worth having.
Endpoints
/v1/streamsstreams:read/v1/streamsstreams:writeA slug is lowercase letters, digits and single hyphens — it goes into your code, so it has to stay typeable and stay stable. transactional is reserved.
Filter the message log by stream with ?stream=product-updates.
How many streams you may have is set by your plan, and the transactional stream counts: Free 1, Starter 3, Growth 10, Scale 25, Enterprise unlimited. So a plan listing one stream is a plan on which this endpoint refuses, with 403 and "type": "stream_limit_reached". The full grid is in limits.
Examples
POST /v1/streams
{ "slug": "product-updates", "name": "Product updates" }
201 {
"id": "str_AZLm3kQ8T2Sf9pXbNc7HrQ",
"slug": "product-updates",
"name": "Product updates",
"isDefault": false
}NextTags and metadata →Label a message with your own vocabulary, get it back on the log and every webhook, and filter by it.