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
Separate Legal Entity Tracking
// 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
- Identify Master Organizations: Billing and management roots
- Define Relationship Types: Owned for consolidation, linked for isolation
- Billing: All sub-organizations share billing with the master organization
- 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
- Create Master Organization: Set up billing root
- Migrate Existing Data: Import current books
- Create Sub-Organizations: Add departments/divisions
- 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.
- ✨ For LLMs/AI assistants: Read our structured API reference