docs
/
AppEngine API

User authentication

Operator sign-in, invitations, password management and session endpoints.

Users are the operators of a tenant. Everything here lives on UsersController, mounted as @Controller(['profile', 'user']) — so every path below also answers under /user/….

Password sign-in

POST/profile/signinNo auth

Also /profile/user/signin, /user/signin, /user/user/signin.

{ "email": "[email protected]", "password": "…" }

Requires the orgid header. Four possible 200 responses — see Sign-in outcomes. Only one contains a token.

Bad credentials are 400 Invalid username or password, recorded as a failed login activity. A blocked device fingerprint is 403 regardless of credentials.

Temporary passwords

A user signing in with a temporary password — stored hashed in resetToken alongside a temporaryPassword flag — gets no session:

{ "requiresPasswordChange": true, "message": "Temporary password used. Please set a new password.", "userId": "…", "email": "…" }

POS passcode and NFC

POST/profile/signin/passcodeNo auth

Fast sign-in for point-of-sale, keyed on the employee id.

{ "employeeId": "E-1042", "pin": "482913", "cardUid": "04A2B3C4D5" }
FieldTypeDescription
employeeId requiredstringThe employee id. An NFC card carries only this value.
pinstringSix digits. Required or not depending on the org's passcode-vs-instant setting.
cardUidstringThe card's hardware UID when signing in by tap. Validated against the registered card list.
This path deliberately skips the 2FA and new-device challenges — a shared terminal would otherwise be unusable.

Managing the credentials:

ActionEndpoint
Set or change a passcode, link an employeeIdPOST /profile/…/passcode (set)
Remove passcode loginremove-passcode handler
Register / revoke an NFC cardcard registry handlers

A user may always manage their own quick-login credentials. Doing it for someone else requires RootSystem, RootAdmin, ConfigAdmin, System or Owner; otherwise 403.

Session

GET/profile/whoamiJWT
GET/profile/who-isJWT
GET/profileJWT
POST/profile/signoutJWT
POST/profile/user/refreshJWT
POST/profile/session-accessJWT
GET/profile/system-orgsJWT

Invitations

Users are invited, not self-registered.

POST/profile/user/invite/sendJWT
POST/profile/user/invite/resend/:invitationIdJWT
POST/profile/user/invite/validateNo auth
POST/profile/user/invite/completeNo auth

Invitations are user_invitation records. validate confirms a token before showing the form; complete sets the password and activates the account.

Profiles

GET/profile/user/profile/:emailOrUsernameJWT
POST/profile/user/:userId/metaJWT
DELETE/profile/user/delete/:emailOrUsernameJWT
DELETE/profile/user/selfJWT

Reading or writing your own profile bypasses role checks — JwtAuthGuard compares the target record's sk with the caller's before any decorator is consulted.

/profile/user/self is self-service account deletion, distinct from an admin deleting someone.

GET/profile/user/magic-linkNo auth
POST/profile/user/magic-link/redirectNo auth
GET/profile/magic-linkNo auth
POST/profile/magic-link/redirectNo auth
GET/profile/code/:emailNo auth

A magic-link token is a short-lived JWT whose payload is { clientHost, email, expires } — signed the same way as a session token, so it verifies through the same machinery.

Shared-site access

GET/profile/user/shared-site-auth/:tokenNo auth

Exchanges a share token for access — the share block on BaseModel, with its optional passcode and expiry.

Application registration

For client apps that need their own identity:

POST/profile/app/registerNo auth
POST/profile/app/keyJWT
POST/profile/validate-app-keyNo auth

Registration returns { appConfig, token }. Backed by the client_app datatype.

Global login

POST/profile/global-loginNo auth

Signs in across orgs rather than against one tenant. Pair with GET /repository/org/user/:email to build an org switcher.

Guest access

POST/profile/guest/authNo auth

Issues a token for an anonymous guest customer — enough to hold a cart or a draft booking before the visitor commits to an account.