covers the concepts behind this page.
to.tenant_id, or on the message as context.tenant_id. Pick one and put it behind a shared helper, because tracking down a message that rendered with the wrong brand is a great deal harder when two call sites disagree about where the tenant lives.
Prerequisites
Send to a user with tenant context
Setcontext.tenant_id on a recipient to attach the tenant’s metadata, preferences, and branding to their message. User-level preferences and profile data take precedence over the tenant’s.
The template holds the content. Pass the variables it expects in data, and reference tenant values like {$.tenant.name} from inside the template, where the tenant context resolves them.
Send to every member of a tenant
Put atenant_id in to and Courier looks up the tenant’s members and sends to each one.
Send to multiple users with shared context
When sending to an array of users, set a shared tenant at the message level withmessage.context.tenant_id. Every recipient inherits it. Override it for a specific recipient by setting context.tenant_id on that entry, which takes precedence over the message-level context.
user_123 and user_456 get Acme Corp’s context, while user_456 gets Beta Inc’s.
Handle users in multiple tenants
Courier infers the tenant for a user who belongs to exactly one tenant, so specifying it is optional for them. A user with two or more memberships must havecontext.tenant_id set, or the send returns Tenant Context Not Found.
Fan out across a hierarchy
Setinclude_children: true to also send to users in a tenant’s descendant tenants, or include_parent: true to walk upward through its ancestors.
On Go and C#,
include_children and include_parent aren’t in the typed recipient models yet, so the tabs above set them as extra fields on the recipient. Every other operation on this page has a fully typed Go and C# form.Segment delivery data by customer
Courier records the tenant on the message atproviders[].reference.tenantId, so you can group logs and delivery data by customer after the fact. Read it from the or from a .
A send that never named a tenant carries no reference, which is one more reason to route every multi-tenant send through the same helper.
Limits & behavior
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 the user belongs to exactly one tenant and the send specifies none, Courier loads that tenant’s context anyway. See , and turn it off in workspace settings if you would rather send unscoped.
- A tenant-scoped inbox message is invisible to a client signed in without the tenant. The send reports success and the feed stays empty. Pass the same
tenantIdtosignInthat your sends carry. - Hierarchy traversal stops at four levels. The window starts at the tenant you sent to rather than at the root, so a fifth ancestor’s settings never reach the message.
Verify
1
Send with a branded tenant
Send with a tenant that has a
brand_id set, and confirm the message renders with that tenant’s brand (see ).2
Check the message log
Confirm the send used the tenant’s preferences, not the workspace defaults.
3
Confirm fan-out delivery
For a fan-out send, confirm each expected member received a copy.