The credential flows are symmetric across the two principal types. Sign in, get a token, refresh it before it expires, reset a forgotten password. The endpoints differ only in the prefix (/profile/... for User, /profile/customer/... for Customer); the request and response shapes are identical.
User sign-in
For staff and operators. Returns a JWT scoped to the User's roles and permitted orgs.
/profile/signinNo authThe same handler is mounted at /profile/user/signin — both paths work.
curl -X POST https://appengine.appmint.io/profile/signin \
-H "orgid: my-org" \
-H "Content-Type: application/json" \
-d '{ "email": "[email protected]", "password": "..." }'
| Field | Type | Description |
|---|---|---|
| email* | string | The user's email address. |
| password* | string | The user's password. |
Response:
{
"data": {
"token": "eyJhbGc...",
"refresh_token": "eyJhbGc...",
"user": {
"pk": "user-...",
"email": "[email protected]",
"firstName": "Admin",
"lastName": "User",
"roles": ["ConfigAdmin"],
"groups": []
}
}
}
Customer sign-in
For end-buyers and member-portal users. Token is single-org by design — Customers can't switch tenants.
/profile/customer/signinNo authcurl -X POST https://appengine.appmint.io/profile/customer/signin \
-H "orgid: my-org" \
-H "Content-Type: application/json" \
-d '{ "email": "[email protected]", "password": "..." }'
Same envelope; the user object will have roles: ["customer"].
Sign-up
User signup creates a staff account; Customer signup creates an end-user. Both auto-sign-in on success and return a token in the same envelope.
/profile/signupNo auth/profile/customer/signupNo authcurl -X POST https://appengine.appmint.io/profile/customer/signup \
-H "orgid: my-org" \
-H "Content-Type: application/json" \
-d '{
"email": "[email protected]",
"password": "at-least-8-chars",
"firstName": "Alice",
"lastName": "Doe",
"phone": "+15551234567"
}'
| Field | Type | Description |
|---|---|---|
| email* | string | Must be unique within the org. |
| password* | string | Plain text over the wire; AppEngine bcrypts it server-side. TLS-only. |
| firstName | string | Optional but recommended. |
| lastName | string | Optional. |
| phone | string | E.164 format. Optional unless you've enabled SMS 2FA. |
User signup additionally accepts a roles array — only callable by an existing admin (the route is not public). For self-service User signup, expose it via your admin tooling rather than the storefront.
Token refresh
Access tokens are short-lived. When yours expires (or you get a 401), exchange the refresh token for a new pair.
/profile/user/refreshNo auth/profile/customer/refreshNo authcurl -X POST https://appengine.appmint.io/profile/customer/refresh \
-H "orgid: my-org" \
-H "Content-Type: application/json" \
-d '{ "refresh_token": "eyJhbGc..." }'
{
"data": {
"token": "eyJhbGc...",
"refresh_token": "eyJhbGc..."
}
}
A common pattern: stash both tokens client-side, intercept 401 responses, transparently refresh, retry the original request once.
Sign-out
/profile/signoutNo authThe endpoint accepts the current token and revokes the session record server-side. Client should also clear its local token storage.
Forgot password
Three-step flow: request a reset email, optionally validate the token, post a new password.
/profile/customer/password/forgot/{email}No auth/profile/customer/password/validate-tokenNo auth/profile/customer/password/resetNo auth(User equivalents: /profile/password/forgot/{email}, /profile/password/validate-token, /profile/password/reset.)
# 1. Send the email
curl https://appengine.appmint.io/profile/customer/password/forgot/[email protected] \
-H "orgid: my-org"
# 2. (Optional) Validate the token before showing the reset form
curl -X POST https://appengine.appmint.io/profile/customer/password/validate-token \
-H "orgid: my-org" -H "Content-Type: application/json" \
-d '{ "email": "[email protected]", "token": "..." }'
# 3. Submit the new password
curl -X POST https://appengine.appmint.io/profile/customer/password/reset \
-H "orgid: my-org" -H "Content-Type: application/json" \
-d '{ "token": "...", "password": "new-password" }'
The email comes from the broadcast module using whichever email provider you've connected (SendGrid, Mailgun, AWS SES). The reset link points to your site, not to AppEngine — configure the redirect URL in the org settings.
Change password
For an authenticated user changing their own password (no token from email).
/profile/password/changeJWT/profile/customer/password/changeJWTcurl -X POST https://appengine.appmint.io/profile/customer/password/change \
-H "orgid: my-org" \
-H "Authorization: Bearer $JWT" \
-H "Content-Type: application/json" \
-d '{ "currentPassword": "...", "newPassword": "..." }'
Whoami
After sign-in, fetch the current principal:
/profile/whoamiJWTUseful for hydrating client state after a page reload, when you have the token in cookies but not the user record.
Customer existence check
Before a sign-up form, you can probe whether an email is already taken:
/profile/customer/exist/{emailOrUsername}No authReturns { exists: true|false, user?: { email, username } }. Don't lean on this for security checks — it's a UX helper, not an authorization tool.