Organizations
Roles
An organization can hold more than the person or agent who signed up for it. Everyone in it is a member holding one of three roles. Owners are people only; administrators can be people or AI.
| Role | Who acts in it | What it can do |
|---|---|---|
Owner (owner) | A person signed in to the dashboard. Never an AI. | Everything an administrator can, plus the owner-only actions below. |
Administrator (admin) | A person, or an AI: the organization's API key, or an AI connected by an owner or administrator. | Invite people as administrators or members, change a member's or administrator's role, remove members and administrators, cancel any waiting invitation, turn services on and off, and change the organization's and its services' settings, except owner-only ones. In the dashboard, also manage the organization's API keys. |
Member (member) | A person, or an AI connected by a member. | Use the organization's services, see who else is a member, and leave. A member cannot invite, cancel an invitation, change a role, remove anyone, turn a service on or off, or change a setting. |
The rule behind the table is that nobody grants more than they hold. An owner
grants any role, an administrator grants admin or member, and a member
grants nothing. The same rule covers the role a member has now: an
administrator cannot change or remove an owner. A request outside the rule is
refused with MEMBER_ROLE_NOT_GRANTABLE.
Owner-only actions
Only an owner can:
- invite someone as an owner;
- make a member or administrator an owner;
- change another owner's role, or remove another owner;
- change an owner-only setting: one whose
writableByisorganization-owner. Anyone else is refused withSETTING_REQUIRES_OWNER.
An owner does these in the dashboard: member changes on the Members page
(/members), settings on the service's page. No AI can do them, as the next
section explains.
An AI is never above administrator
Only a person's dashboard session carries the owner role. Every other
credential is capped where it is checked, on every request: an owner role
becomes admin, and a lower role stays as it is, so an AI never outranks the
person it acts for.
| Credential | Acts as |
|---|---|
| A person signed in to the dashboard | Their own role: owner, administrator or member. |
| An AI signed in as a person (OAuth over MCP) | That person's role, capped at administrator: an owner's AI acts as an administrator, a member's AI as a member. |
| An AI's own OAuth client (client credentials) | The role of the person who registered it, in the first organization they joined, capped at administrator. |
| The organization's API key | Administrator, always. A key is the organization's own agent, not a person. |
So when you connect your AI and it signs in as you, it can do everything an
administrator can, but an owner-only action asked of it is refused
(MEMBER_ROLE_NOT_GRANTABLE for a member change, SETTING_REQUIRES_OWNER
for a setting). Do that action yourself in the dashboard.
The founding owner, whoever first owned the organization, cannot be
demoted, removed or leave, by anyone (MEMBER_FOUNDING_OWNER_PROTECTED). So
every organization always has an owner. Any other owner can be demoted,
removed or leave like anyone else.
Inviting people
Owners and admins invite from the dashboard's Members page, at
/members, or with the organization_invite tool:
role: the role everyone in this invitation gets, one you may grant;emails: the addresses to invite. Case and repeats do not matter: each distinct address is invited once. The tool's input schema says how many one call takes.
Each address gets its own outcome, and one address refused does not stop the rest:
| Outcome | What it means |
|---|---|
invited | An invitation was recorded and its message sent. |
reissued | The address already had an invitation waiting. It was canceled and a new one sent, so only the newest link works. |
already-member | The address already belongs to the organization. Nothing was sent. |
refused | That address could not be invited this time. The outcome carries a code; invite it again to retry. |
The person invited must accept with an account whose address is the one invited, and that address must be verified. An invitation expires after the period its message states; a pending invitation shows when it expires, and an expired one can simply be sent again.
The whole invitation is refused, and nothing recorded, when invitations are
switched off on this deployment (INVITATIONS_DISABLED) or when it would take
the organization past one of its limits (see Limits).
Accepting
The invitation message has a link. It opens the invitation page, where you sign in with the invited address (or sign up with it, if you have no account yet, and verify it) and accept or decline.
Accepting makes you a member at the invited role and lands you in the organization you joined: the dashboard and your AI now work there. Your own organization stays yours, with its keys, credit and data, and you can switch back to it at any time.
Switching
Every person works in one organization at a time, their current organization. Everything you do, in the dashboard and through an AI signed in as you, happens there: its keys, its credit, its services, its data.
- On the site, once you belong to more than one organization, the account menu in the header (behind your initials, or the menu button on a phone) has a "Switch to …" item naming each of the others. Choosing one makes it current, and the page you are on is shown again for that organization.
- An AI acting as you, through your own sign-in, uses
organization_listto see your organizations and which is current, andorganization_switchwith anorganizationIdto change it. A switch either of you makes is seen by the other from its next request. - An API key cannot switch. It acts as its organization's own agent and
always works in that organization;
organization_switchwith a key is refused withORGANIZATION_SWITCH_NOT_ALLOWED.
Switching is not leaving. You stay a member of the organization you switched away from, with your role, and everything there is kept.
Managing members
Each of these acts on the current organization, and the Members page offers the same actions to anyone whose role allows them:
organization_memberslists the members with their roles, marks the founding owner and, when the organization has one, its own agent (in an agent's organization they are the same member), and gives each member'suserId.organization_invitationslists the invitations still waiting, with each one's role and expiry and itsinvitationId.organization_invitation_cancelcancels a waiting invitation by itsinvitationId; its link stops working.organization_member_rolegives a member (memberUserId) a newrole. You must be able to grant both the role they have and the new one. On the Members page, choosing a new role asks you to confirm before anything changes; canceling leaves the role as it was. You can change your own role too, but you cannot give it back to yourself afterwards: another member who may grant it would have to, and the confirmation on your own row says so.organization_member_removeremoves a member (memberUserId). You cannot remove yourself; leave instead.organization_leavetakes you out of the current organization. You land in another organization you belong to, or your own.
The same operations on the REST API:
| Tool | REST |
|---|---|
organization_list | GET /api/v1/organizations |
organization_switch | PUT /api/v1/organizations/current with { "organizationId": "…" } |
organization_members | GET /api/v1/organizations/current/members |
organization_invitations | GET /api/v1/organizations/current/invitations |
organization_invite | POST /api/v1/organizations/current/invitations with { "role": "…", "emails": ["…"] } |
organization_invitation_cancel | DELETE /api/v1/organizations/current/invitations/{invitationId} |
organization_member_role | POST /api/v1/organizations/current/members/{memberUserId}/role with { "role": "…" } |
organization_member_remove | DELETE /api/v1/organizations/current/members/{memberUserId} |
organization_leave | DELETE /api/v1/organizations/current/membership |
current is always the organization your credential is working in; no call
names another organization to act on it.
If a member's role was changed by someone else between your reading it and
your change, the change is refused with MEMBER_ROLE_CHANGED: list the
members again and retry. A removed member, or one who leaves, keeps their own
account and organization; what they made in the organization they left stays
with it.
Limits
Changes to an organization's members — inviting, canceling, changing a role,
removing, leaving and switching — are throttled per caller: each person has
their own hourly allowance, and the organization's API keys share one between
them, as its agent. It is counted across the API, MCP and the dashboard
together, and a change that is refused still counts. Past it a change is
refused as rate-limited (RATE_LIMITED; on the REST API, 429 with
Retry-After). Listing is not throttled.
An organization may also send only so many invitation messages a day, new and
re-sent invitations alike. Past that, each further address in an invitation is
reported refused with RATE_LIMITED and nothing is recorded for it; the
rest of the invitation is still processed. Invite those addresses again later.
How many addresses one invitation takes, how many members an organization may hold and how many invitations it may have waiting are all capped. A refusal says which cap it met:
| Refusal | The cap |
|---|---|
a validation error on emails (400 on the REST API) | too many addresses in one invitation |
ORGANIZATION_MEMBER_LIMIT_REACHED | the organization's members, counting everyone in this invitation |
ORGANIZATION_INVITATION_LIMIT_REACHED | the invitations waiting, counting everyone in this invitation; cancel some, or wait for them to expire |