Skip to main content

Users & Organizations

Manage user accounts, organizations, member invitations, and role assignments. Users can belong to multiple organizations with different roles.

Authentication Endpoints

These endpoints do not require an existing access token.

Register

Create a new user account with an optional organization.

Request Body

string
required
User email address.
string
required
Password (minimum 8 characters).
string
required
Display name (1-255 characters).
string
Organization name. If provided, a new organization is created with the user as owner.

Response (201)

The first user to register on the platform is automatically promoted to superadmin.

Login

Authenticate with email and password.

Request Body

string
required
User email address.
string
required
User password.

Response (200)

Same shape as register response.

Refresh Token

Exchange a valid refresh token for new access and refresh tokens.

Request Body

string
required
Valid refresh token.

Response (200)

Same shape as register response with new tokens.
There is no server-side logout endpoint. Logout is performed client-side by discarding the stored access and refresh tokens.

User Profile

Get Current User

Get the authenticated user’s profile and organization memberships.
All API requests require a valid JWT token in the Authorization: Bearer <token> header. The API Gateway decodes the JWT and forwards auth context (user-id, organization-id, user-email, x-platform-role, x-org-role) as headers to downstream services.

Response (200)

boolean
object

Email Verification

Verify Email

Verify a user’s email address using the token sent via email.

Request Body

string
required
Email verification token.

Resend OTP

Request a one-time password code sent to the user’s email.

Request Body

string
required
User email address.

Verify OTP

Verify an OTP code.

Request Body

string
required
User email address.
string
required
OTP code.

Password Management

Forgot Password

Request a password reset email.

Request Body

string
required
User email address.

Reset Password

Complete a password reset using the token from the reset email.

Request Body

string
required
Password reset token.
string
required
New password (minimum 8 characters).

Organization Management

All API requests require a valid JWT token in the Authorization: Bearer <token> header. The API Gateway decodes the JWT and forwards auth context (user-id, organization-id, user-email, x-platform-role, x-org-role) as headers to downstream services.

Update Organization

Update organization settings.

Path Parameters

string
required
Organization UUID.

Request Body

string
Updated organization name.
object
Organization settings (e.g., require_publish_approval).

List Organization Members

Get all members of an organization with their roles.

Path Parameters

string
required
Organization UUID.

Response (200)

object[]

Get Seat Usage

Get the organization’s member counts, pending invitations, plan seat limit and remaining capacity. Used by Settings → Team (the seat count above the invite form) and the Analytics dashboard “Users” card. The caller must be a member of :id (403 otherwise — there is no superadmin bypass). remaining is the same figure Invite Member refuses on, so a page that shows “0 seats left” agrees with the refusal the invite would get. An organization with no billing account yet is provisioned on the free plan before it is counted — exactly what the invite and acceptance paths do.

Path Parameters

string
required
Organization UUID.

Response (200)

number
Total organization members.
number
Members with last_login_at within the last 30 days.
number
Unused, unexpired invitations, counted once per email. Each one reserves a seat.
number | null
Plan seat limit. null means unlimited.
number | null
Seats left to invite into: maxUsers - totalMembers - pendingInvitations, never below 0. null when unlimited.

Invite Member

Send an invitation email to add a new member to the organization. Seats are validated here, when the invitation is sent — never only at acceptance — so an invitee is never handed an invitation the organization cannot honour:
  • Pending invitations reserve seats: the request is refused when totalMembers + pendingInvitations >= maxUsers.
  • The check applies to every inviter, platform superadmins included.
  • An organization with no billing account is treated as the free plan (the same plan acceptance would provision), never as unlimited.
Acceptance re-checks the limit under a row lock, so two invitations racing for the last seat cannot both be accepted. Only an owner or admin of the organization may invite (a platform superadmin bypasses this role check, but not the seat check). The organization is the caller’s active one.

Request Body

string
required
Email address to invite.
string
required
Role to assign: admin, member, or viewer. owner cannot be granted by an invitation — an owner changes an existing member’s role instead.

Errors

403
The caller is not an owner or admin of the organization. Nothing is sent.
400
role is not one of admin, member, viewer, or email is invalid.
400
No seat is left once members and pending invitations are counted. The message names the limit, for example Seat limit reached: your plan allows a maximum of 3 members (2 members and 1 pending invitation). Upgrade your plan to invite more users. Upgrade the plan or remove a member to invite more people.

Get Invitation

Public. Returns the details of a pending invitation so the accept page can decide whether to offer sign-up or log-in.

Path Parameters

string
required
Invitation token from the invitation email.

Response

string
The invited email address.
string
Organization being joined.
string
Organization slug.
string
Role the member will receive.
boolean
Whether the invited email already has an account. true means the person must log in and use Accept Invitation (logged in).

Accept Invitation (new account)

Public. Accepts an invitation by creating a new account for the invited email, adds it to the organization, and returns a session. This endpoint never signs in to an existing account.

Request Body

string
required
Invitation token.
string
required
Password for the new account (minimum 8 characters).
string
required
Display name for the new account.

Errors

409
An account already exists for the invited email. No session is issued, nothing is changed, and the invitation stays valid — log in and use Accept Invitation (logged in).
400
The token is unknown, expired, or already used.
400
The organization has reached its plan’s member limit.

Accept Invitation (logged in)

Requires Authorization: Bearer <access token>. Accepts an invitation as the logged-in user. The account’s email must match the invited email (case-insensitive). Returns refreshed accessToken/refreshToken/user whose organization list includes the organization just joined. Accepting an invitation to an organization you already belong to succeeds with alreadyMember: true.

Request Body

string
required
Invitation token.

Response

string
The organization joined.
boolean
true when the user was already a member.

Errors

401
Missing, invalid, forged, or expired access token.
403
The invitation was sent to a different email address. Nothing is changed.
403
The account is suspended.
400
The token is unknown, expired, or already used.
400
The organization has reached its plan’s member limit.

Update Member Role

Change a member’s role within the organization.

Path Parameters

string
required
Organization UUID.
string
required
Member’s user UUID.

Request Body

string
required
New role: admin, editor, or viewer.
Only organization owners and admins can change member roles. Owners cannot have their role changed.

Remove Member

Remove a member from the organization.

Path Parameters

string
required
Organization UUID.
string
required
Member’s user UUID.

Organization Roles