Users API - Complete User Management
The Users API provides comprehensive user management capabilities including profile updates, account verification, TOS acceptance, and PSP integration. Built for enterprise-grade user lifecycle management with KYC compliance, multi-PSP support, and secure authentication flows.
🎯 What Can You Manage?
Your complete user ecosystem with these powerful tools:
- Profile Management: Update user profiles with OTP verification
- Account Verification: Email confirmation and account activation
- KYC Integration: PSP-based identity verification and status updates
- Terms of Service: TOS acceptance workflow with secure token generation
- Authentication: User logout and session management
- OTP System: Secure OTP generation and validation
- Admin Controls: User listing, detailed profiles, and administrative oversight
🧩 Your User Management Building Blocks
👤 Profile Management Blocks
PUT /users/update_profile/:user_id- Update user profile with verificationGET /users/:user_id- Get detailed user informationGET /users/users- List all users with filteringGET /users/countries- Get supported country list
✅ Account Verification Blocks
GET /users/confirm/:token- Confirm user account via email tokenGET /users/:user_id/tos-acceptance-link- Generate TOS acceptance linkPOST /users/:user_id/accept-tos- Accept Terms of Service
🔐 Authentication & Security Blocks
POST /users/logout- User logout and session terminationPOST /users/request-otp- Generate OTP for verificationPOST /users/psp_update- PSP/KYC status updates
🏗️ Common User Management Patterns
Pattern 1: "I want to update my profile securely"
Password verification → OTP generation → Profile update → Activity logging
Use: POST /users/request-otp → PUT /users/update_profile/:user_id
Pattern 2: "I want to verify new user accounts"
User registration → Email confirmation → Account activation
Use: GET /users/confirm/:token
Pattern 3: "I want to manage TOS compliance"
Generate TOS link → User acceptance → Update compliance status
Use: GET /users/:user_id/tos-acceptance-link → POST /users/:user_id/accept-tos
Pattern 4: "I want to process KYC updates"
PSP verification → Status update → User activation
Use: POST /users/psp_update
👤 Profile Management Operations
Update User Profile
Update User Profile with Verification
Update user profile information with current password verification and optional OTP validation. Includes activity logging and secure profile management with rollback support.
Parameters
user_idstringrequiredUser ID to update profile for
usernamestringNew username (optional)
emailstringNew email address (optional)
phonestringNew phone number (optional)
current_passwordstringrequiredCurrent password for verification
otp_codestringOTP code (required if USE_OTP_CHECK=true)
Request Body
{
"username": "johndoe_updated",
"email": "john.doe.new@example.com",
"phone": "+628123456789",
"current_password": "currentPassword123",
"otp_code": "123456"
}Response
{
"message": "Profil berhasil diperbarui",
"data": {
"user_id": 123,
"username": "johndoe_updated",
"email": "john.doe.new@example.com",
"phone": "+628123456789",
"updated": "2024-01-15T10:30:00Z"
}
}{
"error": "Password wajib diisi untuk memperbarui profil."
}{
"error": "Password salah"
}{
"error": "User tidak ditemukan"
}{
"error": "Gagal memperbarui profil",
"details": "Database connection error"
}Get User by ID
Get Detailed User Information
Retrieve comprehensive user information including profile data, client information, KYC status, and wallet details. Provides complete user overview for admin and user access.
Parameters
user_idstringrequiredUser ID to retrieve information for
Response
{
"success": true,
"data": {
"user_id": 123,
"client_id": 456,
"email": "john.doe@example.com",
"username": "johndoe",
"user_status": "ACTIVE",
"created": "2024-01-01T00:00:00Z",
"updated": "2024-01-15T10:30:00Z",
"role": "user",
"tos_accepted_at": "2024-01-02T08:00:00Z",
"psp_id": "DOKU_PSP",
"twitter_username": "johndoe_twitter",
"twitter_verified": true,
"twofa_enabled": false,
"phone": "+628123456789",
"client_alias": "John Doe Company",
"client_type": "INDIVIDUAL",
"client_status": "ACTIVE",
"country_code": "ID",
"client_code": "CLI-202401-001",
"ekyc_status": "APPROVED",
"ekyc_verified_at": "2024-01-03T12:00:00Z",
"ekyc_provider": "SUMSUB",
"ekyc_applicant_id": "APP123456",
"ekyb_status": "PENDING",
"ekyb_verified_at": null,
"ekyb_applicant_id": null,
"public_key": "PUB-abcd1234efgh5678",
"profile_picture": "https://storage.example.com/profiles/123.jpg"
}
}{
"error": "user_id tidak valid."
}{
"success": false,
"error": "User tidak ditemukan."
}{
"success": false,
"error": "Gagal mengambil data user."
}Get All Users
Get All Users with Statistics
Retrieve list of all users with transaction statistics, wallet balances, and filtering options. Includes comprehensive user analytics and volume data.
Parameters
client_idnumberFilter by specific client ID (optional)
Response
[
{
"user_id": 123,
"email": "john.doe@example.com",
"username": "johndoe",
"client_id": 456,
"user_status": "ACTIVE",
"ekyc_status": "APPROVED",
"transactions_count": 45,
"total_volume": "15750.00 USD",
"total_balance": "2500.50 USD"
},
{
"user_id": 124,
"email": "jane.smith@example.com",
"username": "janesmith",
"client_id": 456,
"user_status": "ACTIVE",
"ekyc_status": "PENDING",
"transactions_count": 12,
"total_volume": "3200.00 USD",
"total_balance": "850.25 USD"
}
]{
"error": "Terjadi kesalahan server"
}Get Country List
Get Supported Countries List
Retrieve list of supported countries from PSP providers with FIAT_PSP type. Returns country codes with mapped country names for user registration and country-specific configuration.
Response
{
"countries": [
{
"country_code": "AU",
"country_name": "Australia"
},
{
"country_code": "ID",
"country_name": "Indonesia"
},
{
"country_code": "IN",
"country_name": "India"
},
{
"country_code": "SG",
"country_name": "Singapore"
},
{
"country_code": "US",
"country_name": "United States"
}
]
}{
"error": "Failed to fetch country list."
}✅ Account Verification Operations
Confirm User Account
Confirm User Account via Email Token
Activate user account using confirmation token sent via email. Automatically activates user status and removes confirmation token upon successful verification.
Parameters
tokenstringrequiredEmail confirmation token (32-character hex string)
Response
"\n <html>\n <head><title>Konfirmasi Berhasil</title></head>\n <body>\n <h2>Akun Anda telah dikonfirmasi!</h2>\n <p>Silakan login untuk mengakses akun Anda.</p>\n <a href=\"undefined/login\">Ke Halaman Login</a>\n </body>\n </html>\n ""\n <html>\n <head><title>Konfirmasi Gagal</title></head>\n <body>\n <h2>Token tidak valid atau sudah kedaluwarsa.</h2>\n <p>Silakan daftar ulang atau hubungi support.</p>\n <a href=\"undefined/login\">Ke Halaman Login</a>\n </body>\n </html>\n ""\n <html>\n <head><title>Error</title></head>\n <body>\n <h2>Terjadi kesalahan saat konfirmasi akun.</h2>\n <p>Silakan coba lagi nanti atau hubungi support.</p>\n <a href=\"undefined/login\">Ke Halaman Login</a>\n </body>\n </html>\n "Generate TOS Acceptance Link
Generate Terms of Service Acceptance Link
Generate secure link for Terms of Service acceptance with time-limited token. Used for compliance management and legal agreement workflows.
Parameters
user_idstringrequiredUser ID to generate TOS link for
Response
{
"message": "TOS acceptance link generated successfully.",
"link": "https://frontend.example.com/accept-terms-of-service?email=john.doe@example.com&t=abc123def456..."
}{
"error": "Invalid user_id format."
}{
"error": "User not found."
}{
"error": "Failed to generate TOS acceptance link."
}Accept Terms of Service
Accept Terms of Service
Accept Terms of Service using secure token and update user compliance status. Validates token expiry and updates acceptance timestamp.
Parameters
user_idstringrequiredUser ID accepting TOS
tokenstringrequiredTOS acceptance token from generated link
Request Body
{
"token": "abc123def456ghi789jkl012mno345pqr"
}Response
{
"message": "TOS accepted successfully.",
"user_id": 123,
"tos_accepted_at": "2024-01-15T10:30:00Z"
}{
"error": "Invalid token or user_id."
}{
"error": "Token expired."
}{
"error": "Failed to accept TOS."
}🔐 Authentication & Security Operations
User Logout
User Logout and Session Termination
Logout user and terminate active session. Stateless logout for JWT-based authentication with activity logging.
Request Body
{}Response
{
"message": "Logout successful.",
"user_id": 123,
"timestamp": "2024-01-15T10:30:00Z"
}{
"error": "Logout failed",
"details": "Session termination error"
}Request OTP
Generate OTP for Verification
Generate One-Time Password for user verification. OTP expires in 5 minutes and is sent via WhatsApp in production mode. Returns OTP in response for development/mock mode.
Parameters
user_idnumberrequiredUser ID to generate OTP for
Request Body
{
"user_id": 123
}Response
{
"message": "OTP berhasil dikirim.",
"otp": "123456"
}{
"error": "user_id harus disertakan dan berupa angka."
}{
"error": "User tidak ditemukan."
}{
"error": "Gagal generate OTP.",
"details": "Database connection error"
}PSP Update
PSP/KYC Status Update
Update user KYC status and information from PSP providers. Automatically activates user account when KYC is approved and includes activity logging.
Parameters
user_idnumberrequiredUser ID to update
ekyc_statusstringrequiredKYC verification status (PENDING, APPROVED, REJECTED)
ekyc_verified_atstringrequiredKYC verification timestamp (ISO 8601)
country_codestringrequiredCountry code for compliance
Request Body
{
"user_id": 123,
"ekyc_status": "APPROVED",
"ekyc_verified_at": "2024-01-15T10:30:00Z",
"country_code": "ID"
}Response
{
"message": "User eKYC status updated successfully"
}{
"error": "user_id, ekyc_status, ekyc_verified_at, and country_code are required."
}{
"error": "Failed to update user",
"details": "Database connection error"
}🚀 Complete User Management Workflows
Workflow 1: Secure Profile Update
// Complete secure profile update workflow
async function secureProfileUpdate(userId, profileData, currentPassword) {
console.log('Starting secure profile update...');
// Step 1: Request OTP for verification
const otpRequest = await fetch('/api/users/request-otp', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ user_id: userId })
});
console.log('OTP sent for verification');
// Step 2: Get OTP from user (implementation depends on your UI)
const otpCode = await getUserOTPInput(); // Your implementation
// Step 3: Update profile with verification
const updateResult = await fetch(`/api/users/update_profile/${userId}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${userToken}`
},
body: JSON.stringify({
...profileData,
current_password: currentPassword,
otp_code: otpCode
})
});
console.log('Profile updated successfully');
return updateResult.json();
}
Workflow 2: Account Verification Flow
// Complete account verification workflow
async function verifyUserAccount(confirmationToken) {
console.log('Processing account verification...');
// Direct GET request to confirmation endpoint
// This will return HTML response for user display
const response = await fetch(`/api/users/confirm/${confirmationToken}`, {
method: 'GET'
});
if (response.ok) {
console.log('Account verified successfully');
// Redirect user to login page
window.location.href = `${process.env.FRONTEND_URL}/login`;
} else {
console.log('Verification failed');
// Handle verification failure
}
return response;
}
Workflow 3: TOS Compliance Management
// Complete TOS compliance workflow
async function manageTOSCompliance(userId) {
console.log('Managing TOS compliance...');
// Step 1: Generate TOS acceptance link
const linkResponse = await fetch(`/api/users/${userId}/tos-acceptance-link`, {
method: 'GET',
headers: {
'Authorization': `Bearer ${userToken}`
}
});
const linkData = await linkResponse.json();
console.log(`TOS link generated: ${linkData.link}`);
// Step 2: Send link to user (email, notification, etc.)
await sendTOSLinkToUser(linkData.link);
// Step 3: User accepts TOS (this would be called from the TOS acceptance page)
// const acceptanceResult = await fetch(`/api/users/${userId}/accept-tos`, {
// method: 'POST',
// headers: { 'Content-Type': 'application/json' },
// body: JSON.stringify({ token: tosToken })
// });
return linkData;
}
Workflow 4: KYC Status Processing
// Complete KYC status processing workflow (PSP side)
async function processKYCUpdate(userKYCData) {
console.log('Processing KYC status update...');
const { user_id, kyc_status, verification_date, country } = userKYCData;
// Step 1: Validate KYC data
if (!user_id || !kyc_status || !verification_date || !country) {
throw new Error('Missing required KYC data');
}
// Step 2: Update user KYC status
const updateResult = await fetch('/api/users/psp_update', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': pspApiKey
},
body: JSON.stringify({
user_id: user_id,
ekyc_status: kyc_status,
ekyc_verified_at: verification_date,
country_code: country
})
});
if (updateResult.ok) {
console.log(`KYC status updated for user ${user_id}: ${kyc_status}`);
// Step 3: If approved, user is automatically activated
if (kyc_status === 'APPROVED') {
console.log(`User ${user_id} automatically activated due to KYC approval`);
}
}
return updateResult.json();
}
Workflow 5: Admin User Management
// Complete admin user management workflow
async function adminUserManagement(filters = {}) {
console.log('Starting admin user management...');
// Step 1: Get all users with statistics
const usersResponse = await fetch('/api/users/users?' + new URLSearchParams(filters), {
headers: {
'Authorization': `Bearer ${adminToken}`,
'x-api-key': apiKey
}
});
const users = await usersResponse.json();
console.log(`Found ${users.length} users`);
// Step 2: Get detailed information for specific users
const detailedUsers = await Promise.all(
users.slice(0, 10).map(async (user) => {
const detailResponse = await fetch(`/api/users/${user.user_id}`, {
headers: {
'Authorization': `Bearer ${adminToken}`
}
});
return detailResponse.json();
})
);
// Step 3: Generate analytics
const analytics = {
total_users: users.length,
active_users: users.filter(u => u.user_status === 'ACTIVE').length,
kyc_approved: users.filter(u => u.ekyc_status === 'APPROVED').length,
total_volume: users.reduce((sum, u) => sum + parseFloat(u.total_volume.replace(' USD', '')), 0),
average_transactions: users.reduce((sum, u) => sum + u.transactions_count, 0) / users.length
};
console.log('User analytics:', analytics);
return {
users,
detailed_users: detailedUsers,
analytics
};
}
🎯 When to Use Which API
Profile Management
- Update profile:
PUT /users/update_profile/:user_id - View profile:
GET /users/:user_id - List users:
GET /users/users - Country setup:
GET /users/countries
Account Verification
- Email confirmation:
GET /users/confirm/:token - Account activation: Automatic via confirmation
Compliance Management
- TOS workflow:
GET /users/:user_id/tos-acceptance-link→POST /users/:user_id/accept-tos - KYC updates:
POST /users/psp_update
Security Operations
- Profile security:
POST /users/request-otp→PUT /users/update_profile/:user_id - Session management:
POST /users/logout
💡 Pro Tips for User Management
Security Best Practices
// Always validate current password for profile updates
const validateProfileUpdate = async (userId, currentPassword, newData) => {
// Step 1: Verify current password
if (!currentPassword) {
throw new Error('Current password required for profile updates');
}
// Step 2: Use OTP if enabled
if (process.env.USE_OTP_CHECK === 'true') {
const otp = await requestOTP(userId);
// Wait for user OTP input
newData.otp_code = await getUserOTPInput();
}
// Step 3: Execute update with verification
return updateProfile(userId, { ...newData, current_password: currentPassword });
};
Error Handling
// Robust error handling for user operations
async function safeUserOperation(operation) {
try {
return await operation();
} catch (error) {
if (error.message.includes('Password salah')) {
return { error: 'invalid_password', suggestion: 'verify_current_password' };
} else if (error.message.includes('Invalid or expired OTP')) {
return { error: 'invalid_otp', suggestion: 'request_new_otp' };
} else if (error.message.includes('Token expired')) {
return { error: 'token_expired', suggestion: 'regenerate_link' };
} else if (error.message.includes('User tidak ditemukan')) {
return { error: 'user_not_found', suggestion: 'verify_user_id' };
} else {
console.error('Unexpected user error:', error.message);
throw error;
}
}
}
OTP Configuration
// Environment-based OTP handling
class OTPManager {
static async requestOTP(userId) {
const response = await fetch('/api/users/request-otp', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ user_id: userId })
});
const result = await response.json();
// In MOCK_MODE, OTP is returned in response
if (result.otp) {
console.log(`Development OTP: ${result.otp}`);
return result.otp;
}
// In production, OTP is sent via WhatsApp
console.log('OTP sent via WhatsApp');
return null; // User must enter OTP manually
}
static isOTPRequired() {
return process.env.USE_OTP_CHECK === 'true';
}
}
TOS Management
// TOS compliance tracking
class TOSManager {
static async generateTOSLink(userId) {
const response = await fetch(`/api/users/${userId}/tos-acceptance-link`, {
headers: { 'Authorization': `Bearer ${token}` }
});
return response.json();
}
static async acceptTOS(userId, token) {
const response = await fetch(`/api/users/${userId}/accept-tos`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ token })
});
return response.json();
}
static extractTokenFromURL(url) {
const urlParams = new URLSearchParams(new URL(url).search);
return urlParams.get('t');
}
}
🔐 Authentication & Authorization
Different endpoints require different authentication levels:
// Public endpoints (no auth required)
await fetch('/api/users/countries');
await fetch('/api/users/confirm/token123');
// User-level endpoints (JWT token required)
await fetch('/api/users/123', {
headers: { 'Authorization': `Bearer ${userToken}` }
});
// Admin-level endpoints (admin role required)
await fetch('/api/users/users', {
headers: {
'Authorization': `Bearer ${adminToken}`,
'x-api-key': apiKey
}
});
// PSP endpoints (PSP role required)
await fetch('/api/users/psp_update', {
headers: { 'x-api-key': pspApiKey }
});
🌍 Environment Configuration
Required Environment Variables
# OTP Configuration
USE_OTP_CHECK=true # Enable/disable OTP verification
MOCK_MODE=false # Development mode settings
# Frontend URLs
FRONTEND_URL=https://app.example.com # Main application URL
TOS_FRONTEND_URL=https://legal.example.com # TOS acceptance page
# Email Service
APP_URL=https://api.example.com # API base URL for email links
Feature Flags
- USE_OTP_CHECK: Controls OTP requirement for profile updates
- MOCK_MODE: Returns OTP in response for development
- Email Confirmation: Automatic email sending for account verification
- TOS Compliance: Secure token-based Terms of Service acceptance
📊 Response Format Standards
All endpoints follow consistent response formats:
Success Responses
{
"success": true,
"data": { ... },
"message": "Operation completed successfully"
}
Error Responses
{
"success": false,
"error": "Error description",
"details": "Additional error details"
}
HTML Responses (Confirmation Pages)
Account confirmation endpoints return formatted HTML for user-friendly display in browsers.
Always require current password verification for profile updates. Use OTP verification in production environments for additional security. Activity logging tracks all profile changes for audit purposes.
Email confirmation tokens and TOS acceptance tokens expire after 24 hours. Implement proper error handling for expired tokens and provide regeneration options for users.
PSP updates automatically activate user accounts when KYC status is APPROVED. This triggers wallet currency updates and removes user restrictions based on verification status.