How it works
The tenant object
A tenant stores the defaults for its members. Its fields are anid you choose (like acme-corp), a name, an optional parent_tenant_id, a brand_id, default_preferences, free-form properties, and a user_profile that merges into recipients.
Tenants hold no channels, providers, or API keys of their own. Those are workspace-and-environment concepts every tenant shares.
context.tenant_id. Courier loads the object above, merged with its parents, and applies the brand, preferences, and templates it names:
Hierarchy and inheritance
Customers often have structure of their own: environments, regions, sites, business units. Setparent_tenant_id to nest one tenant inside another and Courier walks the chain when it builds a message. You still send a single tenant_id, the deepest one.
The merge walks top-down, parent first, and child values override parent values on conflicting keys. A child starts from everything its ancestors define and overrides only what it needs, so a Slack token set once at the top serves every tenant beneath it.
brand_id, default_preferences, tenant templates, properties, and user_profile (deep-merged key by key).
What inherits, and what does not
Channels, providers, and API keys do not inherit, because they are not tenant fields. You configure a provider (SendGrid, a Slack integration) once per environment, and every tenant there uses it. A parent tenant cannot hold an access token for its children to inherit.user_profile is where a customer’s own provider credentials go. Sends that name the tenant route through their Slack workspace or Teams webhook instead of yours, so you store one token per organization rather than one per user.
- The tenant context (parent chain merged, child over parent).
- The user’s stored Courier profile.
- The
toprofile on the send request.
How a send picks a brand
Courier picks the brand in this order, highest first:brand_idon the send request.- The tenant’s
brand_id, the “auto-infer” behavior: set a brand on the tenant and Courier applies it automatically. - The template’s assigned default brand.
- The workspace’s default (primary) brand.
brand_id on the tenant and send in that tenant’s context. Courier falls back to the primary brand only when no higher layer names one. For template sends, the template must have its brand enabled.
Tenant templates
A tenant template is a tenant’s own version of a template, stored separately and linked to the tenant. Courier merges its content over the message at send time, then routes normally. Reference one withtemplate: "tenant/<template_id>", where tenant is the literal word and the tenant comes from the context. Tenant templates are API-only. See .
Setting tenant context on a send
Courier resolves which tenant a send uses in this order:- A recipient’s
context.tenant_id. - The message-level
context.tenant_id. - A
tenant_idrecipient (fan-out to members).
Auto-infer tenant context
If a send names no tenant and the user belongs to exactly one, Courier loads that tenant’s context. This helps console, list, and audience sends where brand or provider data lives on the tenant. A user with two or more memberships must have the tenant specified, or the send returnsTenant Context Not Found. Turn auto-infer off in workspace settings.
Tenant-scoped inbox
The scopes to a tenant only when you pass atenantId at signIn. That applies to every inbox read and the live socket for the session. Sign in without a tenantId and the inbox shows the user’s notifications across all tenants. There is no client-side auto-infer for the inbox. See .
Limits & behavior
- Hierarchy merges up to four levels. The window slides from the tenant you sent to, not from the root, so in a deeper tree the topmost tenant’s settings are dropped with no error.
- Auto-infer is single-membership only. With multiple memberships, always pass
tenant_id. - Tenant templates are API-only. No console UI creates, lists, or deletes a tenant’s templates.
Troubleshooting
- A send fails with
Tenant Context Not Found. The user belongs to more than one tenant and the send did not specify one. Setcontext.tenant_id. - The wrong brand renders. An explicit
brand_idon the send, or the tenant’s ownbrand_id, overrides the workspace primary brand. To use the tenant’s brand, setbrand_idon the tenant and confirm the template has its brand enabled. - The inbox shows notifications from other tenants. The client signed in without a
tenantId, so no tenant filter applied. PasstenantIdatsignIn. - A user does not see a tenant message in their inbox. The message went to a tenant the client is not signed in with. The send
tenant_idand the sign-intenantIdmust match.
FAQ
Does a child tenant inherit its parent's brand and preferences?
Does a child tenant inherit its parent's brand and preferences?
Courier merges a tenant with its parent chain (up to four levels), child over parent. Brand, default preferences, tenant templates, properties, and user profile inherit. Channels, providers, and API keys do not, because they are workspace-and-environment scoped, not tenant fields.
Why does Courier use the primary brand instead of my tenant's brand?
Why does Courier use the primary brand instead of my tenant's brand?
Courier falls back to the workspace primary brand only when the send, the tenant, and the template all name none. Set
brand_id on the tenant, send in that tenant’s context, and confirm the template has its brand enabled.Why don't my tenant templates show in the console?
Why don't my tenant templates show in the console?
Tenant templates are managed through the API, not the console. No screen creates, lists, or deletes them. Use the tenant templates endpoints. See .