Skip to content

Multi-Tenancy

Every resource in Jina Connect is scoped to a Tenant — an isolated organization. Tenants have:

FieldDescription
nameOrganization name
descriptionOptional description
walletCredit balance for messaging
countryISO country code
stateISO state code
verticalIndustry classification (26 choices: healthcare, education, fintech, etc.)

All querysets are automatically filtered by tenant. The pattern used across the codebase:

class TenantScopedViewSet(ModelViewSet):
def get_queryset(self):
tenant = self.request.user.tenant_user.tenant
return self.model.objects.filter(tenant=tenant)

Resources are never accessible across tenants. This applies to contacts, templates, messages, broadcasts, media, tags, and all other models.

Every new tenant gets 5 system roles (cannot be deleted):

RolePriorityPermissions
Owner0Full access to everything
Admin10Everything except tenant deletion and owner management
Manager20Broadcast, contacts, templates, team inbox management
Agent30Team inbox, contact viewing, message sending
Viewer40Read-only access to all resources

Tenants can create custom roles with granular permissions:

# Permission format: "app.action"
RolePermission.objects.create(
role=custom_role,
permission_key="broadcast.create",
allowed=True
)

Permission keys follow the pattern {app}.{action}:

  • broadcast.create, broadcast.view, broadcast.delete
  • contacts.create, contacts.view, contacts.edit, contacts.delete
  • templates.create, templates.view, templates.edit
  • team_inbox.view, team_inbox.assign, team_inbox.close
  • settings.view, settings.edit

Lower priority number = higher authority. A user with priority 20 can manage users with priority 30+ but not those with priority 10 or lower.

Users are linked to tenants via TenantUser:

User ←→ TenantUser ←→ Tenant
TenantRole

A single User can belong to multiple tenants (multi-org support), each with a different role.

TenantAccessKey provides API key authentication for:

  • MCP server tool access
  • External system integrations
  • Webhook subscriptions
# API key resolves to (Tenant, TenantWAApp)
tenant, wa_app = resolve_tenant(api_key)

Keys are generated per-tenant and can be rotated without affecting JWT auth.

Each tenant gets isolated instances of:

ResourceModelDescription
WhatsApp AppTenantWAAppBSP config, credentials, pricing, daily limits
Telegram BotsTelegramBotAppBot tokens, webhook secrets
SMS AppsSMSAppProvider config, sender ID, DLT fields
RCS AppsRCSAppProvider config, agent ID, SMS fallback
ContactsTenantContactPhone, name, tags, lead status, assignment
TemplatesWATemplateMessage templates with approval lifecycle
BroadcastsBroadcastCampaigns with recipient lists
TagsTenantTagsCustom categorization labels
MediaTenantMediaUploaded files with platform-specific handles
BrandingBrandingSettingsFavicon, logos (singleton per tenant)