Appearance
Members and invitations
Members are users with a role in an organization. The four roles form a ladder:
viewer— read-only access to flags, configs, segments, evaluation, and audit.editor— adds: create / update / delete flags, configs, segments, environments, and projects.admin— adds: org settings, API key minting, member invitations.owner— adds: change member roles, delete the org.
Bearer tokens go through a different gate (scopes) and are not subject to the role ladder for resource access — but org-management endpoints (member updates, invitations, API key minting, org delete) are session-only.
List members
http
GET /api/v1/orgs/{slug}/membersResponse: 200 → Member[]
json
[
{
"userId": "9f7a32b5-…",
"email": "pat@example.com",
"displayName": "Pat Doe",
"role": "owner",
"createdAt": "2026-04-12T10:00:00Z"
}
]Soft-deleted users are filtered out.
Update a member's role
http
PATCH /api/v1/orgs/{slug}/members/{userId}
Cookie: actuator_session=…
Content-Type: application/json
{ "role": "editor" }Session-authenticated, owner role only. Same-role PATCH is a no-op (returns the current row, no audit entry).
Last-owner guard: demoting the last active owner returns 409 last_owner_cannot_demote_or_remove. Promote someone else to owner first.
Response: 200 → MemberErrors: 400 invalid_request, 403 insufficient_role, 404 not_found, 409 last_owner_cannot_demote_or_remove.
Remove a member
http
DELETE /api/v1/orgs/{slug}/members/{userId}
Cookie: actuator_session=…Session-authenticated, owner role only. The last-owner guard applies.
Response: 204 No ContentErrors: 403 insufficient_role, 404 not_found, 409 last_owner_cannot_demote_or_remove.
Invitations
Invitations let an admin or owner add a user to the org. The flow:
- Admin mints an invitation (
POST /api/v1/orgs/{slug}/invitations). The server returns the rawacceptUrlonce — share it via the auto-sent email or by hand. - The invitee follows the link, lands on
/app/invite/{token}. - The dashboard calls
GET /api/v1/invitations/{token}(unauth) to render org name and role. - The invitee submits, calling
POST /api/v1/invitations/{token}/accept(unauth) — this creates the user (if new), attaches the membership, mints a session, and sets theactuator_sessioncookie.
List pending invitations
http
GET /api/v1/orgs/{slug}/invitations
Cookie: actuator_session=…Session-authenticated, admin or owner. Used and expired invitations are filtered out.
Response: 200 → Invitation[]
json
[
{
"id": "9f7a32b5-…",
"email": "newhire@example.com",
"role": "editor",
"expiresAt": "2026-05-13T10:00:00Z",
"createdAt": "2026-05-06T10:00:00Z"
}
]Mint an invitation
http
POST /api/v1/orgs/{slug}/invitations
Cookie: actuator_session=…
Content-Type: application/json
{
"email": "newhire@example.com",
"role": "editor"
}Session-authenticated, admin or owner. Returns the invitation row plus the one-shot raw token and accept URL — store or share these immediately, the server stores only the SHA-256 hash.
An email is sent automatically via the configured mailer. Admins on self-hosted deploys without SMTP can share the acceptUrl directly.
Response: 201 → InvitationMintResponse
json
{
"id": "9f7a32b5-…",
"email": "newhire@example.com",
"role": "editor",
"expiresAt": "…",
"token": "inv_…",
"acceptUrl": "https://useactuator.ai/app/invite/inv_…"
}Errors: 400 invalid_request, 403 insufficient_role, 409 already_member, 409 invitation_pending.
Revoke an invitation
http
DELETE /api/v1/orgs/{slug}/invitations/{id}
Cookie: actuator_session=…Session-authenticated, admin or owner. Revokes a pending invitation. Already-redeemed invitations are preserved as audit-trail evidence and return 404.
Response: 204 No ContentErrors: 403 insufficient_role, 404 not_found.
Public invitation endpoints
These are unauthenticated — the token in the URL is the credential. See Authentication → Invitation accept.