Mobile App — Authentication
Authentication endpoints for the in-store staff/POS mobile app. These are not Directus user-token flows. Instead they issue a per-device, per-workspace mobile session consisting of a short-lived access token and a long-lived refresh token (JWTs minted by MobileAppAuthService).
There are two ways to obtain a mobile session:
- Pairing code — a 6-digit code is generated by a workspace admin (see Users) and delivered to the device's operator, who exchanges it at
POST /mobile-app/auth/pair. - Directus credentials — an existing workspace member logs in at
POST /mobile-app/auth/loginand receives one session profile for every workspace they belong to.
Token model (from MobileAppAuthService):
- Access token — JWT,
type: "access", expires in 15 minutes (expires_in: 900). Sent on every mobile-app runtime request in theX-Mobile-Tokenheader. - Refresh token — JWT,
type: "refresh", expires in 30 days. Exchanged atPOST /mobile-app/auth/refreshfor a new access/refresh pair.
The access token JWT encodes the mobile_app_user_id (sub), workspace_id, and session_id, so all downstream runtime calls (see Config & Runtime) are workspace-scoped without extra headers.
Auth summary per endpoint:
| Endpoint | Auth |
|---|---|
POST /mobile-app/auth/login | Public (email + password in body) |
POST /mobile-app/auth/pair | Public (pairing code in body; IP rate-limited) |
POST /mobile-app/auth/refresh | Public (valid refresh token in body) |
GET /mobile-app/me | Mobile session (X-Mobile-Token) |
POST /mobile-app/auth/logout | Mobile session (X-Mobile-Token) |
No SDK methods. The
@wallethero/sdkdoes not wrap the mobile-auth endpoints. Call these REST endpoints directly from the mobile client.
Login with Directus credentials
POST /wallethero-api/mobile-app/auth/login
Verifies a Directus user's email/password and provisions a mobile session for every workspace the user belongs to. Returns an array of profiles — one per workspace — each carrying its own access/refresh token pair. Suspended workspace memberships are skipped.
Auth: Public — credentials in the request body.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
email | string (email) | Yes | Directus user email |
password | string | Yes | Directus user password |
device_id | string | No | Stable device identifier |
device_name | string | No | Human-readable device name |
device_os | string | No | Device OS string |
push_token | string | No | Push-notification token for the device |
Example Request
curl -X POST "https://api.wallethero.app/wallethero-api/mobile-app/auth/login" \
-H "Content-Type: application/json" \
-d '{
"email": "[email protected]",
"password": "hunter2",
"device_id": "ipad-front-desk-01",
"device_name": "Front Desk iPad",
"device_os": "iPadOS 17"
}'Response (200)
{
"data": [
{
"mobile_app_user_id": "9d1b...",
"workspace_id": "11111111-1111-1111-1111-111111111111",
"workspace_name": "Acme Loyalty",
"access_token": "eyJhbGciOi...",
"refresh_token": "eyJhbGciOi...",
"expires_in": 900,
"user": {
"id": "9d1b...",
"email": "[email protected]",
"phone": null,
"first_name": "Sam",
"last_name": "Taylor",
"full_name": "Sam Taylor"
}
}
]
}Pair a device with a pairing code
POST /wallethero-api/mobile-app/auth/pair
Exchanges a 6-digit pairing code (generated by a workspace admin) for a mobile session. On success it marks the code used, flips the mobile app user to paired, opens a session row, and returns the access/refresh tokens plus the user record.
The endpoint is IP rate-limited: repeated failed attempts (invalid/expired code, too many tries) temporarily block the client IP. Codes also expire and have a per-code attempt cap.
Auth: Public — pairing code in the request body.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
code | string | Yes | 6-digit numeric pairing code (^\d{6}$) |
device_id | string | No | Stable device identifier |
device_name | string | No | Human-readable device name |
device_os | string | No | Device OS string |
push_token | string | No | Push-notification token for the device |
Example Request
curl -X POST "https://api.wallethero.app/wallethero-api/mobile-app/auth/pair" \
-H "Content-Type: application/json" \
-d '{
"code": "482915",
"device_id": "ipad-front-desk-01",
"device_name": "Front Desk iPad",
"device_os": "iPadOS 17"
}'Response (200)
{
"access_token": "eyJhbGciOi...",
"refresh_token": "eyJhbGciOi...",
"expires_in": 900,
"user": {
"id": "9d1b...",
"email": "[email protected]",
"phone": null,
"first_name": "Sam",
"last_name": "Taylor",
"workspace_id": "11111111-1111-1111-1111-111111111111"
}
}Errors
400— Invalid or expired pairing code, expired code, max attempts exceeded, or too many failed pairing attempts from this IP.
Refresh the access token
POST /wallethero-api/mobile-app/auth/refresh
Verifies a refresh-token JWT, validates the backing session (must exist, not be revoked, not expired) and that the user is still active, then issues a new access/refresh token pair and bumps the session's last_active_at.
Auth: Public — valid refresh token in the request body.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
refresh_token | string | Yes | The refresh-token JWT returned by login/pair/refresh |
Example Request
curl -X POST "https://api.wallethero.app/wallethero-api/mobile-app/auth/refresh" \
-H "Content-Type: application/json" \
-d '{ "refresh_token": "eyJhbGciOi..." }'Response (200)
{
"access_token": "eyJhbGciOi...",
"refresh_token": "eyJhbGciOi...",
"expires_in": 900
}Errors
400— Invalid refresh token, invalid token type, session not found or revoked, session expired, or user not found/inactive.
Get current mobile user profile
GET /wallethero-api/mobile-app/me
Returns the profile of the mobile app user backing the current session, including their workspace summary.
Auth: Mobile session — X-Mobile-Token: <access_token>.
Example Request
curl "https://api.wallethero.app/wallethero-api/mobile-app/me" \
-H "X-Mobile-Token: ACCESS_TOKEN"Response (200)
{
"data": {
"id": "9d1b...",
"email": "[email protected]",
"phone": null,
"first_name": "Sam",
"last_name": "Taylor",
"status": "active",
"paired_at": "2026-06-10T08:30:00.000Z",
"last_login": "2026-06-16T09:00:00.000Z",
"metadata": {},
"workspace": {
"id": "11111111-1111-1111-1111-111111111111",
"name": "Acme Loyalty",
"slug": "acme"
}
}
}Logout
POST /wallethero-api/mobile-app/auth/logout
Revokes the current session (sets revoked_at). The access token's session_id is used, so only the calling device's session is invalidated.
Auth: Mobile session — X-Mobile-Token: <access_token>.
Example Request
curl -X POST "https://api.wallethero.app/wallethero-api/mobile-app/auth/logout" \
-H "X-Mobile-Token: ACCESS_TOKEN"Response (200)
{ "message": "Logged out successfully" }