Organizations
All resources (agents, chats, tools) are scoped to an organization. A user can belong to multiple organizations.
List organizations
GET /api/orgs
Authorization: Bearer nxr_...Create organization
POST /api/orgs
Authorization: Bearer nxr_...
Content-Type: application/json
{ "name": "Engineering", "icon": "🛠️", "color": "#6366f1" }Update organization
PATCH /api/orgs/{org_id}
Authorization: Bearer nxr_...
Content-Type: application/json
{ "name": "Platform Engineering" }Delete organization
DELETE /api/orgs/{org_id}
Authorization: Bearer nxr_...Owner only.
Members
List members
GET /api/orgs/{org_id}/members
Authorization: Bearer nxr_...Response:
[
{
"user_id": "uuid",
"email": "user@example.com",
"full_name": "Alice",
"role": "owner | admin | member | viewer",
"joined_at": "2026-01-01T00:00:00Z"
}
]Update member role
PATCH /api/orgs/{org_id}/members/{user_id}
Authorization: Bearer nxr_...
Content-Type: application/json
{ "role": "admin" }Roles (lowest to highest): viewer < member < admin < owner.
Ownership transfer. Assigning the owner role to another member is a guarded transfer: only the current owner may do it, the previous owner is automatically demoted to admin, and the target becomes the sole owner. The current owner’s role cannot otherwise be changed, and they cannot leave the org, until ownership is transferred. Only the owner can grant the admin role.
Remove member
DELETE /api/orgs/{org_id}/members/{user_id}
Authorization: Bearer nxr_...Leave organization
POST /api/orgs/{org_id}/leave
Authorization: Bearer nxr_...Invitations
Create invite
POST /api/orgs/{org_id}/invites
Authorization: Bearer nxr_...
Content-Type: application/json
{ "role": "member" }Invites are token-based. The response returns a shareable token:
{
"token": "invite-token",
"expires_at": "2026-01-08T00:00:00Z",
"invite_path": "/join?token=invite-token"
}Optionally bind the invite to a specific person by passing email (and full_name). This enables zero-touch onboarding: the response then also carries ready-to-share terminal (CLI) install one-liners for that invitee.
POST /api/orgs/{org_id}/invites
Authorization: Bearer nxr_...
Content-Type: application/json
{ "role": "member", "email": "alice@example.com", "full_name": "Alice" }{
"token": "invite-token",
"expires_at": "2026-01-08T00:00:00Z",
"invite_path": "/join?token=invite-token",
"cli_install_sh": "curl -fsSL https://.../install.sh | bash -s -- --join invite-token --url https://your-instance",
"cli_install_ps": "powershell -c \"...\""
}Accept invite
POST /api/orgs/accept-invite
Authorization: Bearer nxr_...
Content-Type: application/json
{ "token": "invite-token" }Validate invite (unauthenticated)
GET /api/orgs/invite/{token}Returns org name and role — useful to show users what they are joining before they register.
Zero-touch CLI onboarding
An email-bound org invite can be redeemed straight from the command line — no prior account, no manual login. This backs the NexoraCLI nexora join command (and the admin’s one-command installer).
Preview an invite (unauthenticated)
GET /api/auth/cli/invite/{token}Returns the org name, role, and invitee email so the CLI can confirm before redeeming.
Redeem an invite (unauthenticated)
POST /api/auth/cli/redeem
Content-Type: application/json
{ "token": "invite-token", "device_name": "alice-laptop", "platform": "linux" }Resolves or auto-creates a passwordless account for the invite email, joins it to the inviting org, and returns everything the CLI needs to operate — a durable API key (used for REST and the chat WebSocket), a device token, and an access token:
{
"access_token": "eyJhbGc...",
"device_token": "nxd_...",
"api_key": "nxr_...",
"org_id": "uuid",
"org_name": "Engineering",
"user_id": "uuid",
"created_account": true
}The invite is single-use and consumed only on success. Off-boarding a teammate is just deactivating their user.
Managed accounts
Users who join an organization through an org invite (web invite-first registration or CLI zero-touch onboarding) are created as managed accounts: they live inside the inviting org, have no personal organization, and cannot switch, create, join, or leave organizations. The flag is exposed as is_managed on GET /api/users/me.
Managed users are restricted server-side — the org switch, create, accept-invite, and leave endpoints return 403 for them. Owners, admins, and anyone who self-registered are unaffected. This lets an org hand employees a locked-down workspace scoped to a single organization.
Permission groups
Admins restrict what members and viewers can see and do with org-scoped permission groups. A user assigned to one or more groups is limited to the union of those groups’ grants; a member with no group keeps full member access; owners and admins always bypass groups. Endpoints live under /api/permissions.
List / create groups
GET /api/permissions/groups
POST /api/permissions/groups
Authorization: Bearer nxr_...
Content-Type: application/json
{
"name": "Support team",
"description": "Read-only agents, capped usage",
"permissions": ["agents.view", "projects.view", "chats.view_shared"],
"limits": {
"token_budget": 1000000,
"token_window_hours": 720,
"max_concurrent_agents": 2,
"max_provider_accounts": 1
},
"capabilities": {
"agent_ids": [],
"skill_keys": [],
"tool_keys": [],
"persona_ids": [],
"provider_ids": [],
"chain_ids": [],
"default_chain_id": null
}
}Other endpoints: PATCH /api/permissions/groups/{id}, DELETE /api/permissions/groups/{id}, PUT /api/permissions/groups/{id}/members (set assigned users), GET /api/permissions/catalog (the full permission-key catalog for the editor matrix), GET /api/permissions/assignable (org resources — agents, skills, tools, personas, providers, chains — an admin can drop into a capability allowlist), and GET /api/permissions/me (the caller’s effective permissions, restriction flag, and usage-budget snapshot).
Permission keys. Each functional area (agents, personas, skills, tools, mcp_servers, knowledge_bases, memory, projects, tasks, issues, proposals, approvals, schedules, channels, providers, integrations, marketplace, webhooks, settings) exposes <area>.view and <area>.manage; manage implies view. Two special keys exist: ui.advanced_mode (allow leaving simple UI mode) and chats.view_shared (see other members’ conversations in the shared chat list). Unknown keys are rejected with 400.
Limits (0 = unlimited): token_budget caps input+output tokens over token_window_hours (0 = lifetime); max_concurrent_agents caps parallel runs per user; max_provider_accounts caps how many provider accounts a user may use. Capabilities are allowlists — leave a list empty to allow everything; default_chain_id forces a fallback chain. When a user belongs to several groups their effective policy is the union of grants, the most generous limit per dimension, and the union of allowlists. Enforcement is live: a turn that crosses the token budget completes and the next one is blocked. See the Groups tab in the UI guide.