Skip to main content
Naming a tenant on a send is the whole of the API you write. This page is what Courier does after that, and it is where a message picks up the wrong brand when something is set in two places. Courier loads the tenant merged with its parent chain, then picks the brand, resolves preferences, and selects tenant-specific content.

How it works

The tenant object

A tenant stores the defaults for its members. Its fields are an id 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.
A send selects that tenant with context.tenant_id. Courier loads the object above, merged with its parents, and applies the brand, preferences, and templates it names:
The highlighted line is the whole of it. Nothing else in the request changes, and no field repeats what the tenant already stores. covers the other targeting shapes.

Hierarchy and inheritance

Customers often have structure of their own: environments, regions, sites, business units. Set parent_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.
Keep the tree to four levels. 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, and nothing warns you. What inherits down the chain: 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 recipient profile is itself a merge, in this precedence (later wins):
  1. The tenant context (parent chain merged, child over parent).
  2. The user’s stored Courier profile.
  3. The to profile on the send request.

How a send picks a brand

Courier picks the brand in this order, highest first:
  1. brand_id on the send request.
  2. The tenant’s brand_id, the “auto-infer” behavior: set a brand on the tenant and Courier applies it automatically.
  3. The template’s assigned default brand.
  4. The workspace’s default (primary) brand.
To brand messages per customer, set 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 with template: "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:
  1. A recipient’s context.tenant_id.
  2. The message-level context.tenant_id.
  3. A tenant_id recipient (fan-out to members).
A tenant loads its context (brand, preferences, templates) and scopes preference lookups to that tenant. It does not change channel or provider routing, which stays workspace-and-environment scoped. covers every targeting shape.

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 returns Tenant Context Not Found. Turn auto-infer off in workspace settings.

Tenant-scoped inbox

The scopes to a tenant only when you pass a tenantId 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. Set context.tenant_id.
  • The wrong brand renders. An explicit brand_id on the send, or the tenant’s own brand_id, overrides the workspace primary brand. To use the tenant’s brand, set brand_id on 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. Pass tenantId at signIn.
  • 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_id and the sign-in tenantId must match.

FAQ

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.
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.
Tenant templates are managed through the API, not the console. No screen creates, lists, or deletes them. Use the tenant templates endpoints. See .