Skip to main content

Auth Service API Documentation

Overview

The Auth Service provides authentication, authorization, and member management functionality with support for:

  • Authentication: Staff login, token management, session validation
  • Staff Management: CRUD operations for staff members
  • Service/API Key Management: Generate and manage API keys for service-to-service authentication
  • WeChat Member Management: WeChat OAuth login, member profile management, QR code generation
  • Consent Management: Privacy policy and terms of service versioning and acceptance tracking

Base URL

baseUrl/auth/api

Authentication

Most endpoints require authentication via JWT token in the Authorization header:

Authorization: Bearer <token>

The token should contain a sub field with the staff/member ID.

Note: Public endpoints like login and password reset do not require authentication.


Authentication API

GET baseUrl/auth/api/check-access-token-session

Check if the current access token session is valid.

Request

Endpoint: GET baseUrl/auth/api/check-access-token-session

Headers:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Example Request

GET baseUrl/auth/api/check-access-token-session

Response

Success Response (200 OK):

{
"statusCode": 200,
"data": {
"message": "Access token is valid",
"data": {
"valid": true
}
}
}

POST baseUrl/auth/api/get-new-access-token

Get a new access token using a refresh token.

Request

Endpoint: POST baseUrl/auth/api/get-new-access-token

Headers:

Content-Type: application/json

Request Body:

{
refreshToken?: string; // Optional, if not provided, will use refreshToken from cookie
}

Example Request

{
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}

Response

Success Response (200 OK):

{
"statusCode": 200,
"data": {
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
}

Note: The refresh token is also set as an HTTP-only cookie.

Error Response (401 Unauthorized):

{
"statusCode": 401,
"data": {
"message": "Refresh token not found in cookies"
}
}

Staff Actions API

POST baseUrl/auth/api/staffs/login

Staff login with email and password.

Request

Endpoint: POST baseUrl/auth/api/staffs/login

Headers:

Content-Type: application/json

Request Body:

{
email: string; // Required, valid email format
password: string; // Required, minimum 1 character
}

Example Request

{
"email": "staff@example.com",
"password": "securePassword123"
}

Response

Success Response (200 OK):

{
"statusCode": 200,
"data": {
"message": "Login successful",
"data": {
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
}
}

Note: The refresh token is automatically set as an HTTP-only cookie.

Error Response (401 Unauthorized):

{
"statusCode": 401,
"data": {
"message": "Invalid email or password"
}
}

POST baseUrl/auth/api/staffs/request-reset-password

Request password reset for a staff member (admin-initiated).

Request

Endpoint: POST baseUrl/auth/api/staffs/request-reset-password

Headers:

Content-Type: application/json

Request Body:

{
type: "EMAIL" | "SMS"; // Required, reset password session type
staffId: string; // Required, UUID of the staff member
}

Example Request

{
"type": "EMAIL",
"staffId": "550e8400-e29b-41d4-a716-446655440000"
}

Response

Success Response (200 OK):

{
"statusCode": 200,
"data": {
"message": "Reset password request sent successfully"
}
}

POST baseUrl/auth/api/staffs/request-reset-password-by-email

Request password reset by email (self-service).

Request

Endpoint: POST baseUrl/auth/api/staffs/request-reset-password-by-email

Headers:

Content-Type: application/json

Request Body:

{
email: string; // Required, valid email format
locale?: "en" | "th" | "cn"; // Optional, default: "en"
}

Example Request

{
"email": "staff@example.com",
"locale": "en"
}

Response

Success Response (200 OK):

{
"statusCode": 200,
"data": {
"message": "Reset password request sent successfully"
}
}

POST baseUrl/auth/api/staffs/reset-password/:sessionId

Reset password using session ID and verification code.

Request

Endpoint: POST baseUrl/auth/api/staffs/reset-password/:sessionId

Headers:

Content-Type: application/json

Path Parameters:

{
sessionId: string; // UUID of the reset password session
}

Request Body:

{
code: string; // Required, verification code (minimum 1 character)
newPassword: string; // Required, minimum 6 characters
}

Example Request

{
"code": "123456",
"newPassword": "newSecurePassword123"
}

Response

Success Response (200 OK):

{
"statusCode": 200,
"data": {
"message": "Password reset successfully"
}
}

Error Response (400 Bad Request):

{
"statusCode": 400,
"data": {
"message": "Invalid or expired session"
}
}

GET baseUrl/auth/api/staffs/check-session/:sessionId

Check if a reset password session is valid.

Request

Endpoint: GET baseUrl/auth/api/staffs/check-session/:sessionId

Path Parameters:

{
sessionId: string; // UUID of the reset password session
}

Example Request

GET baseUrl/auth/api/staffs/check-session/550e8400-e29b-41d4-a716-446655440000

Response

Success Response (200 OK):

{
"statusCode": 200,
"data": {
"message": "Session check completed",
"data": {
"isValid": true
}
}
}

Staff Management API

GET baseUrl/auth/api/staffs

Get all staff members with pagination and filtering.

Request

Endpoint: GET baseUrl/auth/api/staffs

Headers:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Query Parameters:

{
page?: number; // Page number (default: 1)
limit?: number; // Items per page (default: 10)
storeId?: string; // Filter by store ID
roleId?: string; // Filter by role ID (UUID)
status?: "ACTIVE" | "INACTIVE" | "WAIT_FOR_FIRST_ACTIVE"; // Filter by status
search?: string; // Search in name/email
}

Example Request

GET baseUrl/auth/api/staffs?page=1&limit=20&status=ACTIVE&roleId=role-123

Response

Success Response (200 OK):

{
"statusCode": 200,
"data": {
"message": "Staff list retrieved successfully",
"data": {
"meta": {
"page": 1,
"limit": 20,
"total": 45,
"totalPages": 3
},
"data": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "staff@example.com",
"firstname": "John",
"lastname": "Doe",
"phoneNumber": "+66123456789",
"roleId": "role-123",
"storeId": "store-001",
"status": "ACTIVE",
"locale": "en",
"createdAt": "2024-01-15T10:30:00.000Z",
"updatedAt": "2024-01-15T10:30:00.000Z"
}
]
}
}
}

GET baseUrl/auth/api/staffs/me

Get the current authenticated staff member's information.

Request

Endpoint: GET baseUrl/auth/api/staffs/me

Headers:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Example Request

GET baseUrl/auth/api/staffs/me

Response

Success Response (200 OK):

{
"statusCode": 200,
"data": {
"message": "Staff retrieved successfully",
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "staff@example.com",
"firstname": "John",
"lastname": "Doe",
"phoneNumber": "+66123456789",
"roleId": "role-123",
"storeId": "store-001",
"status": "ACTIVE",
"locale": "en",
"createdAt": "2024-01-15T10:30:00.000Z",
"updatedAt": "2024-01-15T10:30:00.000Z"
}
}
}

Error Response (404 Not Found):

{
"statusCode": 404,
"data": {
"message": "Staff not found",
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000"
}
}
}

GET baseUrl/auth/api/staffs/:id

Get a specific staff member by ID.

Request

Endpoint: GET baseUrl/auth/api/staffs/:id

Headers:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Path Parameters:

{
id: string; // UUID of the staff member
}

Example Request

GET baseUrl/auth/api/staffs/550e8400-e29b-41d4-a716-446655440000

Response

Success Response (200 OK):

{
"statusCode": 200,
"data": {
"message": "Staff retrieved successfully",
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "staff@example.com",
"firstname": "John",
"lastname": "Doe",
"phoneNumber": "+66123456789",
"roleId": "role-123",
"storeId": "store-001",
"status": "ACTIVE",
"locale": "en",
"createdAt": "2024-01-15T10:30:00.000Z",
"updatedAt": "2024-01-15T10:30:00.000Z"
}
}
}

POST baseUrl/auth/api/staffs

Create a new staff member.

Request

Endpoint: POST baseUrl/auth/api/staffs

Headers:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json

Request Body:

{
email: string; // Required, valid email format
firstname: string; // Required, max 256 characters
lastname: string; // Required, max 256 characters
phoneNumber?: string; // Optional, max 256 characters
roleId: string; // Required, UUID
storeId?: string; // Optional store ID
status?: "ACTIVE" | "INACTIVE" | "WAIT_FOR_FIRST_ACTIVE"; // Optional, default: "WAIT_FOR_FIRST_ACTIVE"
locale?: "en" | "th" | "cn"; // Optional, default: "en"
}

Example Request

{
"email": "newstaff@example.com",
"firstname": "Jane",
"lastname": "Smith",
"phoneNumber": "+66987654321",
"roleId": "role-123",
"storeId": "store-001",
"status": "WAIT_FOR_FIRST_ACTIVE",
"locale": "en"
}

Response

Success Response (201 Created):

{
"statusCode": 201,
"data": {
"message": "Staff created successfully",
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "newstaff@example.com",
"firstname": "Jane",
"lastname": "Smith",
"phoneNumber": "+66987654321",
"roleId": "role-123",
"storeId": "store-001",
"status": "WAIT_FOR_FIRST_ACTIVE",
"locale": "en",
"createdAt": "2024-01-15T10:30:00.000Z",
"updatedAt": "2024-01-15T10:30:00.000Z"
}
}
}

PUT baseUrl/auth/api/staffs/:id

Update an existing staff member.

Request

Endpoint: PUT baseUrl/auth/api/staffs/:id

Headers:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json

Path Parameters:

{
id: string; // UUID of the staff member
}

Request Body:

{
email: string; // Required, valid email format
firstname: string; // Required, max 256 characters
lastname: string; // Required, max 256 characters
phoneNumber?: string; // Optional, max 256 characters
roleId: string; // Required, UUID
storeId?: string; // Optional store ID
}

Example Request

{
"email": "updated@example.com",
"firstname": "Jane",
"lastname": "Doe",
"phoneNumber": "+66987654321",
"roleId": "role-456",
"storeId": "store-002"
}

Response

Success Response (200 OK):

{
"statusCode": 200,
"data": {
"message": "Staff updated successfully",
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "updated@example.com",
"firstname": "Jane",
"lastname": "Doe",
"phoneNumber": "+66987654321",
"roleId": "role-456",
"storeId": "store-002",
"status": "ACTIVE",
"locale": "en",
"createdAt": "2024-01-15T10:30:00.000Z",
"updatedAt": "2024-01-20T14:30:00.000Z"
}
}
}

DELETE baseUrl/auth/api/staffs/:id

Delete (soft delete) a staff member.

Request

Endpoint: DELETE baseUrl/auth/api/staffs/:id

Headers:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Path Parameters:

{
id: string; // UUID of the staff member
}

Example Request

DELETE baseUrl/auth/api/staffs/550e8400-e29b-41d4-a716-446655440000

Response

Success Response (200 OK):

{
"statusCode": 200,
"data": {
"message": "Staff deleted successfully",
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000"
}
}
}

Service/API Key Management API

POST baseUrl/auth/api/services/generate-api-key

Generate a new API key for service-to-service authentication.

Request

Endpoint: POST baseUrl/auth/api/services/generate-api-key

Headers:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json

Request Body:

{
name: string; // Required, max 256 characters (service name)
roleId: string; // Required, UUID (role for the API key)
expiredIn?: number; // Optional, expiration time in milliseconds
}

Example Request

{
"name": "Point Service API Key",
"roleId": "role-service-point-id",
"expiredIn": 31536000000
}

Response

Success Response (201 Created):

{
"statusCode": 201,
"data": {
"id": "service-key-id",
"name": "Point Service API Key",
"apiKey": "sb_api_abc123def456...",
"roleId": "role-service-point-id",
"expiresAt": "2025-01-15T10:30:00.000Z",
"createdAt": "2024-01-15T10:30:00.000Z"
}
}

GET baseUrl/auth/api/services/me

Get all API keys for the current authenticated staff member.

Request

Endpoint: GET baseUrl/auth/api/services/me

Headers:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Query Parameters:

{
page?: number; // Page number (default: 1)
limit?: number; // Items per page (default: 10)
}

Example Request

GET baseUrl/auth/api/services/me?page=1&limit=20

Response

Success Response (200 OK):

{
"statusCode": 200,
"data": {
"meta": {
"page": 1,
"limit": 20,
"total": 3,
"totalPages": 1
},
"data": [
{
"id": "service-key-id-1",
"name": "Point Service API Key",
"roleId": "role-service-point-id",
"expiresAt": "2025-01-15T10:30:00.000Z",
"createdAt": "2024-01-15T10:30:00.000Z"
}
]
}
}

Note: The actual apiKey is only returned when first created for security reasons.


DELETE baseUrl/auth/api/services/revoke/:id

Revoke (delete) an API key.

Request

Endpoint: DELETE baseUrl/auth/api/services/revoke/:id

Headers:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Path Parameters:

{
id: string; // UUID of the service/API key
}

Example Request

DELETE baseUrl/auth/api/services/revoke/service-key-id-1

Response

Success Response (204 No Content):

No response body.


POST baseUrl/auth/api/services/get-access-token

Get an access token using an API key (for service-to-service authentication).

Request

Endpoint: POST baseUrl/auth/api/services/get-access-token

Headers:

Content-Type: application/json

Request Body:

{
apiKey: string; // Required, the API key string
}

Example Request

{
"apiKey": "sb_api_abc123def456..."
}

Response

Success Response (200 OK):

{
"statusCode": 200,
"data": {
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expiresIn": 3600
}
}

Error Response (401 Unauthorized):

{
"statusCode": 401,
"data": {
"message": "Invalid API key"
}
}

WeChat Member Management API

POST baseUrl/auth/api/members/wechat/login

WeChat OAuth login using WeChat code.

Request

Endpoint: POST baseUrl/auth/api/members/wechat/login

Headers:

Content-Type: application/json

Request Body:

{
code: string; // Required, WeChat authorization code (minimum 1 character)
}

Example Request

{
"code": "wechat_code_abc123..."
}

Response

Success Response (200 OK):

{
"statusCode": 200,
"data": {
"message": "WeChat login successful",
"data": {
"status": "NEW" | "EXISTING",
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
}
}

Note: The refresh token is automatically set as an HTTP-only cookie.

Status values:

  • NEW - New member created
  • EXISTING - Existing member logged in

GET baseUrl/auth/api/members/me

Get the current authenticated member's information.

Request

Endpoint: GET baseUrl/auth/api/members/me

Headers:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Example Request

GET baseUrl/auth/api/members/me

Response

Success Response (200 OK):

{
"statusCode": 200,
"data": {
"message": "WeChat member retrieved successfully",
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"openId": "wechat_openid_abc123",
"nickName": "John Doe",
"avatarUrl": "https://thirdwx.qlogo.cn/...",
"name": "John Doe",
"phoneNumber": "+66123456789",
"gender": "Male",
"birthDate": "1990-01-15T00:00:00.000Z",
"address": {
"address": "123 Main Street",
"subDistrict": "Subdistrict",
"district": "District",
"province": "Bangkok",
"postCode": "10110",
"country": "Thailand",
"latitude": 13.7563,
"longitude": 100.5018
},
"status": "ACTIVE",
"createdAt": "2024-01-15T10:30:00.000Z",
"updatedAt": "2024-01-15T10:30:00.000Z"
}
}
}

Error Response (404 Not Found):

{
"statusCode": 404,
"data": {
"message": "WeChat member not found",
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000"
}
}
}

PUT baseUrl/auth/api/members/me

Update the current authenticated member's information.

Request

Endpoint: PUT baseUrl/auth/api/members/me

Headers:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json

Request Body:

{
nickName?: string; // Optional, max 256 characters
avatarUrl?: string; // Optional, valid URL
birthDate?: string; // Optional, ISO 8601 date string
name?: string; // Optional, max 100 characters
gender?: "Male" | "Female" | "Other"; // Optional
phoneNumber?: string; // Optional, max 20 characters
address?: { // Optional
address?: string;
subDistrict?: string;
district?: string;
province?: string;
postCode?: string;
country?: string;
latitude?: number;
longitude?: number;
};
}

Example Request

{
"name": "John Updated",
"phoneNumber": "+66987654321",
"gender": "Male",
"birthDate": "1990-01-15",
"address": {
"address": "456 New Street",
"province": "Bangkok",
"postCode": "10120"
}
}

Response

Success Response (200 OK):

{
"statusCode": 200,
"data": {
"message": "WeChat member updated successfully"
}
}

GET baseUrl/auth/api/members/me/qr-code

Get QR code identity for the authenticated member.

Request

Endpoint: GET baseUrl/auth/api/members/me/qr-code

Headers:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Example Request

GET baseUrl/auth/api/members/me/qr-code

Response

Success Response (200 OK):

{
"statusCode": 200,
"data": {
"qrCodeUrl": "https://storage.example.com/qr-codes/550e8400-e29b-41d4-a716-446655440000.png",
"memberId": "550e8400-e29b-41d4-a716-446655440000"
}
}

GET baseUrl/auth/api/members

Get all members with pagination and filtering.

Request

Endpoint: GET baseUrl/auth/api/members

Headers:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Query Parameters:

{
page?: number; // Page number (default: 1)
limit?: number; // Items per page (default: 10)
birthdayFrom?: string; // Filter by birthday from date (ISO 8601)
search?: string; // Search in name/nickname/phone/email
includePointBalance?: boolean; // Include point balance (default: false)
includeTier?: boolean; // Include tier information (default: false)
locale?: "en" | "th" | "cn"; // Localize response content
}

Example Request

GET baseUrl/auth/api/members?page=1&limit=20&search=John&includePointBalance=true&includeTier=true&locale=en

Response

Success Response (200 OK):

{
"statusCode": 200,
"data": {
"message": "WeChat members retrieved successfully",
"data": {
"meta": {
"page": 1,
"limit": 20,
"total": 150,
"totalPages": 8
},
"data": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"openId": "wechat_openid_abc123",
"nickName": "John Doe",
"avatarUrl": "https://thirdwx.qlogo.cn/...",
"name": "John Doe",
"phoneNumber": "+66123456789",
"gender": "Male",
"status": "ACTIVE",
"pointBalance": 1250,
"tier": {
"id": "tier-gold-id",
"name_en": "Gold",
"level": 3
},
"createdAt": "2024-01-15T10:30:00.000Z",
"updatedAt": "2024-01-15T10:30:00.000Z"
}
]
}
}
}

POST baseUrl/auth/api/members/bulk

Get multiple members by their IDs (bulk query).

Request

Endpoint: POST baseUrl/auth/api/members/bulk

Headers:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json

Request Body:

{
ids: string[]; // Array of member UUIDs
}

Example Request

{
"ids": [
"550e8400-e29b-41d4-a716-446655440000",
"660e8400-e29b-41d4-a716-446655440001"
]
}

Response

Success Response (200 OK):

{
"statusCode": 200,
"data": {
"message": "WeChat members retrieved successfully",
"data": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"nickName": "John Doe",
"name": "John Doe",
"status": "ACTIVE"
},
{
"id": "660e8400-e29b-41d4-a716-446655440001",
"nickName": "Jane Smith",
"name": "Jane Smith",
"status": "ACTIVE"
}
]
}
}

GET baseUrl/auth/api/members/:id

Get a specific member by ID.

Request

Endpoint: GET baseUrl/auth/api/members/:id

Headers:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Path Parameters:

{
id: string; // UUID of the member
}

Query Parameters:

{
includeTier?: boolean; // Include tier information (default: false)
locale?: "en" | "th" | "cn"; // Localize response content
}

Example Request

GET baseUrl/auth/api/members/550e8400-e29b-41d4-a716-446655440000?includeTier=true&locale=en

Response

Success Response (200 OK):

{
"statusCode": 200,
"data": {
"message": "WeChat member retrieved successfully",
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"openId": "wechat_openid_abc123",
"nickName": "John Doe",
"avatarUrl": "https://thirdwx.qlogo.cn/...",
"name": "John Doe",
"phoneNumber": "+66123456789",
"gender": "Male",
"birthDate": "1990-01-15T00:00:00.000Z",
"status": "ACTIVE",
"tier": {
"id": "tier-gold-id",
"name_en": "Gold",
"level": 3
},
"createdAt": "2024-01-15T10:30:00.000Z",
"updatedAt": "2024-01-15T10:30:00.000Z"
}
}
}

POST baseUrl/auth/api/members/wechat/sync/:memberId

Sync WeChat member information from WeChat API.

Request

Endpoint: POST baseUrl/auth/api/members/wechat/sync/:memberId

Headers:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json

Path Parameters:

{
memberId: string; // UUID of the member
}

Request Body:

{
nickName?: string; // Optional, max 256 characters
avatarUrl?: string; // Optional, valid URL
name?: string; // Optional, max 100 characters
phoneNumber?: string; // Optional, max 20 characters
gender?: 0 | 1 | 2; // Optional, WeChat gender (0: unknown, 1: male, 2: female)
province?: string; // Optional, max 100 characters
city?: string; // Optional, max 100 characters
country?: string; // Optional, max 100 characters
}

Example Request

{
"nickName": "Updated Nickname",
"avatarUrl": "https://thirdwx.qlogo.cn/new_avatar.jpg",
"gender": 1
}

Response

Success Response (200 OK):

{
"statusCode": 200,
"data": {
"message": "WeChat info synced successfully"
}
}

PUT baseUrl/auth/api/members/:memberId

Update a member's information (admin).

Request

Endpoint: PUT baseUrl/auth/api/members/:memberId

Headers:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json

Path Parameters:

{
memberId: string; // UUID of the member
}

Request Body: Same as PUT baseUrl/auth/api/members/me

Example Request

{
"name": "John Updated",
"phoneNumber": "+66987654321"
}

Response

Success Response (200 OK):

{
"statusCode": 200,
"data": {
"message": "WeChat member updated successfully"
}
}

POST baseUrl/auth/api/members/direct

Create a member directly (staff/admin, without WeChat OAuth).

Request

Endpoint: POST baseUrl/auth/api/members/direct

Headers:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json

Request Body:

{
birthDate?: string; // Optional, ISO 8601 date string
name: string; // Required, max 100 characters
gender?: "Male" | "Female" | "Other"; // Optional
phoneNumber: string; // Required, max 20 characters
address?: { // Optional
address?: string;
subDistrict?: string;
district?: string;
province?: string;
postCode?: string;
country?: string;
latitude?: number;
longitude?: number;
};
}

Example Request

{
"name": "John Doe",
"phoneNumber": "+66123456789",
"gender": "Male",
"birthDate": "1990-01-15",
"address": {
"address": "123 Main Street",
"province": "Bangkok",
"postCode": "10110"
}
}

Response

Success Response (200 OK):

{
"statusCode": 200,
"data": {
"message": "WeChat member created successfully via direct create"
}
}

PUT baseUrl/auth/api/members/:memberId/direct

Update a member directly with full control (staff/admin).

Request

Endpoint: PUT baseUrl/auth/api/members/:memberId/direct

Headers:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json

Path Parameters:

{
memberId: string; // UUID of the member
}

Request Body:

{
nickName?: string; // Optional, max 256 characters
avatarUrl?: string; // Optional, valid URL
birthDate?: string; // Optional, ISO 8601 date string
name?: string; // Optional, max 100 characters
gender?: "Male" | "Female" | "Other"; // Optional
phoneNumber?: string; // Optional, max 20 characters
address?: { // Optional
address?: string;
subDistrict?: string;
district?: string;
province?: string;
postCode?: string;
country?: string;
latitude?: number;
longitude?: number;
};
status?: "PENDING" | "WECHAT_INFO_SYNCED" | "ACTIVE" | "INACTIVE"; // Optional
}

Example Request

{
"name": "John Updated",
"status": "ACTIVE",
"phoneNumber": "+66987654321"
}

Response

Success Response (200 OK):

{
"statusCode": 200,
"data": {
"message": "WeChat member updated successfully via direct update"
}
}

PATCH baseUrl/auth/api/members/:memberId/set-active

Set the active status of a member.

Request

Endpoint: PATCH baseUrl/auth/api/members/:memberId/set-active

Headers:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json

Path Parameters:

{
memberId: string; // UUID of the member
}

Request Body:

{
isActive: boolean; // Required
}

Example Request

{
"isActive": false
}

Response

Success Response (200 OK):

{
"statusCode": 200,
"data": {
"message": "WeChat member set active successfully"
}
}

GET baseUrl/auth/api/members/summary/daily

Get daily member registration summary statistics.

Request

Endpoint: GET baseUrl/auth/api/members/summary/daily

Headers:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Query Parameters:

{
startDate?: string; // Start date (ISO 8601 format)
endDate?: string; // End date (ISO 8601 format)
}

Example Request

GET baseUrl/auth/api/members/summary/daily?startDate=2024-01-01&endDate=2024-01-31

Response

Success Response (200 OK):

{
"statusCode": 200,
"data": {
"message": "WeChat member summary daily retrieved successfully",
"data": [
{
"date": "2024-01-15",
"newMembers": 25,
"activeMembers": 1500
},
{
"date": "2024-01-16",
"newMembers": 30,
"activeMembers": 1530
}
]
}
}

GET baseUrl/auth/api/consents/current

Get the current active consent (privacy policy/terms of service).

Request

Endpoint: GET baseUrl/auth/api/consents/current

Query Parameters:

{
locale?: "en" | "th" | "cn"; // Optional, default: "en"
}

Example Request

GET baseUrl/auth/api/consents/current?locale=en

Response

Success Response (200 OK):

{
"statusCode": 200,
"data": {
"message": "Current consent retrieved successfully",
"data": {
"id": "consent-id-123",
"version": "1.2.0",
"versionType": "MINOR",
"title_en": "Privacy Policy",
"title_th": "นโยบายความเป็นส่วนตัว",
"title_cn": "隐私政策",
"content_en": "Privacy policy content...",
"content_th": "เนื้อหานโยบายความเป็นส่วนตัว...",
"content_cn": "隐私政策内容...",
"isCurrent": true,
"publishedAt": "2024-01-01T00:00:00.000Z",
"createdAt": "2024-01-01T00:00:00.000Z",
"updatedAt": "2024-01-01T00:00:00.000Z"
}
}
}

GET baseUrl/auth/api/consents

Get all consents with pagination.

Request

Endpoint: GET baseUrl/auth/api/consents

Headers:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Query Parameters:

{
page?: number; // Page number (default: 1, min: 1)
limit?: number; // Items per page (default: 10, min: 1, max: 100)
locale?: "en" | "th" | "cn"; // Optional, default: "en"
}

Example Request

GET baseUrl/auth/api/consents?page=1&limit=20&locale=en

Response

Success Response (200 OK):

{
"statusCode": 200,
"data": {
"message": "Consents retrieved successfully",
"data": {
"meta": {
"page": 1,
"limit": 20,
"total": 5,
"totalPages": 1
},
"data": [
{
"id": "consent-id-123",
"version": "1.2.0",
"versionType": "MINOR",
"title_en": "Privacy Policy",
"title_th": "นโยบายความเป็นส่วนตัว",
"title_cn": "隐私政策",
"isCurrent": true,
"createdAt": "2024-01-01T00:00:00.000Z"
}
]
}
}
}

GET baseUrl/auth/api/consents/:id

Get a specific consent by ID.

Request

Endpoint: GET baseUrl/auth/api/consents/:id

Headers:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Path Parameters:

{
id: string; // UUID of the consent
}

Query Parameters:

{
locale?: "en" | "th" | "cn"; // Optional, default: "en"
}

Example Request

GET baseUrl/auth/api/consents/consent-id-123?locale=en

Response

Success Response (200 OK):

{
"statusCode": 200,
"data": {
"message": "Consent retrieved successfully",
"data": {
"id": "consent-id-123",
"version": "1.2.0",
"versionType": "MINOR",
"title_en": "Privacy Policy",
"title_th": "นโยบายความเป็นส่วนตัว",
"title_cn": "隐私政策",
"content_en": "Privacy policy content...",
"content_th": "เนื้อหานโยบายความเป็นส่วนตัว...",
"content_cn": "隐私政策内容...",
"isCurrent": true,
"publishedAt": "2024-01-01T00:00:00.000Z",
"createdAt": "2024-01-01T00:00:00.000Z",
"updatedAt": "2024-01-01T00:00:00.000Z"
}
}
}

POST baseUrl/auth/api/consents

Create a new consent version.

Request

Endpoint: POST baseUrl/auth/api/consents

Headers:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json

Request Body:

{
title_en: string; // Required, max 256 characters
title_th: string; // Required, max 256 characters
title_cn: string; // Required, max 256 characters
content_en: string; // Required
content_th: string; // Required
content_cn: string; // Required
versionType?: "MAJOR" | "MINOR"; // Optional, default: "MINOR"
}

Example Request

{
"title_en": "Privacy Policy",
"title_th": "นโยบายความเป็นส่วนตัว",
"title_cn": "隐私政策",
"content_en": "Updated privacy policy content...",
"content_th": "เนื้อหานโยบายความเป็นส่วนตัวที่อัปเดต...",
"content_cn": "更新的隐私政策内容...",
"versionType": "MINOR"
}

Response

Success Response (201 Created):

{
"statusCode": 201,
"data": {
"message": "Consent created successfully",
"data": {
"id": "consent-id-124",
"version": "1.2.1",
"versionType": "MINOR",
"title_en": "Privacy Policy",
"isCurrent": false,
"createdAt": "2024-01-20T10:30:00.000Z"
}
}
}

PUT baseUrl/auth/api/consents/:id

Update consent content.

Request

Endpoint: PUT baseUrl/auth/api/consents/:id

Headers:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json

Path Parameters:

{
id: string; // UUID of the consent
}

Request Body: All fields optional, but at least one must be provided:

{
title_en?: string; // Optional, max 256 characters
title_th?: string; // Optional, max 256 characters
title_cn?: string; // Optional, max 256 characters
content_en?: string; // Optional
content_th?: string; // Optional
content_cn?: string; // Optional
}

Example Request

{
"content_en": "Updated privacy policy content v2..."
}

Response

Success Response (200 OK):

{
"statusCode": 200,
"data": {
"message": "Consent updated successfully",
"data": {
"id": "consent-id-123",
"version": "1.2.0",
"content_en": "Updated privacy policy content v2...",
"updatedAt": "2024-01-20T14:30:00.000Z"
}
}
}

PATCH baseUrl/auth/api/consents/publish

Publish (set as current) a consent version.

Request

Endpoint: PATCH baseUrl/auth/api/consents/publish

Headers:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json

Request Body:

{
id: string; // Required, UUID of the consent to publish
}

Example Request

{
"id": "consent-id-124"
}

Response

Success Response (200 OK):

{
"statusCode": 200,
"data": {
"message": "Consent published successfully",
"data": {
"id": "consent-id-124",
"version": "1.2.1",
"isCurrent": true,
"publishedAt": "2024-01-20T15:00:00.000Z"
}
}
}

PATCH baseUrl/auth/api/consents/rollback

Rollback to the previous consent version.

Request

Endpoint: PATCH baseUrl/auth/api/consents/rollback

Headers:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Example Request

PATCH baseUrl/auth/api/consents/rollback

Response

Success Response (200 OK):

{
"statusCode": 200,
"data": {
"message": "Consent rolled back successfully",
"data": {
"previousConsentId": "consent-id-123",
"currentConsentId": "consent-id-122"
}
}
}

POST baseUrl/auth/api/consents/members/accept-current

Accept the current active consent for the authenticated member.

Request

Endpoint: POST baseUrl/auth/api/consents/members/accept-current

Headers:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Example Request

POST baseUrl/auth/api/consents/members/accept-current

Response

Success Response (201 Created):

{
"statusCode": 201,
"data": {
"message": "Current consent accepted successfully",
"data": {
"id": "acceptance-id-123",
"memberId": "550e8400-e29b-41d4-a716-446655440000",
"consentId": "consent-id-123",
"consentVersion": "1.2.0",
"acceptedAt": "2024-01-15T10:30:00.000Z"
}
}
}

GET baseUrl/auth/api/consents/members/me

Get the current authenticated member's consent acceptance information.

Request

Endpoint: GET baseUrl/auth/api/consents/members/me

Headers:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Query Parameters:

{
locale?: "en" | "th" | "cn"; // Optional, default: "en"
}

Example Request

GET baseUrl/auth/api/consents/members/me?locale=en

Response

Success Response (200 OK):

{
"statusCode": 200,
"data": {
"message": "Member consent acceptance retrieved successfully",
"data": {
"memberId": "550e8400-e29b-41d4-a716-446655440000",
"latestAcceptedConsentId": "consent-id-123",
"latestAcceptedConsentVersion": "1.2.0",
"latestAcceptedAt": "2024-01-15T10:30:00.000Z",
"currentConsentId": "consent-id-124",
"currentConsentVersion": "1.2.1",
"needsAcceptance": true
}
}
}

GET baseUrl/auth/api/consents/members/:id

Get consent acceptance information for a specific member.

Request

Endpoint: GET baseUrl/auth/api/consents/members/:id

Headers:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Path Parameters:

{
id: string; // UUID of the member
}

Query Parameters:

{
locale?: "en" | "th" | "cn"; // Optional, default: "en"
}

Example Request

GET baseUrl/auth/api/consents/members/550e8400-e29b-41d4-a716-446655440000?locale=en

Response

Success Response (200 OK):

Same structure as GET baseUrl/auth/api/consents/members/me


GET baseUrl/auth/api/consents/members

Get all member consent acceptances with pagination (admin).

Request

Endpoint: GET baseUrl/auth/api/consents/members

Headers:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Query Parameters:

{
page?: number; // Page number (default: 1)
limit?: number; // Items per page (default: 10)
}

Example Request

GET baseUrl/auth/api/consents/members?page=1&limit=20

Response

Success Response (200 OK):

{
"statusCode": 200,
"data": {
"message": "Member consent acceptances retrieved successfully",
"data": {
"meta": {
"page": 1,
"limit": 20,
"total": 1500,
"totalPages": 75
},
"data": [
{
"id": "acceptance-id-123",
"memberId": "550e8400-e29b-41d4-a716-446655440000",
"consentId": "consent-id-123",
"consentVersion": "1.2.0",
"acceptedAt": "2024-01-15T10:30:00.000Z"
}
]
}
}
}

Data Types & Enums

Staff Status

  • ACTIVE - Staff member is active
  • INACTIVE - Staff member is inactive
  • WAIT_FOR_FIRST_ACTIVE - Waiting for first password set

Member Status

  • PENDING - Member created but not yet activated
  • WECHAT_INFO_SYNCED - WeChat information synced
  • ACTIVE - Member is active
  • INACTIVE - Member is inactive

Gender

  • Male - Male
  • Female - Female
  • Other - Other

WeChat Gender

  • 0 - Unknown
  • 1 - Male
  • 2 - Female
  • MAJOR - Major version change
  • MINOR - Minor version change

Reset Password Session Type

  • EMAIL - Reset via email
  • SMS - Reset via SMS

Locales

  • en - English
  • th - Thai
  • cn - Chinese (Simplified)

Error Responses

All error responses follow this structure:

{
"statusCode": <HTTP_STATUS_CODE>,
"data": {
"message": "<Error message>",
"errors": [ // Optional, for validation errors
{
"field": "<field_name>",
"message": "<validation message>"
}
]
}
}

Common HTTP Status Codes

  • 200 OK - Request succeeded
  • 201 Created - Resource created successfully
  • 204 No Content - Request succeeded with no content
  • 400 Bad Request - Invalid request data or business rule violation
  • 401 Unauthorized - Missing or invalid authentication token
  • 403 Forbidden - Insufficient permissions
  • 404 Not Found - Resource not found
  • 500 Internal Server Error - Server error

Notes

  1. Authentication: Most endpoints require a valid JWT token in the Authorization header. The token's sub field should contain the staff/member ID.

  2. Cookies: Refresh tokens are automatically set as HTTP-only cookies for login endpoints. This provides better security than storing tokens in client-side storage.

  3. WeChat OAuth: The WeChat login flow uses OAuth 2.0. You need to obtain a WeChat authorization code from the WeChat mini-program or official account, then exchange it for tokens.

  4. Member Management:

    • Members can be created via WeChat OAuth login
    • Members can also be created directly by staff (without WeChat)
    • Direct update allows staff to update any field including status
    • Regular member update is for self-service profile updates
  5. Consent Management:

    • Only one consent can be "current" (published) at a time
    • Publishing a new consent automatically unpublishes the previous one
    • Version numbers are automatically generated based on version type (MAJOR/MINOR)
    • Members must accept new consent versions when published
  6. API Keys:

    • Used for service-to-service authentication
    • Can have expiration dates
    • Once revoked, cannot be used to obtain access tokens
    • The actual API key value is only shown once when created
  7. Password Reset:

    • Two methods: admin-initiated (with staff ID) or self-service (with email)
    • Creates a reset password session with a verification code
    • Session must be validated before resetting password
  8. Date Formats: All date fields use ISO 8601 format (e.g., 2024-12-31T23:59:59.000Z or 2024-12-31).

  9. Pagination: Pagination defaults to page 1 with 10 items per page. Maximum limit is 100 items per page.

  10. Localization: Use the locale query parameter to get localized content. If not specified, defaults to "en" for consent endpoints.


Support

For issues or questions, please contact the development team or refer to the main project documentation.