What tenants are for
White-label the notifications each customer receives
White-label the notifications each customer receives
Every customer sees their own logo, colors, and sender identity. Attach a to the tenant and Courier applies it whenever you send to a user in that tenant, with no change to the template.
Let each customer set their own notification defaults
Let each customer set their own notification defaults
A tenant carries default for its topics. One customer starts opted out of product announcements, another makes billing alerts required. Their users can still change their own.
Give one customer a different version of a message
Give one customer a different version of a message
A overrides the workspace template for that tenant only. Use it when a customer needs different wording, an extra legal line, or their own layout.
Notify everyone in a customer's organization
Notify everyone in a customer's organization
Send to a
tenant_id instead of a user and Courier fans out to its members. Tenants can nest through parent_tenant_id, so a send can walk the hierarchy up or down. See .Model teams, projects, or workspaces inside your product
Model teams, projects, or workspaces inside your product
A tenant does not have to be a company. It maps to whatever unit your product bills or brands: a team, a project, a store, a region.
What you store on a tenant
Anything that is true about a customer organization rather than about a particular notification.
Without a tenant, all of that gets looked up and assembled in front of every send. With one, you pass an id and Courier resolves the rest.
Put event-specific values in
data. Put customer-level values in the tenant’s properties. A support address that arrives in data on every send is one that belongs in properties once.
What a tenant is not
A tenant is not a way to group recipients. If what you want is “send this to these people”, use a . A tenant scopes branding and settings to one customer. To send to a group of users, use a list or an audience. A tenant is not an environment. Use to separate test traffic from production. Tenants divide your customers, not your pipeline. Tenant membership is not permissions. Being in a tenant decides which context Courier builds a message from, and nothing about what that user may do. Authorization stays in your application.How it works
You address a user, and name the tenant that user is acting in. See for the resolution order. Anything the tenant does not define falls through to the workspace default, so you only configure the differences. A user can belong to as many tenants as you need, and each membership is independent. Someone who works with two of your customers can have alerts on at Acme and off at Beta. They see Acme’s branding in one email and Beta’s in the next, with a separate inbox feed on each side.Three things that fail quietly
None of these raise an error, which is what makes them worth knowing before you ship. Courier can apply a tenant you did not name. If a user belongs to exactly one tenant and your send specifies none, Courier loads that tenant’s context anyway. It is a workspace setting, useful for console, list, and audience sends, and confusing the first time a customer’s branding turns up on a message you thought was unscoped. See . Tenant-scoped inbox messages are invisible to clients signed in without the tenant. A message sent withtenant_id: "acme-corp" only appears when the client called signIn with the same tenantId. Sign in without it and the feed is empty, while the send itself reports success.
The fifth level of a hierarchy is dropped. Courier loads tenant context as a four-layer sliding window. It starts at most three ancestors up rather than at the root, so in a five-deep tree the top tenant’s settings never reach a leaf send.
Limits & behavior
Channels, providers, and API keys are never tenant scoped. Configure a provider such as SendGrid once, and every tenant shares it. A tenant cannot hold its own integration credentials, though it can carry a customer’s own Slack token or Teams webhook inuser_profile, which merges into the recipient at send time.
Keep hierarchies to four levels. Deeper than that and the sliding window above drops the root, so nothing important should sit at the top of a deep tree.
Tenants work normally inside an EU workspace. Only creating a new workspace is unavailable in that region. See .
FAQ
Do I need tenants for a single-customer app?
Do I need tenants for a single-customer app?
Tenants serve multiple customer organizations from one account, as in B2B SaaS or white-label products. A single-customer app needs one workspace and no tenants.
Does a tenant need its own template for every notification?
Does a tenant need its own template for every notification?
A tenant inherits every workspace template by default. Create a only for the messages that customer needs to differ.
Can a user belong to more than one tenant?
Can a user belong to more than one tenant?
If the user belongs to exactly one tenant, Courier infers it. With two or more memberships you must set
context.tenant_id, or the send fails with Tenant Context Not Found. See .Where do I put the tenant on a send?
Where do I put the tenant on a send?
Either
to.tenant_id on the recipient or message.context.tenant_id. Both behave identically, so pick one and put it behind a shared helper. uses the context form throughout.