Organizations

Build B2B multi-tenant applications with organization support.

Overview

Organizations enable B2B (business-to-business) scenarios where your customers have their own teams, members, and settings. Each organization is a separate tenant with its own users, roles, and configuration.

Use Cases

  • SaaS with team features - Allow customers to create teams
  • Enterprise customers - Dedicated tenants for large accounts
  • White-label products - Resellers with their own branding
  • Multi-tenant platforms - Isolated data per organization

Organization Structure

Your Application
├── Organization: Acme Corp
│   ├── Members
│   │   ├── Alice (Owner)
│   │   ├── Bob (Admin)
│   │   └── Carol (Member)
│   ├── SSO Connection (Azure AD)
│   └── Settings
│
├── Organization: Globex Inc
│   ├── Members
│   │   ├── Dan (Owner)
│   │   └── Eve (Member)
│   └── Settings
│
└── Individual Users (no organization)

Creating Organizations

Via API

TypeScript:

const org = await client.auth.organizations.create({
  name: 'Acme Corporation',
  slug: 'acme',
  displayName: 'Acme Corp',
  logo: 'https://acme.com/logo.png',
  metadata: {
    plan: 'enterprise',
    industry: 'technology',
  },
});
 
console.log('Organization ID:', org.id);
console.log('Slug:', org.slug);

Python:

org = client.auth.organizations.create(
    name="Acme Corporation",
    slug="acme",
    display_name="Acme Corp",
    logo="https://acme.com/logo.png",
    metadata={
        "plan": "enterprise",
        "industry": "technology",
    },
)
 
print(f"Organization ID: {org.id}")

User Self-Service

Allow users to create organizations:

// User creates their own organization
const org = await client.auth.organizations.createForUser('user_xxx', {
  name: 'My Company',
  slug: 'my-company',
});
 
// User is automatically the owner

Managing Members

Roles

RoleDescriptionPermissions
OWNERFull control, can delete organizationAll
ADMINManage members and settingsInvite, remove, update settings
MEMBERBasic accessView members, use organization

Add Member

await client.auth.organizations.addMember('org_xxx', {
  userId: 'user_xxx',
  role: 'MEMBER',
  permissions: ['read', 'write'],
});

Update Member Role

await client.auth.organizations.updateMember('org_xxx', 'user_xxx', {
  role: 'ADMIN',
  permissions: ['read', 'write', 'invite'],
});

Remove Member

await client.auth.organizations.removeMember('org_xxx', 'user_xxx');

List Members

const members = await client.auth.organizations.listMembers('org_xxx');
 
for (const member of members) {
  console.log(`${member.user.email}: ${member.role}`);
}

Invitations

Invite users to join an organization.

Send Invitation

const invitation = await client.auth.organizations.invite('org_xxx', {
  email: 'newuser@example.com',
  role: 'MEMBER',
  expiresInDays: 7,
});
 
// Invitation email sent automatically
console.log('Invitation ID:', invitation.id);
console.log('Token:', invitation.token);

Accept Invitation

// When user clicks invitation link
const result = await client.auth.organizations.acceptInvitation({
  token: 'invitation-token',
  userId: 'user_xxx', // Or create new user
});

List Invitations

const invitations = await client.auth.organizations.listInvitations('org_xxx');
 
for (const inv of invitations) {
  console.log(`${inv.email}: ${inv.status}`);
}

Revoke Invitation

await client.auth.organizations.revokeInvitation('org_xxx', 'invitation_xxx');

Domain Verification

Verify domain ownership to enable auto-join and SSO.

Add Domain

await client.auth.organizations.addDomain('org_xxx', {
  domain: 'acme.com',
});

Verify Domain

// Get DNS record to add
const verification = await client.auth.organizations.getDomainVerification('org_xxx', 'acme.com');
// Add TXT record: _transactional-verify.acme.com = "verify-xxx"
 
// Verify
await client.auth.organizations.verifyDomain('org_xxx', 'acme.com');

Auto-Join by Domain

Users with verified domain emails automatically join:

await client.auth.organizations.update('org_xxx', {
  autoJoinDomains: ['acme.com'],
  autoJoinRole: 'MEMBER',
});

Organization SSO

Configure SSO for a specific organization.

const connection = await client.auth.connections.create({
  name: 'Acme SSO',
  type: 'SAML',
  organizationId: 'org_xxx',
  config: {
    // SAML configuration
  },
});

Users authenticating through this connection are automatically added to the organization.

Organization Context

Get Current Organization

When a user is logged in:

// From access token claims
const claims = decodeToken(accessToken);
console.log('Organization:', claims.org_id);
 
// Or from API
const membership = await client.auth.organizations.getCurrentMembership(accessToken);

Switch Organization

Users with multiple memberships can switch:

// List user's organizations
const memberships = await client.auth.users.listOrganizations('user_xxx');
 
// Get token for specific organization
const tokens = await client.auth.tokens.create({
  grantType: 'refresh_token',
  refreshToken: currentRefreshToken,
  organizationId: 'org_xxx', // Switch context
});

Organization Scoped Tokens

Include organization in token claims:

// Authorization request with organization
const authUrl = `https://auth.usetransactional.com/auth?` + new URLSearchParams({
  client_id: 'your_client_id',
  redirect_uri: 'https://yourapp.com/callback',
  organization: 'org_xxx', // Or organization slug
  scope: 'openid profile email',
});

Token includes:

{
  "sub": "user_xxx",
  "org_id": "org_xxx",
  "org_slug": "acme",
  "role": "ADMIN",
  "permissions": ["read", "write", "invite"]
}

Querying Organizations

List Organizations

const orgs = await client.auth.organizations.list({
  count: 50,
  search: 'acme',
});

Get Organization

const org = await client.auth.organizations.get('org_xxx');
// or by slug
const org = await client.auth.organizations.getBySlug('acme');

Update Organization

await client.auth.organizations.update('org_xxx', {
  displayName: 'Acme Inc.',
  logo: 'https://acme.com/new-logo.png',
  metadata: {
    plan: 'enterprise-plus',
  },
});

Delete Organization

await client.auth.organizations.delete('org_xxx');

Organization Settings

Member Limits

await client.auth.organizations.update('org_xxx', {
  memberLimit: 50, // Max members
});

Custom Branding

await client.auth.organizations.update('org_xxx', {
  branding: {
    logo: 'https://acme.com/logo.png',
    favicon: 'https://acme.com/favicon.ico',
    primaryColor: '#0066cc',
  },
});

Permission-Based Access

Fine-grained permissions for organization members:

// Define permissions
const permissions = ['read', 'write', 'delete', 'invite', 'manage_billing'];
 
// Assign to member
await client.auth.organizations.updateMember('org_xxx', 'user_xxx', {
  permissions: ['read', 'write'],
});
 
// Check permission in your app
function hasPermission(membership, permission) {
  return membership.role === 'OWNER' || membership.permissions.includes(permission);
}

Webhooks

Track organization events:

// Subscribe to events
await client.auth.webhooks.create({
  url: 'https://yourapp.com/webhooks',
  events: [
    'organization.created',
    'organization.member.added',
    'organization.member.removed',
    'organization.invitation.accepted',
  ],
});

Next Steps

  • Branding - Custom domains and theming
  • SSO - Organization-specific SSO
  • Webhooks - Organization event notifications