Skip to content

Access: members, roles, keys

Who may sign in, what they may do once they have, which clients they may see, and the keys that let a script act on their behalf.

61 endpoints across 8 groups. A permission written module.resource.action:own is scoped: :own covers rows that are yours, :any covers everyone’s, and :any satisfies a check for :own.

EndpointPermission
GET /membersmembers.member.read
PATCH /members/{membership_id}members.member.write
DELETE /members/{membership_id}members.member.write
GET /members/{membership_id}/permissionsmembers.member.read
PUT /members/{membership_id}/rolessettings.roles.manage
DELETE /members/{membership_id}/two-factormembers.member.write
POST /members/invitemembers.member.write
GET /members/lookupDeliberately open
Parameters and schemas per endpoint

List Members — The team, for Instellingen → Gebruikers — staff only.

Permission: members.member.read

Returns: 200 · MemberRead[]

Update Member Role — Swap this membership’s system role; any custom roles it also holds are untouched.

Permission: members.member.write

Path parameters: membership_id

Request body: MemberRoleUpdate

Returns: 200 · MemberRead

Revoke Member

Permission: members.member.write

Path parameters: membership_id

Returns: 204

GET /api/v1/members/{membership_id}/permissions

Section titled “GET /api/v1/members/{membership_id}/permissions”

Member Permissions — A member’s effective permissions — the union over every role they hold.

Permission: members.member.read

Path parameters: membership_id

Returns: 200 · EffectivePermissions

Set Member Roles — Replace a membership’s whole role set in one save. A user may hold several roles.

Permission: settings.roles.manage

Path parameters: membership_id

Request body: MembershipRolesUpdate

Returns: 200 · EffectivePermissions

DELETE /api/v1/members/{membership_id}/two-factor

Section titled “DELETE /api/v1/members/{membership_id}/two-factor”

Reset Member Two Factor — Reset a member’s 2FA — the lost-phone escape hatch (docs/TWOFACTOR.md).

Permission: members.member.write

Path parameters: membership_id

Returns: 204

Invite Member

Permission: members.member.write

Request body: MemberInvite

Returns: 201 · MemberRead

Lookup Members — Name/email of org staff, for assignee/approver pickers. Open to every member.

Permission: Deliberately open

Query parameters:

NameTypeMeaning
permissionstringOnly members who hold this permission at some scope — e.g. tasks.task.write for an assignee picker, leave.request.approve for an approver picker. Omit for everyone in the org.
include_clientsbooleanAlso return client-role memberships (portal users). Off by default: every picker built on this endpoint means staff. (default false)

Returns: 200 · MemberLookup[]

EndpointPermission
GET /permissions/catalogDeliberately open
GET /rolessettings.roles.manage
POST /rolessettings.roles.manage
PATCH /roles/{role_id}settings.roles.manage
DELETE /roles/{role_id}settings.roles.manage
Parameters and schemas per endpoint

Permission Catalog

Permission: Deliberately open

Returns: 200 · PermissionCatalog

List Roles

Permission: settings.roles.manage

Returns: 200 · RoleRead[]

Create Role — Create a custom role, optionally seeded from an existing one.

Permission: settings.roles.manage

Query parameters:

NameTypeMeaning
fromstringDuplicate this role’s permissions into the new one.

Request body: RoleCreate

Returns: 201 · RoleRead

Update Role — Rename, reposition, or replace the whole permission set in one save.

Permission: settings.roles.manage

Path parameters: role_id

Request body: RoleUpdate

Returns: 200 · RoleRead

Delete Role — System roles are not deletable — they are what memberships.role still collapses to.

Permission: settings.roles.manage

Path parameters: role_id

Returns: 204

EndpointPermission
GET /users/{id}Deliberately open
PATCH /users/{id}Deliberately open
DELETE /users/{id}Deliberately open
GET /users/meDeliberately open
PATCH /users/meDeliberately open
POST /users/me/emailDeliberately open
Parameters and schemas per endpoint

Users:User

Permission: Deliberately open

Path parameters: id

Returns: 200 · UserRead

Users:Patch User

Permission: Deliberately open

Path parameters: id

Request body: UserUpdate

Returns: 200 · UserRead

Users:Delete User

Permission: Deliberately open

Path parameters: id

Returns: 204

Users:Current User

Permission: Deliberately open

Returns: 200 · UserRead

Users:Patch Current User

Permission: Deliberately open

Request body: UserUpdate

Returns: 200 · UserRead

Users:Change Email — Change the caller’s own sign-in address. Costs the current password; the new address must be free (emails are unique case-insensitively and stored lowercase, like invites). Verification state resets — the new address has never been proven.

Permission: Deliberately open

Request body: EmailChange

Returns: 200 · UserRead

EndpointPermission
GET /api-keysapikeys.personal.manage
POST /api-keysapikeys.personal.manage
POST /api-keys/{key_id}/revokeapikeys.personal.manage
GET /service-accountsapikeys.service_account.manage
POST /service-accountsapikeys.service_account.manage
DELETE /service-accounts/{account_id}apikeys.service_account.manage
GET /service-accounts/{account_id}/keysapikeys.service_account.manage
POST /service-accounts/{account_id}/keysapikeys.service_account.manage
Parameters and schemas per endpoint

List Personal Keys

Permission: apikeys.personal.manage

Returns: 200 · ApiKeyRead[]

Create Personal Key

Permission: apikeys.personal.manage

Request body: ApiKeyCreate

Returns: 201 · ApiKeyCreated

Revoke Key — Revoke a key. Own personal keys need apikeys.personal.manage; the service refines to apikeys.service_account.manage for a service-account key.

Permission: apikeys.personal.manage

Path parameters: key_id

Returns: 200 · ApiKeyRead

List Service Accounts — Each account with its keys — one grouped read, not one request per account (#290).

Permission: apikeys.service_account.manage

Returns: 200 · ServiceAccountRead[]

Create Service Account

Permission: apikeys.service_account.manage

Request body: ServiceAccountCreate

Returns: 201 · ServiceAccountRead

DELETE /api/v1/service-accounts/{account_id}

Section titled “DELETE /api/v1/service-accounts/{account_id}”

Delete Service Account

Permission: apikeys.service_account.manage

Path parameters: account_id

Returns: 204

GET /api/v1/service-accounts/{account_id}/keys

Section titled “GET /api/v1/service-accounts/{account_id}/keys”

List Service Account Keys

Permission: apikeys.service_account.manage

Path parameters: account_id

Returns: 200 · ApiKeyRead[]

POST /api/v1/service-accounts/{account_id}/keys

Section titled “POST /api/v1/service-accounts/{account_id}/keys”

Create Service Account Key

Permission: apikeys.service_account.manage

Path parameters: account_id

Request body: ApiKeyCreate

Returns: 201 · ApiKeyCreated

EndpointPermission
GET /oauth/connectionsapikeys.personal.manage
DELETE /oauth/connections/{client_pk}apikeys.personal.manage
GET /oauth/consentDeliberately open
POST /oauth/consentapikeys.personal.manage
GET /oauth/metadata/authorization-serverDeliberately open
GET /oauth/metadata/protected-resourceDeliberately open
POST /oauth/registerDeliberately open
POST /oauth/revokeDeliberately open
POST /oauth/tokenDeliberately open
Parameters and schemas per endpoint

List Connections — The clients this user has connected. Counted in one grouped read, not one query per row.

Permission: apikeys.personal.manage

Returns: 200 · app__core__oauth__router__ConnectionRead[]

DELETE /api/v1/oauth/connections/{client_pk}

Section titled “DELETE /api/v1/oauth/connections/{client_pk}”

Disconnect — Disconnect a client: revoke it, and every key it ever issued goes with it.

Permission: apikeys.personal.manage

Path parameters: client_pk

Returns: 204

Consent Request — Validate an authorization request and describe it, without writing anything.

Permission: Deliberately open

Query parameters:

NameTypeMeaning
client_idstring · required
redirect_uristring · required
scopestring(default “)
resourcestring

Returns: 200 · ConsentRequest

Approve Consent — Approve, and get the URL to send the browser back to.

Permission: apikeys.personal.manage

Request body: ConsentApproval

Returns: 200 · ConsentResult

GET /api/v1/oauth/metadata/authorization-server

Section titled “GET /api/v1/oauth/metadata/authorization-server”

Authorization Server Metadata — Served here and proxied by the web app at /.well-known/oauth-authorization-server.

Permission: Deliberately open

Returns: 200 · object

GET /api/v1/oauth/metadata/protected-resource

Section titled “GET /api/v1/oauth/metadata/protected-resource”

Protected Resource Metadata — One document per /mcp URL, section segment included.

Permission: Deliberately open

Query parameters:

NameTypeMeaning
resource_pathstring(default /mcp)

Returns: 200 · object

Register Client — Register a client. Registering grants nothing — it names a thing a person may later consent to, and until somebody does, the row can read no byte of tenant data.

Permission: Deliberately open

Request body: ClientRegistration

Returns: 201

Revoke — Always 200. A revocation endpoint that distinguishes “revoked” from “no such token” is a token oracle, and the caller can do nothing with the difference anyway (RFC 7009 §2.2).

Permission: Deliberately open

Returns: 200

Tokenauthorization_code and refresh_token. Form-encoded, per the RFC.

Permission: Deliberately open

Returns: 200

EndpointPermission
GET /auth/2faDeliberately open
POST /auth/2fa/backup-codesDeliberately open
POST /auth/2fa/challenge/smsDeliberately open
POST /auth/2fa/confirmDeliberately open
POST /auth/2fa/disableDeliberately open
POST /auth/2fa/setupDeliberately open
DELETE /auth/2fa/smsDeliberately open
POST /auth/2fa/sms/confirmDeliberately open
POST /auth/2fa/sms/setupDeliberately open
POST /auth/2fa/verifyDeliberately open
POST /auth/forgot-passwordDeliberately open
POST /auth/loginDeliberately open
POST /auth/logoutDeliberately open
GET /auth/oidc/callbackDeliberately open
GET /auth/oidc/loginDeliberately open
POST /auth/registerDeliberately open
POST /auth/request-verify-tokenDeliberately open
POST /auth/reset-passwordDeliberately open
POST /auth/verifyDeliberately open
Parameters and schemas per endpoint

Auth:Twofactor.Status

Permission: Deliberately open

Returns: 200 · TwoFactorStatus

Auth:Twofactor.Backup Codes — A fresh set (shown once), invalidating every previous code. Costs a current TOTP code — a stolen session alone must not be able to mint recovery codes.

Permission: Deliberately open

Request body: CodeIn

Returns: 200 · BackupCodesOut

Auth:Twofactor.Challenge Sms — Text a login code to the enrolled number — only for accounts that confirmed one.

Permission: Deliberately open

Request body: ChallengeSms

Returns: 200 · SmsSendOut

Auth:Twofactor.Confirm — A valid code from the freshly-scanned app is what turns 2FA on — and mints the backup codes, returned exactly once.

Permission: Deliberately open

Request body: CodeIn

Returns: 200 · BackupCodesOut

Auth:Twofactor.Disable — Turn 2FA off for the caller’s own account. A confirmed setup costs the password (a stolen session must not be able to strip the second factor); abandoning an unconfirmed setup is free. Lost everything? That is what the org admin’s reset is for (members.py).

Permission: Deliberately open

Request body: DisableIn

Returns: 204

Auth:Twofactor.Setup — Start (or restart) enrollment: mint a secret, return it as QR + manual key.

Permission: Deliberately open

Returns: 200 · TwoFactorSetupOut

Auth:Twofactor.Sms Disable — Drop the SMS factor (TOTP + backup codes remain — never leaves the account factor-less).

Permission: Deliberately open

Returns: 204

Auth:Twofactor.Sms Confirm

Permission: Deliberately open

Request body: CodeIn

Returns: 204

Auth:Twofactor.Sms Setup — Register a number for SMS codes: it becomes usable only after echoing a code sent to it. SMS is an additional factor on a confirmed TOTP setup, never the only one — a number can be re-registered, but 2FA cannot start out SMS-only.

Permission: Deliberately open

Request body: SmsSetupIn

Returns: 200 · SmsSendOut

Auth:Twofactor.Verify — Redeem a login challenge with a code from any enrolled factor → session cookie.

Permission: Deliberately open

Request body: ChallengeVerify

Returns: 200

Reset:Forgot Password

Permission: Deliberately open

Request body: Body_reset_forgot_password_api_v1_auth_forgot_password_post

Returns: 202

Auth:Cookie.Login — Password login, for the org this hostname resolves to.

Permission: Deliberately open

Returns: 200 · LoginChallenge

Auth:Cookie.Logout

Permission: Deliberately open

Returns: 200

Oidc Callback

Permission: Deliberately open

Returns: 200

Oidc Login

Permission: Deliberately open

Returns: 200

Register:Register

Permission: Deliberately open

Request body: UserCreate

Returns: 201 · UserRead

Verify:Request-Token

Permission: Deliberately open

Request body: Body_verify_request_token_api_v1_auth_request_verify_token_post

Returns: 202

Reset:Reset Password

Permission: Deliberately open

Request body: Body_reset_reset_password_api_v1_auth_reset_password_post

Returns: 200

Verify:Verify

Permission: Deliberately open

Request body: Body_verify_verify_api_v1_auth_verify_post

Returns: 200 · UserRead

EndpointPermission
GET /settings/ssosettings.auth.manage
PUT /settings/ssosettings.auth.manage
POST /settings/sso/testsettings.auth.manage
Parameters and schemas per endpoint

Get Sso Settings

Permission: settings.auth.manage

Returns: 200 · SsoSettingsRead

Save Sso Settings

Permission: settings.auth.manage

Request body: SsoSettingsWrite

Returns: 200 · SsoSettingsRead

Test Sso Settings

Permission: settings.auth.manage

Returns: 200 · SsoTestResult

EndpointPermission
GET /settings/service-accesssettings.service_access.manage
POST /settings/service-accesssettings.service_access.manage
DELETE /settings/service-accesssettings.service_access.manage
Parameters and schemas per endpoint

Service Access Status

Permission: settings.service_access.manage

Returns: 200 · ServiceAccessStatus

Issue Service Pin

Permission: settings.service_access.manage

Returns: 201 · ServiceAccessIssued

Revoke Service Pin

Permission: settings.service_access.manage

Returns: 200 · ServiceAccessStatus