Skip to content

Subaccounts & X-Org-Id

Iron is multi-tenant by subaccount. Each subaccount (an “org”) owns its own data: contacts, conversations, pipelines, staff, agent config, connectors, and numbers. Nothing is shared across tenants.

To act inside a specific subaccount, send its org UUID in the X-Org-Id header:

X-Org-Id: 11111111-2222-3333-4444-555555555555

The API validates this against your crm.org_members rows:

  • If you are a member of that org, the request acts inside it.
  • If you are not a member, the API returns 403 Forbidden — and it never leaks whether the org exists.
  • If the header is malformed (not a UUID), the API returns 400.

If you omit X-Org-Id, the API resolves your earliest-joined org as the acting org.

Orgs form a parent/child hierarchy. An agency org can have client subaccounts beneath it (via the parent_org_id chain). This hierarchy drives:

  • RLS scoping — at the database level, the acting org sees itself plus its direct children.
  • “View as client” impersonation — an admin can mint a time-boxed token to act inside one of their own subaccounts. The audit trail always records the real admin’s identity, even under impersonation. See POST /impersonate.
  • Agency-only endpoints — cross-account reports, rate cards, and rebilling are restricted to the agency org.

Internally, every request resolves an OrgContext carrying:

  • user — the authenticated Supabase user.
  • org — the resolved acting org.
  • member — the caller’s membership row (role, client flag, data-scoping flags).

Roles and permission sets gate what a member can do; client members get a restricted, data-scoped view. See The Operator Model.