Designing API Account Hierarchies: When to Add Organizations Above Individual Users

Most APIs ship with one account type: a single user, a single API key, a single billing relationship. That model breaks when customers want shared resources, multiple seats, or centralized billing. The trick is adding a hierarchy layer in a way that does not break every existing endpoint.

Every B2B SaaS product eventually hits the same customer request: can we have multiple users on one account? Sometimes it is phrased as multiple seats. Sometimes as shared resources across team members. Sometimes as centralized billing for everything the team uses. Underneath, the request is the same: the single-user model the product shipped with does not fit how the customer's organization actually works.

The right response is rarely to retrofit organizations on top of users in a way that breaks existing API contracts. The right response is to design the hierarchy correctly the first time, even if only one customer is currently asking for it, because the migration cost grows nonlinearly with the number of existing integrations.

What changes when you add an organization layer

In the single-user model, every resource the API exposes belongs to one user. The user owns API keys, owns resources created via those keys, pays for usage attributed to those resources, and sees audit logs for actions taken by those keys. Authentication and authorization collapse to a single check: is this API key valid, and does it belong to the user who owns the resource being accessed?

An organization layer separates these concerns. Resources belong to an organization. Users belong to one or more organizations with roles that determine what they can do. API keys belong to an organization but may be scoped to act on behalf of a specific user (for audit trail purposes) or as the organization itself (for service integrations). Billing is attached to the organization, not the user. Audit logs record both the user identity and the organization context.

The single most consequential decision in the design is whether resources move with the organization or with the user. The Stripe and GitHub model puts resources at the organization level, with users being members who act on the organization's resources. The Slack model leans toward workspaces (organizations) but allows users to have personal items. The Notion model started user-first and added workspaces later, with the migration pain still visible in the API surface today.

The minimum viable hierarchy

For most B2B SaaS, a three-level hierarchy is sufficient: organization, user, and key. The organization is the billing entity and the resource owner. Users are people who can sign in and act on behalf of the organization. Keys are API credentials that authenticate either as a user (for audit attribution) or as the organization itself (for service accounts).

The minimum schema is three tables plus two join tables: organizations, users, api_keys, organization_members (user-to-organization with role), and api_key_scopes (key-to-organization-or-user). Resources gain an organization_id column that becomes the primary tenant boundary for queries, indexing, and authorization.

The role design needs only two roles at first: owner and member. Owner can invite users, change billing, create API keys, and delete the organization. Member can do everything else. Most customers do not need finer-grained roles until they hit a specific compliance or security requirement; adding roles is much easier than removing them, so starting with two and expanding when asked is the safer default.

The API surface changes that customers see

The first change is authentication. The API key now encodes which organization the request acts within. Most APIs use a prefixed key format like org_xxx_yyy where the prefix encodes the organization scope and key type. The middleware that validates the key also looks up the organization context, which becomes available to every downstream handler.

The second change is resource creation. POST endpoints that previously created a user-owned resource now create an organization-owned resource. The organization is implied by the API key, not specified in the request body, which means existing integrations continue to work without modification.

The third change is listing. GET endpoints that previously returned the user's resources now return the organization's resources. For most customers this is a no-op because their single-user account migrated to a single-user-single-organization account; they see the same resources they always did.

The fourth change is admin operations: invite-user, list-members, change-role, remove-user. These are new endpoints with no equivalent in the single-user model, and they only matter for organizations with more than one user. Most APIs add a /v1/organizations and /v1/organizations/{id}/members surface for these operations.

The migration question

The hard part of adding hierarchy to an existing API is not designing the new model. It is migrating existing customers to it without breaking integrations they already shipped.

The standard pattern is to do the migration in three phases. Phase one is the dual-model phase: the database supports both the old user-scoped resources and the new organization-scoped resources, with every existing user getting a default organization created automatically. Phase two is the silent-migration phase: existing API keys continue to work as user-scoped credentials, but internally they resolve to the default organization for resource lookups. Phase three is the deprecation phase, often spanning a year or more: customers are notified that user-scoped semantics are going away and given migration tools to update their integrations.

Most customers will never notice phases one and two. Their integration continues to work with no code change. Phase three is where customer support burden concentrates, and providers with established customer bases often defer it indefinitely, leaving the dual model in place and accepting the operational cost of supporting both shapes.

Three patterns that fail

The first failure pattern is putting the organization ID in every request path. Endpoints like /v1/organizations/{org_id}/projects/{project_id} look cleaner than /v1/projects/{project_id} but force every existing integration to learn what org_id to pass. The org_id is already implied by the API key in most designs, and putting it in the path duplicates that information without adding security.

The second failure pattern is letting users belong to one organization. The constraint feels simpler in the data model but breaks contractor and consultant use cases where one person legitimately works with multiple customer organizations. Allowing multi-membership from the beginning costs little and supports a common workflow.

The third failure pattern is conflating authentication and authorization. The API key tells you which organization the request acts within. Whether the request is allowed to perform the requested action is a separate question that depends on the key's scopes (if scoped keys are supported), the role of any user the key acts on behalf of, and the specific resource being accessed. Collapsing these into a single check makes future role-based and scope-based features impossible to add cleanly.

The post-pivot context

The product currently in development takes the opposite end of this spectrum: a public directory where most users will never need an organization at all. But the design still benefits from this thinking. The submission form ties a project to a contact email and an edit token; if the directory grows into a tool where teams want to manage multiple project listings together, the migration path is to introduce an account layer that owns one or more projects and gives access to multiple email addresses.

Designing for that future without building it now means keeping the project schema agnostic about how ownership is structured. The current edit token is the entire authorization surface; adding an account layer later means letting an account claim ownership of one or more projects via the edit token, after which the account replaces the token as the authorization primitive. The schema does not need to change immediately; only the assumption that the edit token is the only path to ownership needs to be deferred.

The deeper observation is that API hierarchy decisions have asymmetric reversibility. Adding a layer later costs much more than designing the layer in from the start, even if the layer is initially trivial. For products that have any plausible path to multi-user customers, the right default is to support an organization layer from day one, even if every account starts with one organization and one user. The model costs essentially nothing when there is exactly one of everything and pays back enormously the first time a customer asks for the second.


Read more essays and technical writing at anethoth.com — a notebook on databases, distributed systems, biology, and the engineering that holds the world together.