Skip to Content
GuidesManaging Multiple Organizations (B2B2B)

Managing Multiple Organizations (B2B2B)

If you’re a platform (ERP, POS, commerce, fintech) that onboards multiple businesses onto Yona, this guide explains multi-tenancy.

The model

Your platform is a primary organization. Each business you onboard is a secondary (child) organization with isolated data, its own API key, and its own billing.

┌──────────────────────────────────────────────────────────────┐ │ │ │ PRIMARY ORGANIZATION (Your Platform) │ │ API Key: sk_live_partner_... │ │ │ │ Permissions: │ │ ✓ Create and manage child organizations │ │ ✓ Create, rotate, and revoke child API keys │ │ ✓ Manage child org users and webhooks │ │ ✓ Configure credit pool and transfer credits │ │ ✗ Cannot access child invoices, sellers, or buyers │ │ ✗ Cannot read child billing data │ │ │ │ Access methods: │ │ partner.forOrganization(childOrgId) │ │ → API keys, users, webhooks only │ │ partner.forApiKey(childKey, childOrgId) │ │ → Invoices, sellers, buyers, billing │ │ │ ├──────────────────┬──────────────────┬────────────────────────┤ │ │ │ │ │ CHILD ORG A │ CHILD ORG B │ CHILD ORG C │ │ │ │ │ │ Own API key │ Own API key │ Own API key │ │ Own sellers │ Own sellers │ Own sellers │ │ Own buyers │ Own buyers │ Own buyers │ │ Own invoices │ Own invoices │ Own invoices │ │ Own billing │ Own billing │ Own billing │ │ │ │ │ │ Data is fully │ Data is fully │ Data is fully │ │ isolated from │ isolated from │ isolated from │ │ other children │ other children │ other children │ │ │ │ │ └──────────────────┴──────────────────┴────────────────────────┘ Credit flow: Primary ──── transferCredits() ───→ Child A Primary ──── transferCredits() ───→ Child B Primary ──── transferCredits() ───→ Child C OR set primaryCoversSecondary: true (primary pool pays for all child usage automatically)

1. Initialize your partner client

const partner = new EInvoice({ apiKey: 'sk_live_partner_key', organizationId: 'your_partner_org_id', });

2. Onboard a child organization

const { organization, apiKey } = await partner.createOrganizationWithApiKey( { businessName: 'Acme Nigeria', email: 'admin@acme.ng' }, { mode: 'production', name: 'acme-primary-key' }, );

3. Operate as the child org

Use forApiKey() for data operations (invoices, sellers, buyers, billing):

const acme = partner.forApiKey(apiKey.key, organization.id); const seller = await acme.sellers.create({ /* ... */ }); const buyer = await acme.buyers.create({ /* ... */ }); const invoice = await acme.invoices.create({ /* ... */ }); await acme.invoices.submit(invoice.data.id);

4. Admin operations with your partner key

Use forOrganization() for admin tasks (API keys, users, webhooks):

const acmeAdmin = partner.forOrganization(organization.id); await acmeAdmin.apiKeys.list(); await acmeAdmin.users.list(); await acmeAdmin.webhooks.create({ /* ... */ });
Scope of forOrganization()

forOrganization() only works for API keys, users, and webhooks. For invoices, sellers, buyers, and billing, use forApiKey() instead.

5. Configure credit pool

await partner.organizations.updateCreditPoolConfig({ primaryCoversSecondary: true, minimumReserve: 500, });
💡 What does primaryCoversSecondary do?

When set to true, the primary organization’s credit pool pays for all child org usage. When false, each child must have its own credits.

ConfigBehavior
primaryCoversSecondary: truePrimary’s pool pays for everything
primaryCoversSecondary: false, fallbackToPrimary: falseChild uses own pool only
primaryCoversSecondary: false, fallbackToPrimary: trueChild first, primary covers shortfall

6. Transfer credits

await partner.billing.transferCredits({ targetOrganizationId: organization.id, amount: 1000, description: 'Monthly credit allocation', });

Both organizations must be in payg or hybrid billing mode.

Last updated on