Multi-Organization Benefits

Crane Ledger's multi-organization architecture is designed to handle the complex financial structures of modern businesses. Whether you're an accounting firm serving hundreds of clients, an enterprise with multiple subsidiaries, or a SaaS platform with per-customer accounting, Crane Ledger's organization hierarchy provides the flexibility and isolation you need.

Organization Hierarchy Overview

Master vs Sub-Organizations

Master Organization (Root)
├── Billing Root
├── Credit Pool Owner
└── Can have unlimited sub-organizations

Sub-Organizations (Children)
├── Isolated or shared data
├── Shared billing with master
├── Custom configurations
└── Hierarchical relationships

Relationship Types

Owned Relationships (Consolidated)

  • Data Sharing: Financial data rolls up to parent
  • Consolidated Reporting: Unified financial statements
  • Perfect For: Corporate groups, subsidiaries, departments

Linked Relationships (Isolated)

  • Data Isolation: Complete separation of financial data
  • Independent Reporting: Separate financial statements
  • Perfect For: Client isolation, separate legal entities

Accounting Firm Benefits

Client Data Isolation & Compliance

Perfect Client Separation

// Create client organization
const clientOrg = await crane.organizations.createSub({
  parent_organization_id: firmMasterOrg.id,
  organization_name: `${client.name} Accounting`,
  relationship_type: 'linked',        // 🔒 Complete data isolation
  billing_type: 'shared',             // 💳 Firm manages billing
  base_currency_code: client.currency
});

Benefits:

  • Regulatory Compliance: Client data completely separated
  • Audit Protection: No risk of cross-client data leakage
  • Custom Configurations: Different settings per client
  • Centralized Billing: Firm manages all API costs, can allocate internally

Multi-Client Portal Architecture

class AccountingPortal {
  constructor(firmApiKey) {
    this.firmApiKey = firmApiKey;
  }

  async createClient(clientData) {
    // 1. Create isolated organization
    const clientOrg = await this.createClientOrg(clientData);

    // 2. Set up chart of accounts
    await this.setupClientChart(clientOrg.id, clientData.industry);

    // 3. Create client API key for portal access
    const clientKey = await this.createClientApiKey(clientOrg.id);

    // 4. Configure billing
    await this.setupClientBilling(clientOrg.id, clientData.billing);

    return { clientOrg, clientKey };
  }

  async getFirmOverview() {
    // Consolidated view across all clients
    const clients = await crane.organizations.list({
      parent_id: this.firmOrgId
    });

    const overview = {
      totalClients: clients.length,
      totalRevenue: 0,
      totalExpenses: 0,
      activeProjects: 0
    };

    // Aggregate metrics (without accessing client data)
    for (const client of clients) {
      const metrics = await this.getClientMetrics(client.id);
      overview.totalRevenue += metrics.revenue;
      overview.totalExpenses += metrics.expenses;
      overview.activeProjects += metrics.projects;
    }

    return overview;
  }
}

Scalability for Growth

Handle Hundreds of Clients

Firm Master Organization
├── Client A (Linked - Isolated)
│   ├── 2023 Books
│   ├── 2024 Books
│   └── Tax Returns
├── Client B (Linked - Isolated)
│   ├── Monthly Accounting
│   └── CFO Services
├── Client C (Linked - Isolated)
│   ├── Startup Books
│   └── Fundraising Support
└── ... ( hundreds more )

Benefits:

  • Unlimited Scale: No practical limit on client count
  • Performance Isolation: One client can't affect others
  • Cost Efficiency: Shared infrastructure costs
  • Management Simplicity: Single platform for all clients

White-Label Client Portals

Custom Client Experiences

// Client-specific portal configuration
const clientPortal = new ClientPortal({
  clientId: 'client_123',
  apiKey: clientApiKey,
  theme: client.branding,
  features: client.subscriptionTier
});

// Portal automatically scopes all operations to client org
await clientPortal.invoices.list();     // Only client's invoices
await clientPortal.reports.balance();   // Client's balance sheet
await clientPortal.accounts.list();     // Client's chart of accounts

Benefits:

  • Branded Experience: Custom logos, colors, domains
  • Feature Control: Different features per client tier
  • Data Security: Clients only see their own data
  • Unified Platform: Single codebase serves all clients

Enterprise Corporation Benefits

Complex Corporate Structures

Multi-Subsidiary Consolidation

Global Corporation
├── Master Organization (Consolidated HQ)
│   ├── US Operations (Owned - Consolidated)
│   │   ├── East Division (Owned - Consolidated)
│   │   ├── West Division (Owned - Consolidated)
│   │   └── Shared Services (Owned - Consolidated)
│   ├── European Subsidiary (Linked - Isolated)
│   │   ├── Germany GmbH (Owned - Consolidated)
│   │   ├── France SARL (Owned - Consolidated)
│   │   └── UK Limited (Owned - Consolidated)
│   └── Asian Operations (Linked - Isolated)
│       ├── China Co Ltd (Owned - Consolidated)
│       └── Singapore Pte Ltd (Owned - Consolidated)

Benefits:

  • Regulatory Compliance: Separate books for different jurisdictions
  • Consolidated Reporting: Roll up financials for corporate view
  • Currency Management: Different base currencies per region
  • Tax Optimization: Proper entity separation for tax planning
  • Management Accounting: Internal reporting by division/region

Department-Level Cost Centers

Internal Chargebacks

// Create department organizations
const departments = await Promise.all([
  crane.organizations.createSub({
    parent_id: companyMaster.id,
    name: 'Engineering',
    relationship_type: 'owned',    // Consolidated reporting
    billing_type: 'shared'         // Company pays, tracks internally
  }),
  crane.organizations.createSub({
    parent_id: companyMaster.id,
    name: 'Sales',
    relationship_type: 'owned',
    billing_type: 'shared'
  }),
  crane.organizations.createSub({
    parent_id: companyMaster.id,
    name: 'Marketing',
    relationship_type: 'owned',
    billing_type: 'shared'
  })
]);

// Track expenses by department
await crane.transactions.create({
  organization_id: engineeringOrg.id,
  description: 'AWS Hosting Costs - Q4',
  entries: [
    { account_id: cloudExpenses.id, entry_type: 'debit', amount: 15000 },
    { account_id: accountsPayable.id, entry_type: 'credit', amount: 15000 }
  ]
});

Joint Ventures & Partnerships

// Joint venture structure
const jointVenture = await crane.organizations.createSub({
  parent_id: companyMaster.id,
  name: 'TechCorp-JointVenture LLC',
  relationship_type: 'linked',     // Separate legal entity
  billing_type: 'shared',          // Master org manages billing
  base_currency_code: 'USD'
});

// Track ownership and distributions
await crane.transactions.create({
  organization_id: jointVenture.id,
  description: 'Ownership Distribution',
  entries: [
    { account_id: retainedEarnings.id, entry_type: 'debit', amount: 50000 },
    { account_id: distributionsPayable.id, entry_type: 'credit', amount: 50000 }
  ]
});

SaaS Platform Benefits

Per-Customer Accounting

Customer Isolation

class SaaSPlatform {
  constructor(platformApiKey) {
    this.platformApiKey = platformApiKey;
  }

  async onboardCustomer(customerData) {
    // Create isolated customer organization
    const customerOrg = await crane.organizations.createSub({
      parent_organization_id: this.platformMasterOrg.id,
      organization_name: `Customer: ${customerData.name}`,
      relationship_type: 'linked',        // 🔒 Complete data isolation
      billing_type: 'shared',             // Platform manages billing
      base_currency_code: customerData.currency
    });

    // Set up customer-specific accounting
    await this.setupCustomerAccounting(customerOrg.id, customerData);

    return customerOrg;
  }

  async recordSubscriptionRevenue(customerId, amount, period) {
    const customerOrg = await this.getCustomerOrg(customerId);

    await crane.transactions.create({
      organization_id: customerOrg.id,
      description: `Subscription Revenue - ${period}`,
      entries: [
        { account_id: accountsReceivable.id, entry_type: 'debit', amount },
        { account_id: subscriptionRevenue.id, entry_type: 'credit', amount }
      ]
    });
  }

  async generateRevenueReport() {
    // Aggregate across all customers
    const customers = await crane.organizations.list({
      parent_id: this.platformMasterOrg.id
    });

    const revenueByCustomer = {};
    let totalRevenue = 0;

    for (const customer of customers) {
      const balance = await crane.reports.incomeStatement(customer.id);
      revenueByCustomer[customer.name] = balance.netIncome;
      totalRevenue += balance.netIncome;
    }

    return { totalRevenue, revenueByCustomer };
  }
}

Feature-Based Accounting

Tier-Specific Accounting Rules

// Different accounting based on subscription tier
async setupCustomerAccounting(orgId, customer) {
  const tier = customer.subscriptionTier;

  switch (tier) {
    case 'enterprise':
      // Complex multi-entity structure
      await this.setupEnterpriseStructure(orgId);
      break;

    case 'professional':
      // Standard business accounting
      await this.setupProfessionalStructure(orgId);
      break;

    case 'starter':
      // Simplified accounting
      await this.setupStarterStructure(orgId);
      break;
  }
}

Revenue Recognition Automation

Usage-Based Billing

async recordUsage(customerId, usageData) {
  const customerOrg = await this.getCustomerOrg(customerId);

  // Calculate revenue based on usage
  const revenue = this.calculateRevenue(usageData);

  await crane.transactions.create({
    organization_id: customerOrg.id,
    description: `Usage Revenue - ${usageData.period}`,
    entries: [
      { account_id: unbilledRevenue.id, entry_type: 'debit', amount: revenue },
      { account_id: revenue.id, entry_type: 'credit', amount: revenue }
    ]
  });

  // Generate invoice
  await crane.invoices.create({
    organization_id: customerOrg.id,
    contact_id: customer.contactId,
    items: [{
      description: `Usage Charges - ${usageData.period}`,
      quantity: 1,
      price: revenue
    }]
  });
}

Real Estate Investment Benefits

Property-Level Accounting

Individual Property Tracking

// Real estate investment structure
const propertyOrg = await crane.organizations.createSub({
  parent_organization_id: investorMasterOrg.id,
  organization_name: `${property.address} LLC`,
  relationship_type: 'owned',        // Consolidated reporting
  billing_type: 'shared',            // Investor manages billing
  base_currency_code: 'USD'
});

// Set up property-specific accounts
await crane.accounts.create(propertyOrg.id, {
  code: '1601',
  name: 'Building',
  type: 'asset',
  parent_account_id: fixedAssets.id
});

await crane.accounts.create(propertyOrg.id, {
  code: '4001',
  name: 'Rental Income',
  type: 'revenue'
});

Portfolio Consolidation

Investor Reporting

async generateInvestorReport(investorId) {
  // Get all properties for this investor
  const properties = await crane.organizations.list({
    parent_id: this.investorMasterOrg.id,
    metadata: { investor_id: investorId }
  });

  const report = {
    totalProperties: properties.length,
    totalValue: 0,
    totalIncome: 0,
    totalExpenses: 0,
    netOperatingIncome: 0
  };

  for (const property of properties) {
    const financials = await crane.reports.incomeStatement(property.id);

    report.totalIncome += financials.totalRevenue;
    report.totalExpenses += financials.totalExpenses;
    report.netOperatingIncome += financials.netIncome;

    // Get property value from balance sheet
    const balance = await crane.reports.balanceSheet(property.id);
    report.totalValue += balance.totalAssets;
  }

  return report;
}

Depreciation Tracking

Tax Depreciation Schedules

// Set up depreciation for property
const depreciation = await crane.recurring.create({
  organization_id: propertyOrg.id,
  recurable_type: 'transaction',
  template: {
    description: 'Monthly Depreciation',
    entries: [
      { account_id: depreciationExpense.id, entry_type: 'debit', amount: monthlyAmount },
      { account_id: accumulatedDepreciation.id, entry_type: 'credit', amount: monthlyAmount }
    ]
  },
  frequency: 'monthly',
  start_date: purchaseDate,
  end_date: depreciationEndDate
});

Implementation Patterns

Organization Templates

Pre-Configured Structures

const templates = {
  accountingClient: {
    relationship_type: 'linked',
    billing_type: 'shared',
    chartOfAccounts: 'standard_business',
    defaultCurrency: 'USD'
  },

  corporateSubsidiary: {
    relationship_type: 'owned',
    billing_type: 'shared',
    chartOfAccounts: 'corporate',
    defaultCurrency: 'parent'
  },

  saasCustomer: {
    relationship_type: 'linked',
    billing_type: 'shared',
    chartOfAccounts: 'service_business',
    defaultCurrency: 'customer_choice'
  }
};

async createFromTemplate(templateName, orgData) {
  const template = templates[templateName];
  const org = await crane.organizations.createSub({
    ...orgData,
    ...template
  });

  await this.applyChartTemplate(org.id, template.chartOfAccounts);
  return org;
}

Automated Organization Management

Lifecycle Management

class OrganizationManager {
  async createOrganization(type, data) {
    const org = await this.createBaseOrg(type, data);
    await this.setupInitialAccounts(org.id, type);
    await this.configureSettings(org.id, type);
    await this.createApiKeys(org.id, type);
    await this.setupBilling(org.id, type);

    return org;
  }

  async archiveOrganization(orgId) {
    // Move to archive status
    await crane.organizations.update(orgId, {
      status: 'archived',
      archived_at: new Date()
    });

    // Keep data but restrict access
    await this.revokeApiKeys(orgId);
    await this.disableBilling(orgId);
  }

  async getOrganizationMetrics(orgId) {
    const [balance, transactions, invoices] = await Promise.all([
      crane.reports.balanceSheet(orgId),
      crane.transactions.list(orgId, { limit: 1 }), // Just count
      crane.invoices.list(orgId, { limit: 1 })      // Just count
    ]);

    return {
      totalAssets: balance.totalAssets,
      totalLiabilities: balance.totalLiabilities,
      transactionCount: transactions.total,
      invoiceCount: invoices.total,
      lastActivity: transactions.data[0]?.created_at
    };
  }
}

Security & Compliance

Data Isolation Guarantees

Organization-Level Security

  • API Key Scoping: Keys only access assigned organization
  • Database Isolation: Data physically separated by organization
  • Audit Trails: Complete activity logs per organization
  • Access Controls: Permission-based operation access

Cross-Organization Protection

// Attempting to access wrong organization
await crane.accounts.list({
  organization_id: 'org_wrong_id'  // ❌ Will fail
});
// Error: "Access denied to organization"

await crane.accounts.list({
  organization_id: 'org_correct_id'  // ✅ Works
});
// Returns: Account list for correct org

Compliance Benefits

Regulatory Requirements

  • SOX Compliance: Proper segregation of duties
  • GAAP/IFRS: Accurate financial reporting structures
  • Data Privacy: Client data isolation (GDPR, CCPA)
  • Audit Trails: Complete financial history

Multi-Jurisdictional Support

  • Currency Separation: Different currencies per organization
  • Tax Jurisdiction: Proper entity separation for tax purposes
  • Regulatory Reporting: Jurisdiction-specific financial statements

Performance & Scalability

Efficient Multi-Org Queries

Indexed Organization Queries

// Fast organization listing
const orgs = await crane.organizations.list({
  parent_id: 'org_parent',
  relationship_type: 'owned',
  limit: 100,
  offset: 0
});

// Optimized by database indexes on:
// - parent_organization_id
// - relationship_type
// - created_at

Resource Management

Per-Organization Limits

  • API Rate Limits: Configurable per organization
  • Credit Pools: Isolated or shared billing
  • Storage Quotas: Configurable data limits
  • Concurrent Operations: Worker queue management

Scalability Features

  • Horizontal Scaling: Add capacity as organizations grow
  • Read Replicas: Fast queries across multiple organizations
  • Caching Layers: Organization-specific caching
  • Background Processing: Non-blocking operations

Best Practices

Organization Structure Design

Plan Your Hierarchy

  1. Identify Master Organizations: Billing and management roots
  2. Define Relationship Types: Owned for consolidation, linked for isolation
  3. Billing: All sub-organizations share billing with the master organization
  4. Consider Growth: Design for future expansion

Naming Conventions

// Consistent naming patterns
const patterns = {
  client: 'Client: {CompanyName}',
  subsidiary: '{CompanyName} - {Division}',
  property: '{Address} Property LLC',
  department: '{CompanyName} - {Department} Dept'
};

Access Management

API Key Strategy

// Different keys for different purposes
const keys = {
  portal: {
    name: 'Client Portal Access',
    permissions: ['read', 'write'],
    expires: 'never'
  },
  integration: {
    name: 'Bank Integration',
    permissions: ['read', 'write'],
    expires: '1_year'
  },
  reporting: {
    name: 'Financial Reporting',
    permissions: ['read'],
    expires: 'never'
  }
};

Monitoring & Maintenance

Organization Health Checks

async healthCheck(orgId) {
  const checks = {
    apiKeys: await crane.apiKeys.list(orgId).then(keys => keys.length > 0),
    accounts: await crane.accounts.list(orgId).then(acc => acc.length > 5),
    recentActivity: await crane.transactions.list(orgId, {
      limit: 1,
      created_after: '30_days_ago'
    }).then(txns => txns.length > 0),
    billing: await crane.organizations.billing(orgId).then(
      b => b.credits_remaining > 100
    )
  };

  return {
    healthy: Object.values(checks).every(Boolean),
    issues: Object.entries(checks).filter(([, healthy]) => !healthy)
  };
}

Backup & Recovery

Organization-Level Backups

// Export organization data
const backup = await crane.organizations.export(orgId, {
  format: 'json',
  include_history: true,
  compression: 'gzip'
});

// Restore to new organization
const restoredOrg = await crane.organizations.restore(backup, {
  name: `${originalName} - Restored`,
  parent_id: originalParentId
});

Migration Strategies

From Single-Org Systems

Gradual Migration

  1. Create Master Organization: Set up billing root
  2. Migrate Existing Data: Import current books
  3. Create Sub-Organizations: Add departments/divisions
  4. Transition Gradually: Move functions over time

Data Mapping

// Map existing data to organization structure
const migration = {
  currentSystem: {
    accounts: [...],
    transactions: [...],
    customers: [...]
  },

  craneStructure: {
    master: {
      name: 'Company Master',
      accounts: 'shared_accounts',
      billing: 'primary'
    },
    subsidiaries: [
      {
        name: 'US Operations',
        accounts: 'us_specific',
        currency: 'USD'
      },
      {
        name: 'EU Operations',
        accounts: 'eu_specific',
        currency: 'EUR'
      }
    ]
  }
};

Crane Ledger's multi-organization architecture provides the flexibility to support any business structure. From accounting firms serving thousands of clients to enterprises with complex subsidiary relationships, the organization hierarchy ensures proper data isolation, billing management, and consolidated reporting.


Need help?

Create a free account to access our support portal. Once signed in, use the Support tab in your dashboard to submit a support ticket — our team typically responds within 24 hours.