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. In objects such as properties and user_profile, a child overrides only the keys it sets, 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).
default_preferences inherits as one list, not topic by topic. A child with no default_preferences items uses its parent’s list. A child that sets any items replaces the parent’s list entirely, and topics missing from it fall back to their workspace default.
To override one topic and keep the rest, give the child the full list: copy the parent’s items and change the topic you need. Update the child when the parent’s list changes, because the child no longer reads it.
What inherits, and what doesn’t
Channels, providers, and API keys do not inherit, because they aren’t tenant fields. You configure a provider (SendGrid, a Slack integration) once per environment, and every tenant there uses it. A parent tenant can’t hold an access token for its children to inherit.user_profile is where a customer’s own provider details go. Sends that name the tenant route through their Slack workspace instead of yours, or reach their Microsoft Teams organization through your bot with ms_teams fields such as tenant_id and service_url. You store them once per organization rather than once 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 only messages sent without a tenant. Auto-infer doesn’t apply to the inbox client. See .
Troubleshooting
- A send fails with
Tenant Context Not Found. The user belongs to more than one tenant and the send didn’t 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. - A message sent without a tenant doesn’t appear in the inbox. The client signed in with a
tenantId, so it shows only that tenant’s messages. Sign in without atenantIdto see messages sent without one. - A user doesn’t see a tenant message in their inbox. The message went to a tenant the client isn’t 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. Default preferences inherit as a whole list, so a child that sets any items replaces the parent’s list. Channels, providers, and API keys don’t, 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 .