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.