Organisations & Workspaces API
Manage the two-level hierarchy: Organisations (company/firm) contain one or more Workspaces (project/team/division). All resources (forms, tables, matters, etc.) are scoped to a workspace. Users have roles at both the organisation level and workspace level.
Data Model
- Organisation - the top-level entity representing a company or firm. Has a unique slug, settings, and member list.
- Workspace - a child of an Organisation. All data (forms, tables, matters, documents, workflows) is scoped to a workspace. Users switch between workspaces within their organisation.
- Role Hierarchy - Organisation OWNER/ADMIN have implicit access to all workspaces. Organisation MEMBER/VIEWER only access workspaces they are explicitly added to.
| Org Role | Workspace Access | Can Create Workspaces |
|---|---|---|
OWNER | Implicit OWNER in all workspaces | Yes |
ADMIN | Implicit ADMIN in all workspaces | Yes |
MEMBER | Only explicitly-added workspaces | No |
VIEWER | Only explicitly-added workspaces (read-only) | No |
Organisation Endpoints
| Method | Endpoint | Description |
|---|---|---|
GET | /api/organizations | List all organisations you belong to |
POST | /api/organizations | Create a new organisation |
GET | /api/organizations/:orgId | Get organisation details |
PATCH | /api/organizations/:orgId | Update organisation (name, slug, settings) |
DELETE | /api/organizations/:orgId | Delete organisation (OWNER only, cascades) |
GET | /api/organizations/:orgId/workspaces | List workspaces in an organisation |
POST | /api/organizations/:orgId/workspaces | Create workspace within organisation |
GET | /api/organizations/:orgId/members | List organisation members |
POST | /api/organizations/:orgId/members | Add member to organisation (existing user or create new user) |
PATCH | /api/organizations/:orgId/members/:memberId | Update member role (OWNER only) |
DELETE | /api/organizations/:orgId/members/:memberId | Remove member from organisation (cascades to workspace memberships) |
POST | /api/organizations/:orgId/members/:memberId/reset-2fa | Reset a member's two-factor authentication |
POST | /api/organizations/:orgId/members/:memberId/unlock-login | Clear login rate limits for a locked-out member |
Workspace Member Endpoints
Manage members within individual workspaces. Users must be organisation members before they can be added to a workspace.
| Method | Endpoint | Description |
|---|---|---|
GET | /api/organizations/:orgId/workspaces/:workspaceId/members | List members of a workspace |
POST | /api/organizations/:orgId/workspaces/:workspaceId/members | Add an organisation member to a workspace |
DELETE | /api/organizations/:orgId/workspaces/:workspaceId/members/:memberId | Remove a member from a workspace |
Workspace Endpoints
| Method | Endpoint | Description |
|---|---|---|
GET | /api/workspaces | List all workspaces you belong to |
POST | /api/workspaces | Create a new workspace (optionally within an org) |
GET | /api/workspaces/:id | Get workspace details with member list and resource counts |
PATCH | /api/workspaces/:id | Update workspace (name, slug, settings, logo) |
DELETE | /api/workspaces/:id | Delete workspace (OWNER only, requires name confirmation) |
POST | /api/workspace/switch | Switch active workspace (saves both workspace and org context) |
GET | /api/user/workspaces | List user's workspaces with parent org info and active marker |
List Organisations
Returns all organisations the authenticated user belongs to, with workspace and member counts.
GET /api/organizations
Response
{
"organizations": [
{
"id": "cm_org_abc123",
"name": "Clara Labs",
"slug": "clara-labs",
"settings": null,
"createdAt": "2026-01-15T09:00:00.000Z",
"updatedAt": "2026-02-20T14:30:00.000Z",
"role": "OWNER",
"_count": {
"workspaces": 3,
"members": 8
}
}
]
}
Create Organisation
Creates a new organisation. The authenticated user becomes the OWNER. Slug is auto-generated from the name if not provided.
POST /api/organizations
Content-Type: application/json
Body
{
"name": "Acme Inc.",
"slug": "acme-inc"
}
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Organisation name (1-255 characters) |
slug | string | No | URL-friendly identifier. Auto-generated from name if omitted. |
List Workspaces in Organisation
Returns workspaces within an organisation. OWNER/ADMIN see all workspaces; MEMBER/VIEWER only see workspaces they have been explicitly added to.
GET /api/organizations/:orgId/workspaces
Response
{
"workspaces": [
{
"id": "cm_ws_xyz789",
"name": "ADGM Operations",
"slug": "adgm-ops",
"orgId": "cm_org_abc123",
"createdAt": "2026-01-20T10:00:00.000Z",
"role": "OWNER",
"_count": {
"members": 5,
"forms": 12,
"tables": 8,
"workflows": 3
}
}
]
}
List Organisation Members
Returns all members of an organisation. Requires OWNER or ADMIN role.
GET /api/organizations/:orgId/members
Response
{
"members": [
{
"id": "cm_member_123",
"userId": "cm_user_456",
"organizationId": "cm_org_abc123",
"role": "ADMIN",
"createdAt": "2026-01-15T09:00:00.000Z",
"user": {
"id": "cm_user_456",
"name": "Jane Smith",
"email": "jane@example.com",
"image": null
}
}
]
}
Add Organisation Member
Add a member to the organisation. Supports two flows: add an existing user by ID, or create a new user by providing name, email, and password. Requires OWNER or ADMIN role. Admins can only assign MEMBER or VIEWER roles.
POST /api/organizations/:orgId/members
Content-Type: application/json
Option 1: Add Existing User
{
"userId": "cm_user_789",
"role": "MEMBER"
}
| Field | Type | Required | Description |
|---|---|---|---|
userId | string | Yes | ID of an existing user to add |
role | string | No | OWNER, ADMIN, MEMBER (default), or VIEWER |
Option 2: Create New User
{
"name": "John Doe",
"email": "john@example.com",
"password": "securePassword123",
"role": "MEMBER"
}
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Full name of the new user |
email | string | Yes | Email address (if user exists, adds them instead of creating) |
password | string | Yes | Minimum 12 characters, validated for strength |
role | string | No | OWNER, ADMIN, MEMBER (default), or VIEWER |
If a user with the given email already exists, they are added to the organisation without creating a duplicate account. Returns 409 if the user is already an organisation member.
Update Member Role
Change a member's organisation role. Requires OWNER role. Cannot change your own role or demote the last owner.
PATCH /api/organizations/:orgId/members/:memberId
Content-Type: application/json
{
"role": "ADMIN"
}
Remove Organisation Member
Remove a member from the organisation. Also removes them from all workspaces within the organisation. Requires OWNER or ADMIN role. Cannot remove yourself or the last owner.
DELETE /api/organizations/:orgId/members/:memberId
Reset Member 2FA
Disable two-factor authentication for a member, removing their authenticator app connection and backup codes. The member will be required to set up 2FA again on their next login. Requires OWNER or ADMIN role. Cannot reset your own 2FA through this endpoint. Admins cannot reset 2FA for owners or other admins.
POST /api/organizations/:orgId/members/:memberId/reset-2fa
Response
{ "success": true }
| Status | Condition |
|---|---|
200 | 2FA successfully reset |
400 | 2FA is not enabled for this user, or attempting to reset own 2FA |
403 | Insufficient role (admin trying to reset owner/admin) |
404 | Member not found in organisation |
This action is audit-logged. The member's TOTP secret, backup codes, and verification timestamps are all cleared.
Unlock Member Login
Clear login rate limits for a member who has been locked out due to too many failed login attempts. Also clears 2FA verification rate limits. Requires OWNER or ADMIN role. Admins cannot unlock owners or other admins.
POST /api/organizations/:orgId/members/:memberId/unlock-login
Response
{ "success": true }
| Status | Condition |
|---|---|
200 | Rate limits cleared successfully |
403 | Insufficient role (admin trying to unlock owner/admin) |
404 | Member not found in organisation |
Rate limits are stored in-memory (or Upstash Redis if configured). Login limits are 10 attempts per 15 minutes per identity and 25 per IP. This endpoint clears the per-identity counter. The member can attempt to log in again immediately after unlocking.
Workspace Members
Manage which organisation members have access to a specific workspace. Users must be organisation members first. Organisation OWNER/ADMIN have implicit access to all workspaces.
List Workspace Members
GET /api/organizations/:orgId/workspaces/:workspaceId/members
{
"members": [
{
"id": "cm_ws_member_abc",
"userId": "cm_user_456",
"workspaceId": "cm_ws_xyz789",
"role": "ADMIN",
"createdAt": "2026-02-01T12:00:00.000Z",
"user": {
"id": "cm_user_456",
"name": "Jane Smith",
"email": "jane@example.com",
"image": null
}
}
]
}
Add Member to Workspace
Add an existing organisation member to a workspace. The target user must already be a member of the parent organisation.
POST /api/organizations/:orgId/workspaces/:workspaceId/members
Content-Type: application/json
{
"userId": "cm_user_456",
"role": "MEMBER"
}
| Field | Type | Required | Description |
|---|---|---|---|
userId | string | Yes | ID of an organisation member to add to the workspace |
role | string | No | OWNER, ADMIN, MEMBER (default), or VIEWER |
Remove Member from Workspace
DELETE /api/organizations/:orgId/workspaces/:workspaceId/members/:memberId
Context Switching
The active workspace determines which data is returned by all other API endpoints (forms, tables, matters, etc.). Switch workspace to change context.
POST /api/workspace/switch
Content-Type: application/json
{
"workspaceId": "cm_ws_xyz789"
}
Switching workspace also updates the active organisation to the workspace's parent org. Organisation OWNER/ADMIN can switch to any workspace in their org without needing an explicit workspace membership.
Oversight Permissions & Members
When a workspace is overseen by another workspace, you can grant resource-level access to the overseer's members. The overseer-members endpoint returns members of all workspaces that oversee the current workspace, for use in permission pickers across tables, documents, boards, and submissions.
Get Overseer Workspace Members
GET /api/oversight/overseer-members
{
"overseerWorkspaces": [
{
"workspaceId": "cm_ws_overseer",
"workspaceName": "Regulator Workspace",
"members": [
{ "userId": "cm...", "name": "Inspector", "email": "inspect@example.com", "role": "ADMIN" },
{ "userId": "cm...", "name": "Auditor", "email": "auditor@example.com", "role": "MEMBER" }
]
}
]
}
Only returns members from workspaces with an active oversight relationship. Used by the unified permission picker across Tables, Knowledge Base, Matters, and Submissions.
Unified Grant Types
Resource permissions (tables, documents, boards, submissions) support three grant types via a unified AccessGrant model:
| targetType | targetId | Description |
|---|---|---|
user | User ID | Grant to a specific user (local or oversight workspace) |
workspace_role | Role name (OWNER, ADMIN, MEMBER, VIEWER) | Grant to all users with the specified workspace role |
oversight_workspace | Workspace ID | Grant to all members of an overseer workspace (validated against active relationships) |
Source Workspace Labels
When a workspace is configured as an overseer of subordinate workspaces, aggregated views automatically include source workspace labels. The isOverseer flag is returned by the Tasks and Matters APIs when the user has subordinate workspaces.
| View | Label | Details |
|---|---|---|
| Task list | Origin column | Building2 icon + workspace name. Shown when isOverseer is true. |
| Matter list (table) | Source column | Building2 icon + workspace name. Pass includeSubordinates=true to aggregate. |
| Matter kanban board | Card badge | Small Building2 icon + workspace name on each kanban card. |
| Audit log | Workspace badge | Already implemented. Building2 icon badge on each audit entry. |
Delete Organisation
Permanently deletes an organisation and all its workspaces. Requires OWNER role and name confirmation.
DELETE /api/organizations/:orgId
Content-Type: application/json
{
"confirmName": "Clara Labs"
}
Warning: Deleting an organisation cascades to all workspaces within it and all their data (forms, tables, matters, documents, workflows).