API

Users - Profile & Settings

User profile management, email updates, password changes, and payment preferences.

Base path: /api/v1/users

User endpoints allow customers and owners to manage their profiles, update credentials, and preferences.


POST /api/v1/users/email/otp — Send Email Update OTP

Auth: Protected (Authorization: Bearer <accessToken>)
Used by: owner-booki-web-app, customer-booki-web-app · Role: owner, branch-manager, customer
organizationId: From JWT token (not required in request body)
Description: Send a 6-digit OTP to verify email change.

Request

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

Fields:

  • email (string, required): New email address to send OTP to

Note: organizationId is read from the user's JWT token server-side.

Response (200 OK)

{
  "message": "Update email OTP sent successfully. Kindly check your email for the OTP."
}

Error Responses

401 Unauthorized — No valid token:

{
  "statusCode": 401,
  "message": "Access token is required to proceed."
}

cURL Example

curl -X POST http://localhost:4001/api/v1/users/email/otp \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer eyJhbGc..." \
  -d '{
    "email": "newemail@example.com"
  }'

POST /api/v1/users/email/otp/:otp/verify — Verify Email Update OTP

Auth: Protected (Authorization: Bearer <accessToken>)
Used by: owner-booki-web-app, customer-booki-web-app · Role: owner, branch-manager, customer
Description: Verify OTP and update email (OTP valid for 10 minutes). The OTP is passed as a URL parameter.

Request

POST /api/v1/users/email/otp/123456/verify

No request body required. The OTP is read from the URL path, and the user identity is derived from the JWT token.

Response (200 OK)

{
  "message": "Update email OTP verified successfully."
}

Error Responses

400 Bad Request — Invalid or expired OTP:

{
  "statusCode": 400,
  "message": "Invalid or expired OTP"
}

cURL Example

curl -X POST "http://localhost:4001/api/v1/users/email/otp/123456/verify" \
  -H "Authorization: Bearer eyJhbGc..."

GET /api/v1/users/id/:id — Get User by ID

Auth: Protected (Authorization: Bearer <accessToken>)
Used by: owner-booki-web-app · Role: owner, branch-manager
organizationId: From JWT token
Description: Retrieve a specific user by ID.

Request

GET /api/v1/users/id/507f1f77bcf86cd799439011

Response (200 OK)

{
  "_id": "507f1f77bcf86cd799439011",
  "email": "jane@example.com",
  "firstName": "Jane",
  "lastName": "Doe",
  "phone": "09171234567",
  "userType": "owner",
  "organizationId": "507f191e810c19729de860ea",
  "status": "active",
  "preferredPaymentMethod": "maya",
  "createdAt": "2026-03-15T10:30:00Z"
}

cURL Example

curl -X GET http://localhost:4001/api/v1/users/id/507f1f77bcf86cd799439011 \
  -H "Authorization: Bearer eyJhbGc..."

GET /api/v1/users/email/:email — Get User by Email

Auth: Protected (Authorization: Bearer <accessToken>)
Used by: owner-booki-web-app · Role: owner, branch-manager
organizationId: From JWT token
Description: Retrieve a user by email address (admin/owner context).

Request

GET /api/v1/users/email/jane@example.com

Response (200 OK)

Same as above.

cURL Example

curl -X GET http://localhost:4001/api/v1/users/email/jane@example.com \
  -H "Authorization: Bearer eyJhbGc..."

GET /api/v1/users/payment-preference — Get Payment Preference

Auth: Protected (Authorization: Bearer <accessToken>)
Used by: owner-booki-web-app, customer-booki-web-app · Role: owner, customer
organizationId: From JWT token
Description: Get the user's preferred payment method for bookings.

Response (200 OK)

{
  "user": {
    "_id": "507f1f77bcf86cd799439011",
    "preferredPaymentMethod": "maya"
  }
}

cURL Example

curl -X GET http://localhost:4001/api/v1/users/payment-preference \
  -H "Authorization: Bearer eyJhbGc..."

GET /api/v1/users — List Users (Admin Only)

Auth: Protected (Authorization: Bearer <accessToken>) · admin only
Used by: admin-booki-web-app · Role: admin
organizationId: Not applicable (admin sees all users)
Description: List all users (super-admin endpoint).

Request

Query Parameters (optional):

  • page (number, default: 1)
  • limit (number, default: 10, max: 100)
  • search (string): Search by name or email
  • sort (string, default: _id)
  • order (string, default: desc)
GET /api/v1/users?page=1&limit=20&search=jane

Response (200 OK)

{
  "items": [
    {
      "_id": "507f1f77bcf86cd799439011",
      "email": "jane@example.com",
      "firstName": "Jane",
      "lastName": "Doe",
      "userType": "owner",
      "status": "active",
      "createdAt": "2026-03-15T10:30:00Z"
    }
  ],
  "pages": 1,
  "pageRange": "1-1"
}

cURL Example

curl -X GET "http://localhost:4001/api/v1/users?page=1&limit=20" \
  -H "Authorization: Bearer ADMIN_TOKEN"

PUT /api/v1/users/name — Update Display Name

Auth: Protected (Authorization: Bearer <accessToken>)
Used by: owner-booki-web-app, customer-booki-web-app · Role: owner, branch-manager, customer
organizationId: From JWT token (not required in request body)
Description: Update user's first, middle, or last name (at least one required).

Request

{
  "firstName": "Janet",
  "lastName": "Smith"
}

Fields (at least one of the following required):

  • firstName (string, optional): First name (max 255)
  • middleName (string, optional): Middle name (max 255)
  • lastName (string, optional): Last name (max 255)

Note: id is injected from the JWT token server-side.

Response (200 OK)

{
  "message": "Name updated successfully."
}

cURL Example

curl -X PUT http://localhost:4001/api/v1/users/name \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer eyJhbGc..." \
  -d '{
    "firstName": "Janet",
    "lastName": "Smith"
  }'

PUT /api/v1/users/:id/password — Update Password

Auth: Protected (Authorization: Bearer <accessToken>)
Used by: owner-booki-web-app, customer-booki-web-app · Role: owner, branch-manager, customer
organizationId: From JWT token
Description: Change user password (requires strong password).

Request

PUT /api/v1/users/507f1f77bcf86cd799439011/password

Body:

{
  "password": "NewSecureP@ss123"
}

Fields:

  • password (string, required): New password (min 8 chars, must include uppercase, lowercase, number, and special character)

Note: id is read from the URL path parameter.

Response (200 OK)

{
  "message": "Password updated successfully."
}

Error Responses

422 Unprocessable Entity — Weak password:

{
  "statusCode": 422,
  "message": "Password must contain at least one uppercase letter, one lowercase letter, one number, and one special character."
}

cURL Example

curl -X PUT http://localhost:4001/api/v1/users/507f1f77bcf86cd799439011/password \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer eyJhbGc..." \
  -d '{
    "password": "NewSecureP@ss123"
  }'

PUT /api/v1/users/payment-preference — Update Payment Preference

Auth: Protected (Authorization: Bearer <accessToken>)
Used by: owner-booki-web-app, customer-booki-web-app · Role: owner, customer
organizationId: From JWT token
Description: Set the user's preferred payment method for bookings.

Request

{
  "preferredPaymentMethod": "cash"
}

Fields:

  • preferredPaymentMethod (string, required): cash or maya

Note: id is injected from the JWT token server-side.

Response (200 OK)

{
  "message": "Payment method preference updated successfully."
}

cURL Example

curl -X PUT http://localhost:4001/api/v1/users/payment-preference \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer eyJhbGc..." \
  -d '{
    "preferredPaymentMethod": "cash"
  }'

DELETE /api/v1/users/:id — Delete User (Admin Only)

Auth: Protected (Authorization: Bearer <accessToken>)
Used by: admin-booki-web-app · Role: any authenticated user
organizationId: Not applicable
Description: Soft-delete a user account.

Request

DELETE /api/v1/users/507f1f77bcf86cd799439011

Response (200 OK)

{
  "message": "User deleted successfully."
}

Error Responses

404 Not Found — User not found:

{
  "statusCode": 404,
  "message": "User not found"
}

cURL Example

curl -X DELETE http://localhost:4001/api/v1/users/507f1f77bcf86cd799439011 \
  -H "Authorization: Bearer ADMIN_TOKEN"

GET /api/v1/subscription/my-payments — Get My Subscription Payment History

Auth: Protected (Authorization: Bearer <accessToken>)
Used by: owner-booki-web-app · Role: owner
organizationId: From JWT token
Description: Retrieve the subscription payment history for the current owner.

Response (200 OK)

{
  "items": [
    {
      "_id": "507f1f77bcf86cd799439091",
      "organizationId": "507f191e810c19729de860ea",
      "amount": 999.0,
      "status": "paid",
      "paidAt": "2026-04-01T10:00:00Z",
      "planName": "Pro Monthly"
    }
  ],
  "total": 10,
  "page": 1,
  "pages": 1
}

cURL Example

curl -X GET http://localhost:4001/api/v1/subscription/my-payments \
  -H "Authorization: Bearer eyJhbGc..."

GET /api/v1/subscription/payments/:id — Get Subscription Payment by ID

Auth: Protected (Authorization: Bearer <accessToken>)
Used by: owner-booki-web-app · Role: owner
organizationId: From JWT token
Description: Retrieve a specific subscription payment by ID.

cURL Example

curl -X GET http://localhost:4001/api/v1/subscription/payments/507f1f77bcf86cd799439091 \
  -H "Authorization: Bearer eyJhbGc..."

POST /api/v1/users/payment-methods/setup — Setup Customer Payment Method

Auth: Protected (Authorization: Bearer <accessToken>) · customer only
Used by: customer-booki-web-app · Role: customer
organizationId: From JWT token
Description: Initiate payment method setup for the authenticated customer. No request body required — the user identity is derived from the JWT token.

Response (200 OK)

{
  "paymentMethod": {
    "_id": "507f1f77bcf86cd799439099",
    "userId": "507f1f77bcf86cd799439011",
    "type": "maya",
    "last4": "1234",
    "createdAt": "2026-04-01T10:00:00Z"
  },
  "message": "Payment method saved successfully"
}

cURL Example

curl -X POST http://localhost:4001/api/v1/users/payment-methods/setup \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer eyJhbGc..." \
  -d '{"paymentToken": "tok_live_abc123...", "type": "maya"}'

GET /api/v1/users/payment-methods — List Customer Payment Methods

Auth: Protected (Authorization: Bearer <accessToken>) · customer only
Used by: customer-booki-web-app · Role: customer
organizationId: From JWT token
Description: List all saved payment methods for the current customer.

Response (200 OK)

{
  "items": [
    {
      "_id": "507f1f77bcf86cd799439099",
      "type": "maya",
      "last4": "1234",
      "createdAt": "2026-04-01T10:00:00Z"
    }
  ]
}

cURL Example

curl -X GET http://localhost:4001/api/v1/users/payment-methods \
  -H "Authorization: Bearer eyJhbGc..."

DELETE /api/v1/users/payment-methods/:paymentMethodId — Delete Customer Payment Method

Auth: Protected (Authorization: Bearer <accessToken>) · customer only
Used by: customer-booki-web-app · Role: customer
organizationId: From JWT token
Description: Remove a saved payment method.

Response (200 OK)

{
  "message": "Payment method removed"
}

cURL Example

curl -X DELETE http://localhost:4001/api/v1/users/payment-methods/507f1f77bcf86cd799439099 \
  -H "Authorization: Bearer eyJhbGc..."

User Types

TypeRoleAccess
ownerBusiness ownerFull organization control
branch-managerBranch managerBranch-level control
customerRegular customerCan book services
adminSuper-adminFull platform control
guestTemporary userOne-time booking

User Status

  • active: User can log in and access features
  • pending: Account created, not yet verified
  • suspended: Temporary suspension
  • deleted: Soft-deleted (marked with deletedAt)

Notes

  • All timestamps are ISO 8601 format.
  • Emails are case-insensitive and unique per organization.
  • Passwords are BCrypt hashed; never returned.
  • See booki-api/src/validations/user.validation.ts for field constraints.