Skip to main content

Account Mng

Account API Documentation

Author: Josh S. Sakweli, Backend Lead Team
Last Updated: 2026-05-19
Version: v1.0

Base URL: {base_url}/api/v1/account

Short Description: The Account API manages everything related to a user's identity, credentials, and security. This includes password management, two-factor authentication, email verification, session control, trusted devices, and linking external auth providers. All operations in this API are private — only the authenticated account owner can act on their own account.

Why Account and Profile Are Separate:

Account = who you are in the system (credentials, security, identity verification). Profile = how you appear to others (display name, bio, location, picture).

This separation exists for a clear reason: account operations carry security implications and are always private — only you can change your password, revoke a session, or deactivate your account. Profile operations are social and can be partially visible to others. Mixing them creates confusion about what is private vs public, and makes it harder to apply the right access control. The Account API is your security dashboard; the Profile API is your public face.

Hints:

  • All endpoints except GET /username/check, GET /username/search, and GET /username/{username} require a valid Bearer JWT token
  • X-Session-Id header (UUID) is required for session-specific operations
  • Username checks are case-insensitive — all usernames are lowercased automatically
  • OTP codes expire in 10 minutes unless otherwise stated
  • User-selectable OTP channels are: SMS, WHATSAPP, EMAIL, SMS_AND_WHATSAPP

Standard Response Format

Success Response Structure

{
  "success": true,
  "httpStatus": "OK",
  "message": "Operation completed successfully",
  "action_time": "2025-09-23T10:30:45",
  "data": {}
}

Error Response Structure

{
  "success": false,
  "httpStatus": "BAD_REQUEST",
  "message": "Error description",
  "action_time": "2025-09-23T10:30:45",
  "data": "Error description"
}

Standard Response Fields

Field Type Description
success boolean true for successful operations, false for errors
httpStatus string HTTP status name (OK, BAD_REQUEST, NOT_FOUND, etc.)
message string Human-readable message describing the result
action_time string ISO 8601 timestamp of when the response was generated
data object/string Response payload on success, error details on failure

Standard Error Types

  • 400 BAD_REQUEST: Invalid request data, business rule violation, or item already exists
  • 401 UNAUTHORIZED: Missing, expired, or invalid JWT token
  • 403 FORBIDDEN: Verification failure (wrong password, wrong OTP)
  • 404 NOT_FOUND: Account or resource not found
  • 422 UNPROCESSABLE_ENTITY: Validation errors with field-level detail
  • 500 INTERNAL_SERVER_ERROR: Unexpected server error

Security

1. Get Security Info

Purpose: Returns the authenticated user's account security overview including verification status, 2FA state, and a computed security strength score.

Endpoint: GET {base_url}/api/v1/account/security-info

Access Level: 🔒 Protected (Requires valid JWT)

Authentication: Bearer Token

Request Headers:

Header Type Required Description
Authorization string Yes Bearer <jwt_token>

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "Security information retrieved successfully",
  "action_time": "2026-05-19T10:30:45",
  "data": {
    "isEmailVerified": true,
    "isPhoneVerified": true,
    "isTwoFactorEnabled": false,
    "isAccountLocked": false,
    "lastPasswordChange": "2026-04-10T08:22:00",
    "accountCreatedAt": "2025-12-01T14:00:00",
    "roles": ["ROLE_USER"],
    "securityStrength": {
      "score": 50,
      "level": "MEDIUM",
      "description": "Your account security is good but can be improved",
      "recommendations": ["Enable two-factor authentication"]
    }
  }
}

Success Response Fields:

Field Description
isEmailVerified Whether the account's email has been verified
isPhoneVerified Whether the account's phone number has been verified
isTwoFactorEnabled Whether 2FA is currently active
isAccountLocked Whether the account is locked or deactivated
lastPasswordChange ISO 8601 timestamp of the last account edit
accountCreatedAt ISO 8601 timestamp of account creation
roles Array of role strings assigned to the account
securityStrength.score Integer 0–100 representing security health
securityStrength.level VERY_WEAK, WEAK, MEDIUM, or STRONG
securityStrength.description Human-readable summary of the score
securityStrength.recommendations List of actionable steps to improve score

Error Response JSON Sample:

{
  "success": false,
  "httpStatus": "UNAUTHORIZED",
  "message": "Token has expired",
  "action_time": "2026-05-19T10:30:45",
  "data": "Token has expired"
}

2. Enable Two-Factor Authentication

Purpose: Enables 2FA on the authenticated user's account. Requires password confirmation as a security gate.

Endpoint: POST {base_url}/api/v1/account/2fa/enable

Access Level: 🔒 Protected (Requires valid JWT)

Authentication: Bearer Token

Request Headers:

Header Type Required Description
Authorization string Yes Bearer <jwt_token>
Content-Type string Yes application/json

Request JSON Sample:

{
  "password": "MyStr0ngP@ss!"
}

Request Body Parameters:

Parameter Type Required Description Validation
password string Yes Current account password Not blank

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "Two-factor authentication enabled successfully",
  "action_time": "2026-05-19T10:30:45",
  "data": null
}

Error Response JSON Sample:

{
  "success": false,
  "httpStatus": "FORBIDDEN",
  "message": "Password is incorrect",
  "action_time": "2026-05-19T10:30:45",
  "data": "Password is incorrect"
}

3. Disable Two-Factor Authentication

Purpose: Disables 2FA on the authenticated user's account. Requires password confirmation.

Endpoint: POST {base_url}/api/v1/account/2fa/disable

Access Level: 🔒 Protected (Requires valid JWT)

Authentication: Bearer Token

Request Headers:

Header Type Required Description
Authorization string Yes Bearer <jwt_token>
Content-Type string Yes application/json

Request JSON Sample:

{
  "password": "MyStr0ngP@ss!"
}

Request Body Parameters:

Parameter Type Required Description Validation
password string Yes Current account password Not blank

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "Two-factor authentication disabled successfully",
  "action_time": "2026-05-19T10:30:45",
  "data": null
}

Error Response JSON Sample:

{
  "success": false,
  "httpStatus": "BAD_REQUEST",
  "message": "Two-factor authentication is not enabled",
  "action_time": "2026-05-19T10:30:45",
  "data": "Two-factor authentication is not enabled"
}

4. Deactivate Account

Purpose: Locks the authenticated user's account (soft deactivation). The account is not deleted — data is preserved and support can reactivate it. Requires password confirmation.

Endpoint: DELETE {base_url}/api/v1/account/deactivate

Access Level: 🔒 Protected (Requires valid JWT)

Authentication: Bearer Token

Request Headers:

Header Type Required Description
Authorization string Yes Bearer <jwt_token>
Content-Type string Yes application/json

Request JSON Sample:

{
  "password": "MyStr0ngP@ss!",
  "reason": "Taking a break from the platform"
}

Request Body Parameters:

Parameter Type Required Description Validation
password string Yes Current account password Not blank
reason string No Optional reason for deactivation Max 500 characters

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "Account deactivated successfully",
  "action_time": "2026-05-19T10:30:45",
  "data": null
}

Error Response JSON Sample:

{
  "success": false,
  "httpStatus": "FORBIDDEN",
  "message": "Password is incorrect",
  "action_time": "2026-05-19T10:30:45",
  "data": "Password is incorrect"
}

Password Management

5. Change Password

Purpose: Changes the account password. Supports two paths: provide currentPassword if the account already has one, or provide otp for passwordless accounts or if the user forgot their current password.

Endpoint: POST {base_url}/api/v1/account/password/change

Access Level: 🔒 Protected (Requires valid JWT)

Authentication: Bearer Token

Request Headers:

Header Type Required Description
Authorization string Yes Bearer <jwt_token>
Content-Type string Yes application/json

Request JSON Sample:

{
  "currentPassword": "OldP@ss123!",
  "newPassword": "NewStr0ng@Pass!",
  "confirmPassword": "NewStr0ng@Pass!"
}

Request Body Parameters:

Parameter Type Required Description Validation
currentPassword string Conditional Required if account has a password One of currentPassword or otp must be provided
otp string Conditional OTP alternative for passwordless accounts One of currentPassword or otp must be provided
newPassword string Yes The new password Min 8 characters, not blank
confirmPassword string Yes Must match newPassword Not blank

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "Password changed",
  "action_time": "2026-05-19T10:30:45",
  "data": {
    "success": true,
    "hadPassword": true,
    "message": "Password changed successfully"
  }
}

Success Response Fields:

Field Description
success Always true on success
hadPassword true if this was a change, false if it was a first-time set
message Human-readable confirmation

Error Response JSON Sample:

{
  "success": false,
  "httpStatus": "UNPROCESSABLE_ENTITY",
  "message": "Validation failed",
  "action_time": "2026-05-19T10:30:45",
  "data": {
    "newPassword": "Password must be at least 8 characters"
  }
}

6. Send OTP for Password Change

Purpose: Sends an OTP to the user's verified phone/email to enable password change without knowing the current password. Returns a temp token for the verification step.

Endpoint: POST {base_url}/api/v1/account/password/change-with-otp/send-otp

Access Level: 🔒 Protected (Requires valid JWT)

Authentication: Bearer Token

Request Headers:

Header Type Required Description
Authorization string Yes Bearer <jwt_token>
Content-Type string Yes application/json

Request JSON Sample:

{
  "channel": "SMS"
}

Request Body Parameters:

Parameter Type Required Description Validation
channel string Yes Where to send the OTP enum: SMS, WHATSAPP, EMAIL, SMS_AND_WHATSAPP

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "OTP sent",
  "action_time": "2026-05-19T10:30:45",
  "data": {
    "tempToken": "eyJhbGciOiJIUzI1NiJ9...",
    "maskedValue": "+254***7890",
    "expiresIn": 600
  }
}

Success Response Fields:

Field Description
tempToken Short-lived token to submit in the verify step
maskedValue Masked destination (phone or email) the OTP was sent to
expiresIn Seconds until the OTP expires

7. Change Password with OTP

Purpose: Completes the OTP-based password change flow using the temp token and OTP from the previous step.

Endpoint: POST {base_url}/api/v1/account/password/change-with-otp/verify

Access Level: 🔒 Protected (Requires valid JWT)

Authentication: Bearer Token

Request Headers:

Header Type Required Description
Authorization string Yes Bearer <jwt_token>
Content-Type string Yes application/json

Request JSON Sample:

{
  "tempToken": "eyJhbGciOiJIUzI1NiJ9...",
  "otp": "482910",
  "newPassword": "NewStr0ng@Pass!",
  "confirmPassword": "NewStr0ng@Pass!"
}

Request Body Parameters:

Parameter Type Required Description Validation
tempToken string Yes Token from the send-otp step Not blank
otp string Yes 6-digit OTP received Exactly 6 characters
newPassword string Yes New password Min 8 characters, not blank
confirmPassword string Yes Must match newPassword Not blank

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "Password changed successfully",
  "action_time": "2026-05-19T10:30:45",
  "data": {
    "success": true,
    "hadPassword": true,
    "message": "Password changed successfully"
  }
}

8. Check If Password Can Be Set

Purpose: Checks whether the authenticated user is eligible to set a password. Useful for passwordless accounts (OAuth-only) who want to add a password.

Endpoint: GET {base_url}/api/v1/account/password/can-set

Access Level: 🔒 Protected (Requires valid JWT)

Authentication: Bearer Token

Request Headers:

Header Type Required Description
Authorization string Yes Bearer <jwt_token>

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "You can set a password",
  "action_time": "2026-05-19T10:30:45",
  "data": {
    "canSetPassword": true,
    "authProvider": "GOOGLE"
  }
}

Success Response Fields:

Field Description
canSetPassword true if the account does not yet have a password
authProvider The current primary auth provider (EMAIL, GOOGLE, APPLE, etc.)

9. Set Password (First Time)

Purpose: Sets a password for the first time on an account that currently has no password (e.g., a Google OAuth account). Use /password/change for subsequent changes.

Endpoint: POST {base_url}/api/v1/account/password/set

Access Level: 🔒 Protected (Requires valid JWT)

Authentication: Bearer Token

Request Headers:

Header Type Required Description
Authorization string Yes Bearer <jwt_token>
Content-Type string Yes application/json

Request JSON Sample:

{
  "newPassword": "MyStr0ngP@ss!",
  "confirmPassword": "MyStr0ngP@ss!"
}

Request Body Parameters:

Parameter Type Required Description Validation
newPassword string Yes Password to set Min 8 characters, not blank
confirmPassword string Yes Must match newPassword Not blank

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "Password set successfully",
  "action_time": "2026-05-19T10:30:45",
  "data": {
    "success": true,
    "hadPassword": false,
    "message": "Password set successfully"
  }
}

Error Response JSON Sample:

{
  "success": false,
  "httpStatus": "BAD_REQUEST",
  "message": "Password already set",
  "action_time": "2026-05-19T10:30:45",
  "data": "Password already set"
}

Username Management

10. Check Username Availability

Purpose: Checks whether a given username is valid and available. Public endpoint — no auth required. Returns alternative suggestions when the username is taken.

Endpoint: GET {base_url}/api/v1/account/username/check

Access Level: 🌐 Public

Authentication: None

Query Parameters:

Parameter Type Required Description Validation
username string Yes Username to check Auto-lowercased

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "Username available",
  "action_time": "2026-05-19T10:30:45",
  "data": {
    "username": "john_doe",
    "available": true,
    "suggestions": null
  }
}

When Unavailable:

{
  "success": true,
  "httpStatus": "OK",
  "message": "Username not available",
  "action_time": "2026-05-19T10:30:45",
  "data": {
    "username": "john_doe",
    "available": false,
    "suggestions": ["john_doe1", "john_doe99", "johndoe_"]
  }
}

Success Response Fields:

Field Description
username The lowercased username that was checked
available true if the username is both valid and not taken
suggestions List of alternative usernames (only present when available is false)

11. Check If Username Can Be Changed

Purpose: Checks whether the authenticated user is currently allowed to change their username (based on change frequency limits).

Endpoint: GET {base_url}/api/v1/account/username/can-change

Access Level: 🔒 Protected (Requires valid JWT)

Authentication: Bearer Token

Request Headers:

Header Type Required Description
Authorization string Yes Bearer <jwt_token>

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "You can change your username",
  "action_time": "2026-05-19T10:30:45",
  "data": {
    "canChange": true,
    "currentUsername": "john_doe"
  }
}

Success Response Fields:

Field Description
canChange true if the user is allowed to change username now
currentUsername The user's current public username

12. Change Username

Purpose: Changes the authenticated user's public username. Subject to rate/frequency limits — check /can-change first. The change is recorded in the username history.

Endpoint: POST {base_url}/api/v1/account/username/change

Access Level: 🔒 Protected (Requires valid JWT)

Authentication: Bearer Token

Request Headers:

Header Type Required Description
Authorization string Yes Bearer <jwt_token>
Content-Type string Yes application/json

Request JSON Sample:

{
  "username": "new_username"
}

Request Body Parameters:

Parameter Type Required Description Validation
username string Yes Desired new username Auto-lowercased; must be valid and available

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "Username changed successfully",
  "action_time": "2026-05-19T10:30:45",
  "data": {
    "oldUsername": "john_doe",
    "newUsername": "new_username"
  }
}

Success Response Fields:

Field Description
oldUsername The previous username
newUsername The newly assigned username

Error Response JSON Sample:

{
  "success": false,
  "httpStatus": "BAD_REQUEST",
  "message": "Username change limit reached",
  "action_time": "2026-05-19T10:30:45",
  "data": "Username change limit reached"
}

13. Search Users

Purpose: Full-text search for accounts by username or display name. Public endpoint. Supports pagination.

Endpoint: GET {base_url}/api/v1/account/username/search

Access Level: 🌐 Public

Authentication: None

Query Parameters:

Parameter Type Required Description Validation Default
q string Yes Search query (supports @username format) Min 2 characters
page integer No Zero-based page number Min: 0 0
size integer No Results per page Max: 20 4

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "Users found",
  "action_time": "2026-05-19T10:30:45",
  "data": {
    "users": [
      {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "userName": "john_doe",
        "displayName": "John Doe",
        "avatarUrl": "https://cdn.example.com/avatar.jpg"
      }
    ],
    "totalCount": 1,
    "hasMore": false
  }
}

Success Response Fields:

Field Description
users Array of matching user objects
users[].id Account UUID
users[].userName Public username
users[].displayName Display name (may be null)
users[].avatarUrl First profile picture URL (may be null)
totalCount Total number of matching results
hasMore true if more pages exist

14. Get User by Username

Purpose: Looks up a minimal user card by exact username. Returns only public-facing identity fields. Only works for active, non-locked accounts that have completed primary onboarding.

Endpoint: GET {base_url}/api/v1/account/username/{username}

Access Level: 🌐 Public

Authentication: None

Path Parameters:

Parameter Type Required Description Validation
username string Yes Username to look up (supports @username format) Auto-lowercased

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "User found",
  "action_time": "2026-05-19T10:30:45",
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "userName": "john_doe",
    "displayName": "John Doe",
    "avatarUrl": "https://cdn.example.com/avatar.jpg"
  }
}

Error Response JSON Sample:

{
  "success": false,
  "httpStatus": "NOT_FOUND",
  "message": "User not found",
  "action_time": "2026-05-19T10:30:45",
  "data": "User not found"
}

Sessions

15. Get Active Sessions

Purpose: Returns all active sessions for the authenticated account. Optionally marks the caller's current session when X-Session-Id is provided.

Endpoint: GET {base_url}/api/v1/account/sessions

Access Level: 🔒 Protected (Requires valid JWT)

Authentication: Bearer Token

Request Headers:

Header Type Required Description
Authorization string Yes Bearer <jwt_token>
X-Session-Id string (UUID) No Current session UUID to mark it in the response

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "Sessions retrieved",
  "action_time": "2026-05-19T10:30:45",
  "data": {
    "sessions": [
      {
        "id": "123e4567-e89b-12d3-a456-426614174000",
        "deviceId": "device_abc123",
        "deviceName": "iPhone 15",
        "platform": "IOS",
        "ipAddress": "197.248.1.1",
        "location": "Nairobi, KE",
        "lastActiveAt": "2026-05-19T09:00:00",
        "createdAt": "2026-04-01T12:00:00",
        "currentSession": true
      }
    ],
    "totalCount": 1,
    "currentSession": { ... }
  }
}

Success Response Fields:

Field Description
sessions Array of all active session objects
sessions[].id Session UUID
sessions[].deviceName Human-readable device name
sessions[].platform Device platform (IOS, ANDROID, WEB, etc.)
sessions[].ipAddress IP address the session was created from
sessions[].location Approximate geographic location
sessions[].lastActiveAt When this session last made a request
sessions[].currentSession true if this is the caller's current session
totalCount Total number of active sessions
currentSession The caller's current session object (if X-Session-Id provided)

16. Sign Out (Current Session)

Purpose: Invalidates the session identified by the X-Session-Id header.

Endpoint: POST {base_url}/api/v1/account/sessions/sign-out

Access Level: 🔒 Protected (Requires valid JWT)

Authentication: Bearer Token

Request Headers:

Header Type Required Description
Authorization string Yes Bearer <jwt_token>
X-Session-Id string (UUID) Yes The session to invalidate

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "Signed out successfully",
  "action_time": "2026-05-19T10:30:45",
  "data": null
}

17. Sign Out Other Devices

Purpose: Invalidates all sessions except the current one. Requires password or OTP confirmation as a security gate.

Endpoint: POST {base_url}/api/v1/account/sessions/sign-out-others

Access Level: 🔒 Protected (Requires valid JWT)

Authentication: Bearer Token

Request Headers:

Header Type Required Description
Authorization string Yes Bearer <jwt_token>
X-Session-Id string (UUID) Yes The session to KEEP (current session)
Content-Type string Yes application/json

Request JSON Sample:

{
  "password": "MyStr0ngP@ss!"
}

Request Body Parameters:

Parameter Type Required Description Validation
password string Conditional Account password One of password or otp required
otp string Conditional OTP alternative One of password or otp required

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "Signed out of other devices",
  "action_time": "2026-05-19T10:30:45",
  "data": null
}

18. Sign Out All Devices

Purpose: Invalidates all active sessions including the current one. Requires password or OTP confirmation.

Endpoint: POST {base_url}/api/v1/account/sessions/sign-out-all

Access Level: 🔒 Protected (Requires valid JWT)

Authentication: Bearer Token

Request Headers:

Header Type Required Description
Authorization string Yes Bearer <jwt_token>
Content-Type string Yes application/json

Request JSON Sample:

{
  "password": "MyStr0ngP@ss!"
}

Request Body Parameters:

Parameter Type Required Description Validation
password string Conditional Account password One of password or otp required
otp string Conditional OTP alternative One of password or otp required

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "Signed out of all devices",
  "action_time": "2026-05-19T10:30:45",
  "data": null
}

19. Revoke Specific Session

Purpose: Revokes a specific session by its ID. Used to forcefully end a session from another device.

Endpoint: DELETE {base_url}/api/v1/account/sessions/{sessionId}

Access Level: 🔒 Protected (Requires valid JWT)

Authentication: Bearer Token

Request Headers:

Header Type Required Description
Authorization string Yes Bearer <jwt_token>

Path Parameters:

Parameter Type Required Description Validation
sessionId UUID Yes ID of the session to revoke Valid UUID format

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "Session revoked",
  "action_time": "2026-05-19T10:30:45",
  "data": null
}

Devices

20. Verify Device

Purpose: Completes new device verification during login. When a login attempt is made from an unrecognized device, this endpoint finalizes the flow after the user confirms ownership with an OTP. Returns full auth tokens on success.

Endpoint: POST {base_url}/api/v1/account/device/verify

Access Level: 🌐 Public (No JWT — called before full auth is established)

Authentication: None

Request Headers:

Header Type Required Description
User-Agent string Yes Device user-agent (auto-sent by clients)

Request JSON Sample:

{
  "deviceVerificationToken": "dvt_abc123...",
  "otp": "482910",
  "deviceId": "unique-device-fingerprint-id",
  "deviceName": "iPhone 15 Pro",
  "platform": "IOS"
}

Request Body Parameters:

Parameter Type Required Description Validation
deviceVerificationToken string Yes Token issued during the login challenge step Not blank
otp string Yes 6-digit OTP sent to user for device verification Exactly 6 numeric digits
deviceId string Yes Unique client-side device fingerprint Not blank
deviceName string No Human-readable device name
platform string No Device platform (IOS, ANDROID, WEB, etc.)

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "Device verified. Login successful.",
  "action_time": "2026-05-19T10:30:45",
  "data": {
    "accessToken": "eyJhbGciOiJIUzI1NiJ9...",
    "refreshToken": "eyJhbGciOiJIUzI1NiJ9...",
    "onboarding": {
      "isPrimaryComplete": true,
      "hasUsername": true
    },
    "user": {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "userName": "john_doe",
      "firstName": "John"
    }
  }
}

Success Response Fields:

Field Description
accessToken JWT access token for subsequent API calls
refreshToken JWT refresh token for getting new access tokens
onboarding Flags indicating what onboarding steps remain
user Basic user info object

21. Get Trusted Devices

Purpose: Returns the list of devices that have been verified and trusted on this account.

Endpoint: GET {base_url}/api/v1/account/devices

Access Level: 🔒 Protected (Requires valid JWT)

Authentication: Bearer Token

Request Headers:

Header Type Required Description
Authorization string Yes Bearer <jwt_token>
X-Device-Id string No Current device ID to mark it in the response

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "Devices retrieved",
  "action_time": "2026-05-19T10:30:45",
  "data": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "deviceId": "unique-device-fingerprint-id",
      "deviceName": "iPhone 15 Pro",
      "platform": "IOS",
      "lastUsedAt": "2026-05-19T09:00:00",
      "createdAt": "2026-04-01T12:00:00"
    }
  ]
}

22. Revoke Device

Purpose: Removes a trusted device. The next login from that device will require device verification again.

Endpoint: DELETE {base_url}/api/v1/account/devices/{deviceKeyId}

Access Level: 🔒 Protected (Requires valid JWT)

Authentication: Bearer Token

Request Headers:

Header Type Required Description
Authorization string Yes Bearer <jwt_token>

Path Parameters:

Parameter Type Required Description Validation
deviceKeyId UUID Yes ID of the device key to revoke Valid UUID format

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "Device revoked",
  "action_time": "2026-05-19T10:30:45",
  "data": null
}

Account Linking

23. Initiate Email Link

Purpose: Starts the process of linking an email address to the account. Sends a verification OTP to the provided email and returns a temp token for the verify step.

Endpoint: POST {base_url}/api/v1/account/link/email/initiate

Access Level: 🔒 Protected (Requires valid JWT)

Authentication: Bearer Token

Request Headers:

Header Type Required Description
Authorization string Yes Bearer <jwt_token>
Content-Type string Yes application/json

Request JSON Sample:

{
  "email": "john@example.com"
}

Request Body Parameters:

Parameter Type Required Description Validation
email string Yes Email address to link Valid email format, not blank

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "Verification code sent",
  "action_time": "2026-05-19T10:30:45",
  "data": {
    "tempToken": "eyJhbGciOiJIUzI1NiJ9...",
    "maskedValue": "jo***@example.com",
    "expiresIn": 600,
    "linked": false,
    "message": "Verification code sent to jo***@example.com"
  }
}

Success Response Fields:

Field Description
tempToken Short-lived token to submit in the verify step
maskedValue Masked email the OTP was sent to
expiresIn Seconds until the OTP expires

Purpose: Completes the email linking process by submitting the OTP and temp token from the initiate step.

Endpoint: POST {base_url}/api/v1/account/link/email/verify

Access Level: 🔒 Protected (Requires valid JWT)

Authentication: Bearer Token

Request Headers:

Header Type Required Description
Authorization string Yes Bearer <jwt_token>
Content-Type string Yes application/json

Request JSON Sample:

{
  "tempToken": "eyJhbGciOiJIUzI1NiJ9...",
  "otp": "482910"
}

Request Body Parameters:

Parameter Type Required Description Validation
tempToken string Yes Token from the initiate step Not blank
otp string Yes 6-digit OTP sent to the email Exactly 6 characters

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "Email linked successfully",
  "action_time": "2026-05-19T10:30:45",
  "data": {
    "linked": true,
    "message": "Email linked successfully"
  }
}

Purpose: Removes the linked email from the account.

Endpoint: DELETE {base_url}/api/v1/account/link/email

Access Level: 🔒 Protected (Requires valid JWT)

Authentication: Bearer Token

Request Headers:

Header Type Required Description
Authorization string Yes Bearer <jwt_token>

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "Email unlinked",
  "action_time": "2026-05-19T10:30:45",
  "data": {
    "unlinked": true,
    "message": "Email unlinked successfully"
  }
}

Endpoint: POST {base_url}/api/v1/account/link/oauth

Access Level: 🔒 Protected (Requires valid JWT)

Authentication: Bearer Token

Request Headers:

Header Type Required Description
Authorization string Yes Bearer <jwt_token>
Content-Type string Yes application/json

Request JSON Sample:

{
  "provider": "GOOGLE",
  "idToken": "ya29.a0AfH6SMC..."
}

Request Body Parameters:

Parameter Type Required Description Validation
provider string Yes OAuth provider to link enum: GOOGLE, APPLE
idToken string Yes ID token from the provider's SDK Not blank

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "GOOGLE linked successfully",
  "action_time": "2026-05-19T10:30:45",
  "data": {
    "linked": true,
    "message": "GOOGLE linked successfully"
  }
}

Purpose: Removes a linked OAuth provider from the account.

Endpoint: DELETE {base_url}/api/v1/account/link/oauth/{provider}

Access Level: 🔒 Protected (Requires valid JWT)

Authentication: Bearer Token

Request Headers:

Header Type Required Description
Authorization string Yes Bearer <jwt_token>

Path Parameters:

Parameter Type Required Description Validation
provider string Yes OAuth provider to unlink GOOGLE or APPLE (case-insensitive)

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "GOOGLE unlinked",
  "action_time": "2026-05-19T10:30:45",
  "data": {
    "unlinked": true,
    "message": "GOOGLE unlinked successfully"
  }
}

Error Response JSON Sample:

{
  "success": false,
  "httpStatus": "BAD_REQUEST",
  "message": "Cannot unlink last auth provider",
  "action_time": "2026-05-19T10:30:45",
  "data": "Cannot unlink last auth provider"
}

Quick Reference — All Account Endpoints

# Method Endpoint Auth Description
1 GET /account/security-info 🔒 Get security overview
2 POST /account/2fa/enable 🔒 Enable 2FA
3 POST /account/2fa/disable 🔒 Disable 2FA
4 DELETE /account/deactivate 🔒 Soft-deactivate account
5 POST /account/password/change 🔒 Change password
6 POST /account/password/change-with-otp/send-otp 🔒 Request OTP for password change
7 POST /account/password/change-with-otp/verify 🔒 Change password via OTP
8 GET /account/password/can-set 🔒 Check if password can be set
9 POST /account/password/set 🔒 Set password (first time)
10 GET /account/username/check 🌐 Check username availability
11 GET /account/username/can-change 🔒 Check username change eligibility
12 POST /account/username/change 🔒 Change username
13 GET /account/username/search 🌐 Search users
14 GET /account/username/{username} 🌐 Lookup user by username
15 GET /account/sessions 🔒 List active sessions
16 POST /account/sessions/sign-out 🔒 Sign out current session
17 POST /account/sessions/sign-out-others 🔒 Sign out all other sessions
18 POST /account/sessions/sign-out-all 🔒 Sign out all sessions
19 DELETE /account/sessions/{sessionId} 🔒 Revoke specific session
20 POST /account/device/verify 🌐 Verify new device
21 GET /account/devices 🔒 List trusted devices
22 DELETE /account/devices/{deviceKeyId} 🔒 Revoke trusted device
23 POST /account/link/email/initiate 🔒 Start email linking
24 POST /account/link/email/verify 🔒 Complete email linking
25 DELETE /account/link/email 🔒 Unlink email
26 POST /account/link/oauth 🔒 Link OAuth provider
27 DELETE /account/link/oauth/{provider} 🔒 Unlink OAuth provider