SwitchLock Docs
Companies

How Tenants Work

Every company on SwitchLock is a fully isolated tenant. Its users, balances, transactions, and API keys never touch another company's data.

Multi-tenant architecture

When you register a company, the platform provisions a complete financial stack for that tenant in a single atomic operation. Each component below belongs exclusively to your company — no configuration or row-level security rule is shared across tenants.

Isolated ledger

A dedicated double-entry ledger with GL accounts for revenue, clearing, tax, payout, treasury, and bank collection — in both USD and ZiG.

Private user pool

Users you create belong to your company. A mobile number registered under one company is an entirely separate identity if registered under another.

Per-company API keys

Keys are scoped to a single company. An API key from Company A cannot read or write data for Company B, even if both keys are valid.

Custom fee config

Platform fees are stamped onto your company at registration from the active PLATFORM_FEE config. You can update your system_fee_basis_points independently.

Admin accounts

Human logins scoped to your company. Admins authenticate with email + password and receive a JWT — separate from the API key used by your server.

Webhook endpoint

One webhook URL per company. Every significant event — escrow funded, payment released, KYB status change — is POST-ed to your endpoint.

Business model: MERCHANT vs DEVELOPER

The isMerchant flag you set at registration determines how money moves through your tenant. Pick the model that matches your product — you cannot change it later without re-registering.

MERCHANTisMerchant: true

You are the seller. Buyers pay you directly. SwitchLock provisions a merchant avatar user at registration — a system identity that represents your store — so buyers can send funds to your company without you needing to register a separate seller user.

  • Single seller, many buyers
  • Merchant avatar auto-created at registration
  • Best for: e-commerce stores, service providers, brick-and-mortar POS
DEVELOPERisMerchant: false

You build a platform where buyers and sellers are different registered users. Escrow flows run between two of your own users — you orchestrate, the platform holds funds, and you release them when delivery is confirmed.

  • Peer-to-peer or marketplace flows
  • Register sellers and buyers as separate users
  • Best for: freelance platforms, property portals, vehicle marketplaces

The merchant avatar user carries the metadata flag is_merchant_avatar: true and the custom reference <slug>-DEFAULT-MERCHANT-AVATAR. You can query it via the identity API if you need to pass it as a seller ID in payment link creation.

Registering a company

POST /v1/core/companies is the one public endpoint on the platform — no API key required. Submit as multipart/form-data so you can optionally attach an incorporation document in the same request.

curl -X POST "https://api.switchlock.co.zw/v1/core/companies" \
  -F "name=Acme Marketplace" \
  -F "slug=acme" \
  -F "adminEmail=admin@acme.co.zw" \
  -F "adminFirstName=Jackson" \
  -F "adminLastName=Doe" \
  -F "adminPassword=SuperSecret123!" \
  -F "isMerchant=false"
Response — 201 Created (admin password shown once)
{
  "id": "cmp_01HXYZ...",
  "name": "Acme Marketplace",
  "slug": "acme",
  "business_model": "DEVELOPER",
  "kyc_status": "PENDING",
  "createdAt": "2026-06-23T09:00:00.000Z",
  "admin": {
    "email": "admin@acme.co.zw",
    "password": "SuperSecret123!"
  }
}

The admin.password field is returned in plaintext only in this response. Store it securely — it is hashed in the database and cannot be recovered.

For the full registration walkthrough including API key generation, see Getting Started.

Company ID and slug

Two identifiers appear throughout the API. They serve different purposes and are not interchangeable.

IdentifierFormatWhere to use
Company IDUUID (e.g. cmp_01HXYZ...)Pass as x-company-id request header on every authenticated API call. Find it in the registration response or via GET /v1/core/companies/me.
SlugURL-safe string (e.g. acme)Appears in webhook payloads, fee references (REG-FEE-<SLUG>), and the merchant avatar reference (<SLUG>-DEFAULT-MERCHANT-AVATAR). Must be globally unique.

Retrieve your company ID at any time:

curl "https://api.switchlock.co.zw/v1/core/companies/me" \
  -H "x-api-key: zl_sk_your_key_here" \
  -H "x-company-id: cmp_01HXYZ..."
Response — 200 OK
{
  "id": "cmp_01HXYZ...",
  "name": "Acme Marketplace",
  "slug": "acme",
  "business_model": "DEVELOPER",
  "kyc_status": "PENDING",
  "system_fee_basis_points": null,
  "webhook_url": null,
  "createdAt": "2026-06-23T09:00:00.000Z"
}

Isolation guarantee

The x-company-id header is not just a hint — every query that touches user, transaction, escrow, or admin data is scoped by company_id at the database level. The following boundaries are enforced server-side:

  • A user registered under Company A does not exist in Company B's user pool, even if the same mobile number is used.
  • Revoking an API key is scoped to the requesting company — you cannot revoke another company's keys.
  • Removing an admin is scoped to the requesting company — you cannot remove admins from another tenant.
  • Ledger balances and transaction history are never returned across company boundaries.

Do not share your API key or company ID across different products or environments. Generate a separate key per environment — staging and production should be entirely separate company registrations.

Next steps