Organizations¶
Endpoints for managing organizations, their members, and invitations.
Base path: /api/organizations
Authentication: All endpoints require a valid session.
Endpoints¶
Organization CRUD¶
| Method | Path | Min Role | Description |
|---|---|---|---|
GET |
/api/organizations |
OrganizationAdmin |
List organizations |
POST |
/api/organizations |
PlatformAdmin |
Create an organization |
GET |
/api/organizations/:id |
OrganizationAdmin |
Get organization details |
PATCH |
/api/organizations/:id |
OrganizationAdmin |
Update organization |
DELETE |
/api/organizations/:id |
PlatformAdmin |
Archive organization |
Organization Members¶
| Method | Path | Min Role | Description |
|---|---|---|---|
GET |
/api/organizations/:id/users |
Coach |
List organization members |
POST |
/api/organizations/:id/users |
OrganizationAdmin |
Add a user to the organization |
PATCH |
/api/organizations/:id/users/:userId |
OrganizationAdmin |
Update a member's role or status |
DELETE |
/api/organizations/:id/users/:userId |
OrganizationAdmin |
Disable a member's access |
Invitations¶
| Method | Path | Min Role | Description |
|---|---|---|---|
GET |
/api/organizations/:id/invites |
Manager |
List pending invites |
POST |
/api/organizations/:id/invites |
Manager |
Create or resend an invite |
GET /api/organizations¶
List organizations.
PlatformAdmin: Returns all organizations in the system with optional filters.OrganizationAdmin: Returns only their own organization.
Query parameters:
| Parameter | Type | Description |
|---|---|---|
limit |
integer | Max records (default: 100, max: 1000) |
offset |
integer | Records to skip (default: 0) |
search |
string | Filter by org name (case-insensitive, partial match) |
status |
string | Filter by status: active, inactive, suspended, or archived |
Response 200:
{
"data": [
{
"id": "org-uuid",
"name": "Praxia Academy",
"description": "Educational consultants",
"logoUrl": null,
"status": "active",
"settings": {},
"defaultTimezone": "UTC",
"createdAt": "2025-01-01T00:00:00.000Z",
"updatedAt": "2025-01-01T00:00:00.000Z"
}
],
"meta": {
"total_count": 5
}
}
POST /api/organizations¶
Create a new organization. Only PlatformAdmin can create organizations.
Request body:
{
"name": "Praxia Academy",
"description": "Educational consultants",
"logoUrl": "https://...",
"status": "active",
"settings": {}
}
| Field | Type | Required | Constraints |
|---|---|---|---|
name |
string | Yes | 1–255 characters |
description |
string | No | Free text |
logoUrl |
string | No | Must be a valid URL |
status |
string | No | active, inactive, suspended, or archived (default: active) |
settings |
object | No | Arbitrary JSON settings |
Response 201:
{
"data": {
"id": "org-uuid",
"name": "Praxia Academy",
"description": "Educational consultants",
"logoUrl": null,
"status": "active",
"settings": {},
"createdAt": "2025-01-01T00:00:00.000Z",
"updatedAt": "2025-01-01T00:00:00.000Z"
}
}
GET /api/organizations/:id¶
Get a single organization by ID.
PlatformAdmin: Can view any organization.OrganizationAdmin: Can only view their own organization.
Path parameters:
| Parameter | Type | Description |
|---|---|---|
id |
string | Organization UUID |
Response 200:
{
"data": {
"id": "org-uuid",
"name": "Praxia Academy",
"description": "Educational consultants",
"logoUrl": null,
"status": "active",
"settings": {},
"createdAt": "2025-01-01T00:00:00.000Z",
"updatedAt": "2025-01-01T00:00:00.000Z"
}
}
Error responses:
| Code | Condition |
|---|---|
403 |
OrganizationAdmin attempting to view another org |
404 |
Organization not found |
PATCH /api/organizations/:id¶
Update organization details.
PlatformAdmin: Can update any organization.OrganizationAdmin: Can only update their own organization.
Path parameters:
| Parameter | Type | Description |
|---|---|---|
id |
string | Organization UUID |
Request body (all fields optional):
{
"name": "Praxia Academy (Updated)",
"description": "Updated description",
"logoUrl": "https://...",
"status": "inactive",
"settings": { "theme": "dark" },
"defaultTimezone": "America/New_York"
}
| Field | Type | Constraints |
|---|---|---|
name |
string | 1–255 characters |
description |
string | Free text |
logoUrl |
string | Must be a valid URL |
status |
string | active, inactive, suspended, or archived |
settings |
object | Arbitrary JSON settings |
defaultTimezone |
string | IANA timezone identifier (e.g. America/New_York); max 100 chars |
Response 200:
Error responses:
| Code | Condition |
|---|---|
403 |
OrganizationAdmin attempting to update another org |
404 |
Organization not found |
DELETE /api/organizations/:id¶
Archive an organization (soft delete). Sets status = 'archived'.
Min role: PlatformAdmin
Path parameters:
| Parameter | Type | Description |
|---|---|---|
id |
string | Organization UUID |
Response 200:
GET /api/organizations/:id/users¶
List members of an organization.
Access rules:
PlatformAdmincan list members of any org.OrganizationAdmin,Manager,Coachcan only list members of their own org.Managercannot seeOrganizationAdminmembers.Coachonly sees activeTeachermembers (used by the mentorship creation UI).
Path parameters:
| Parameter | Type | Description |
|---|---|---|
id |
string | Organization UUID |
Query parameters:
| Parameter | Type | Description |
|---|---|---|
limit |
integer | Max records (default: 100, max: 1000) |
offset |
integer | Records to skip (default: 0) |
search |
string | Filter by email or display name |
role |
string | Filter by org role (e.g. Coach, Teacher) |
Response 200:
{
"data": [
{
"id": "user-cuid",
"email": "jane@example.com",
"status": "active",
"firstName": "Jane",
"lastName": "Smith",
"avatarUrl": null,
"roleInOrganization": "Coach",
"isPrimary": true,
"membershipStatus": "active",
"joinedAt": "2025-01-15T09:00:00.000Z"
}
],
"meta": {
"total_count": 12
}
}
Error responses:
| Code | Condition |
|---|---|
403 |
Caller is not a member of this org (or viewing a restricted org) |
POST /api/organizations/:id/users¶
Add an existing user to the organization and assign them a role.
Min role: OrganizationAdmin
Path parameters:
| Parameter | Type | Description |
|---|---|---|
id |
string | Organization UUID |
Request body:
| Field | Type | Required | Constraints |
|---|---|---|---|
userId |
string | Yes | Must be an existing user CUID |
roleInOrganization |
string | Yes | One of OrganizationAdmin, Manager, Coach, Teacher |
isPrimary |
boolean | No | Mark as primary org (default: false) |
Response 201:
{
"data": {
"organizationId": "org-uuid",
"userId": "user-cuid",
"roleInOrganization": "Coach",
"isPrimary": false,
"membershipStatus": "active",
"joinedAt": "2025-04-01T12:00:00.000Z"
}
}
Error responses:
| Code | Condition |
|---|---|
403 |
Caller is modifying a different org |
409 |
User is already a member of this organization |
PATCH /api/organizations/:id/users/:userId¶
Update a member's role in the organization or re-enable a disabled membership.
Min role: OrganizationAdmin
Path parameters:
| Parameter | Type | Description |
|---|---|---|
id |
string | Organization UUID |
userId |
string | User CUID |
Request body (all fields optional):
| Field | Type | Constraints |
|---|---|---|
roleInOrganization |
string | OrganizationAdmin, Manager, Coach, or Teacher |
isPrimary |
boolean | Mark as primary org |
membershipStatus |
string | active or disabled |
Response 200:
{
"data": {
"organizationId": "org-uuid",
"userId": "user-cuid",
"roleInOrganization": "Manager",
"isPrimary": true,
"membershipStatus": "active",
"updatedAt": "2025-04-01T12:00:00.000Z"
}
}
Error responses:
| Code | Condition |
|---|---|
403 |
Caller is modifying a different org |
404 |
Membership not found |
DELETE /api/organizations/:id/users/:userId¶
Soft-disable a user's membership. Sets membershipStatus = 'disabled'. The user loses org-scoped access immediately but their data (mentorships, sessions, files) is preserved.
To restore access, call PATCH /api/organizations/:id/users/:userId with { "membershipStatus": "active" }.
Min role: OrganizationAdmin
Path parameters:
| Parameter | Type | Description |
|---|---|---|
id |
string | Organization UUID |
userId |
string | User CUID |
Response 200:
Error responses:
| Code | Condition |
|---|---|
403 |
Caller is modifying a different org |
404 |
Membership not found |
GET /api/organizations/:id/invites¶
List pending, non-expired invitations for the organization.
Access rules:
PlatformAdminandOwnercan list invites for any org.OrganizationAdmincan see all pending invites for their org.Managercan only see invites forCoachandTeacherroles.
Path parameters:
| Parameter | Type | Description |
|---|---|---|
id |
string | Organization UUID |
Response 200:
{
"data": [
{
"id": "invite-uuid",
"email": "newcoach@example.com",
"roleInOrganization": "Coach",
"status": "pending",
"expiresAt": "2025-04-15T12:00:00.000Z",
"createdAt": "2025-04-08T12:00:00.000Z"
}
],
"meta": {
"total_count": 3
}
}
POST /api/organizations/:id/invites¶
Create a new invitation or resend an existing pending invite to the same email address.
Access rules:
OrganizationAdmin,PlatformAdmin, andOwnercan invite any org role.Managercan only inviteCoachandTeacherroles.
If a pending invite already exists for the same email in this org, it is updated (expiry reset, token regenerated) and the invite email is resent. The response is 200 in that case; 201 for a new invite.
Path parameters:
| Parameter | Type | Description |
|---|---|---|
id |
string | Organization UUID |
Request body:
| Field | Type | Required | Constraints |
|---|---|---|---|
email |
string | Yes | Valid email address |
roleInOrganization |
string | Yes | OrganizationAdmin, Manager, Coach, or Teacher |
expiresInDays |
integer | No | 1–30 (default: 7) |
Response 201 (new invite):
{
"data": {
"id": "invite-uuid",
"email": "newcoach@example.com",
"roleInOrganization": "Coach",
"status": "pending",
"expiresAt": "2025-04-15T12:00:00.000Z",
"inviteToken": "abc123..."
}
}
inviteToken in non-production
The inviteToken field is only included in non-production environments to aid development and testing.
Error responses:
| Code | Condition |
|---|---|
403 |
Caller is from a different org, or Manager attempting to invite a Manager or above |
500 |
Failed to create or update the invite record |