Common headers (all space routes)
HeaderNotes
AuthorizationRequired. Bearer <token>
X-Tenant-IdRequired. Tenant the space belongs to.
GET
/space
List spaces

Returns all active spaces the authenticated user is a member of within the tenant.

Response

{
  "spaces": [
    {
      "id": 1,
      "name": "My Space",
      "code": "my-space",
      "description": null,
      "isActive": true,
      "role": "admin"
    }
  ]
}
POST
/space
Create a space

Creates a new space and adds the caller as an admin member. Returns 409 if the code is already taken within the tenant.

Request body

FieldNotes
nameRequired.
codeRequired. Unique within the tenant.
descriptionOptional.

Response (201)

{
  "id": 1,
  "name": "My Space",
  "code": "my-space",
  "description": null,
  "role": "admin"
}
GET
/space/:id
Get a space

Returns a single space. The caller must be an active member. Returns 404 if not found or not a member.

Response

{
  "space": {
    "id": 1,
    "name": "My Space",
    "code": "my-space",
    "description": null,
    "isActive": true,
    "role": "admin"
  }
}
PATCH
/space/:id
Update a space

Updates one or more fields on a space. Requires admin space role.

Request body (all fields optional)

FieldNotes
nameOptional.
codeOptional.
descriptionOptional.
isActiveOptional. Boolean.
DELETE
/space/:id
Deactivate a space

Soft-deletes the space by setting is_active = 0. Requires admin space role.

Response

{
  "success": true
}
GET
/space/:id/me
Get own membership

Returns the caller's membership record and syncs their identity from the token. Returns 403 if not a member.

Response

{
  "id": 1,
  "userId": "user-uuid",
  "email": "user@example.com",
  "firstName": "Jane",
  "lastName": "Doe",
  "displayName": null,
  "role": "admin"
}
GET
/space/:id/users
List space users

Returns all members of the space. Requires membership.

Response

{
  "users": [
    {
      "id": 1,
      "userId": "user-uuid",
      "email": "user@example.com",
      "firstName": null,
      "lastName": null,
      "displayName": null,
      "role": "admin",
      "isActive": true,
      "lastSyncedAt": null,
      "lastSeenAt": null
    }
  ]
}
GET
/space/:id/users/:spaceUserId
Get a space user

Returns a single space member by their space_users.id. Requires membership.

PATCH
/space/:id/users/:spaceUserId
Update a space user

Updates a member's role or active status. Requires admin space role.

Request body (all fields optional)

FieldNotes
roleOptional. e.g. editor, admin.
isActiveOptional. Boolean.
DELETE
/space/:id/users/:spaceUserId
Remove a space user

Permanently removes the member row from the space. Requires admin space role.

Response

{
  "success": true
}
GET
/space/:id/invites
List invitations

Returns all invitations for the space ordered by creation date. Requires admin space role.

Response

{
  "invites": [
    {
      "id": 1,
      "email": "invite@example.com",
      "role": "editor",
      "status": "pending",
      "expiresAt": "2026-08-20T00:00:00.000Z",
      "createdAt": "2026-08-13T00:00:00.000Z"
    }
  ]
}
POST
/space/:id/invite
Create an invitation

Creates a 7-day invitation for an email address. Returns a one-time token that must be sent to the invitee. Requires admin space role.

Request body

FieldNotes
emailRequired.
roleRequired. Role to assign on acceptance.

Response (201)

{
  "inviteId": 1,
  "email": "invite@example.com",
  "role": "editor",
  "status": "pending",
  "expiresAt": "2026-08-20T00:00:00.000Z",
  "token": "raw-token-to-send-to-invitee"
}
DELETE
/space/:id/invite/:inviteId
Revoke an invitation

Sets a pending invitation's status to revoked. Returns 404 if the invitation is not pending. Requires admin space role.

Response

{
  "success": true
}
POST
/space/:id/invite/accept
Accept an invitation

Authenticates the caller against the invitation token and adds them as a space member. Returns 404 if the token is invalid or already used, 422 if the email or tenant does not match, and 410 if the invite has expired.

Request body

FieldNotes
tokenRequired. Raw token from the invitation email.

Response (201)

{
  "spaceUserId": 1,
  "role": "editor"
}