organization_id, and every query filters on it.
A user reaches an organization through a membership, which carries exactly one
role. One user can hold memberships in many organizations; the panel’s switcher is
that list.
The public code
Every organization has apublic_code shaped org_<32 hex>. It is what appears
in the panel URL and what travels in the X-Organization-Id header.
The internal UUID never leaves the API on the surfaces the panel uses. Use
public_code in URLs and headers.Creating one
Sign-up creates the first organization. A signed-in user can open more, becoming owner of each:- it always has the three system roles (
owner,admin,member); - it always has an owner;
- it always has a live and a test environment, each with a publishable key.
Switching
Switching is navigation, not state you have to manage. Membership is verified every time, and switching into an organization you do not belong to answers404
— never a leak that it exists.
Inviting people
An invitation is created against a role and emailed as a one-time link, valid for 7 days. One pending invitation per address, enforced by a partial unique index — so a double click cannot produce two.existing_account), so it knows whether to ask for a name and password.
An existing account joins directly — the invitation went to that address, and
possession of the link proves nothing more is needed.
The invitation exists even when the email is lost. Revoke and re-invite.
Leaving and removing
Two different actions, deliberately:
Leaving is a user administering their own access, so it is not gated on
members:write. Removing yourself through the first endpoint answers 403 with a
message pointing at the second.
Removal takes effect on that person’s very next request: the session’s membership
JOIN stops matching.
The last-owner guard
An organization must keep at least one owner. Demoting, removing or leaving as the last owner answers:409
Deleting
Owner only (organization:delete), and the exact name must be typed back:
400 confirmation_mismatch.