User Management Endpoints Index

User Authentication Types

The system supports different authentication types based on the authentication method used during registration:

Code Name Description Set During
EMAI Email Traditional email/password authentication POST /api/auth/register
GOOG Google OAuth Google Sign-In authentication POST /api/auth/google/register
APPE Apple OAuth Apple Sign-In authentication (future) Future implementation
FACE Facebook OAuth Facebook authentication (future) Future implementation
XXXX X OAuth X (formerly Twitter) authentication (future) Future implementation
LINK LinkedIn OAuth LinkedIn authentication (future) Future implementation

Important Notes:

User Endpoints

GET /api/users

List all users (requires authentication)

Headers:

Authorization: Bearer ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr...

Query Parameters:

  • sort - JSON array with field name and direction ["fieldName","ASC|DESC"]
    Available sort fields: id, username, email, firstName, lastName, createdAt, updatedAt, verifiedAt, typeName, authTypeName, isActive, userTypeCode, authTypeCode, lastLoginAt
    Example: sort=["username","ASC"] - Sort by username in ascending order
  • page - Page number (1-based)
    Example: page=1 - Get the first page
  • perPage - Number of items per page
    Example: perPage=10 - Show 10 items per page
  • filter - JSON object with field name/value pairs for filtering {"fieldName1":"value1","fieldName2":value2}
    Example: filter={"username":"John","isActive":true} - Filter active users with username containing "John"

    Available filters:
    • q - Global search across username, email, first name, last name, user type name, and authentication type name
    • username - Filter by username (partial match, case-insensitive)
    • email - Filter by email address (partial match, case-insensitive)
    • firstName - Filter by first name (partial match, case-insensitive)
    • lastName - Filter by last name (partial match, case-insensitive)
    • isActive - Filter by active status (true/false)
    • userTypeCode - Filter by user type code (SUBS, NONS, ADMI)
    • typeName - Filter by user type name (partial match, case-insensitive)
    • authTypeCode - Filter by authentication type (EMAI, GOOG, APPE, FACE, XXXX, LINK)
    • authTypeName - Filter by authentication type name (partial match, case-insensitive)
    • verifiedAt - Filter by verification status
      Use "null" for unverified users
      Use "!null" for verified users
      Use a date string for specific date matching
    • lastLoginAt - Filter by last login
      Use "null" for users who never logged in
      Use "!null" for users who have logged in
      Use a date string for specific date matching
    • legacyUserId - Filter by legacy user ID
      Use "null" for non-legacy users
      Use "!null" for legacy users
      Use a number for specific legacy user ID
    • subscriptionExemptionStartsAt - Filter by subscription exemption start date (exact date or date range, or "null"/"!null")
    • subscriptionExemptionEndsAt - Filter by subscription exemption end date (exact date or date range, or "null"/"!null")
    • createdAt - Filter by creation date (exact date or date range)
    • updatedAt - Filter by last update date (exact date or date range)


    Special filter: Global Search
    Using the key q in the filter will search across all text columns:
    Example: filter={"q":"John","isActive":true} - Find active users with "John" in any text field

    Special filter: NULL/NOT NULL Values
    For nullable fields, use "null" to find records with NULL values or "!null" to find records with non-NULL values:
    Example: filter={"verifiedAt":"null"} - Find unverified users
    Example: filter={"lastLoginAt":"!null"} - Find users who have logged in
    Example: filter={"legacyUserId":"null"} - Find non-legacy users
    Example: filter={"legacyUserId":"!null"} - Find legacy users

Example Requests:

GET /api/users?page=1&perPage=10&sort=["username","ASC"]&filter={"userTypeCode":"SUBS"}
GET /api/users?page=2&perPage=20&filter={"q":"John","isActive":true}
GET /api/users?filter={"email":"gmail.com","verifiedAt":"null"}
GET /api/users?filter={"verifiedAt":"!null","isActive":true}
GET /api/users?filter={"lastLoginAt":"null"}
GET /api/users?filter={"lastLoginAt":"!null","userTypeCode":"SUBS"}
GET /api/users?filter={"legacyUserId":"null"}
GET /api/users?filter={"legacyUserId":"!null","isActive":true}
GET /api/users?filter={"typeName":"Subscribed","isActive":true}
GET /api/users?filter={"authTypeCode":"GOOG","isActive":true}
GET /api/users?filter={"authTypeName":"Google OAuth","isActive":true}
GET /api/users?sort=["authTypeName","ASC"]&filter={"isActive":true}

Response (200 OK):

{
    "data": [
        {
            "id": 1,
            "username": "John Doe",
            "email": "john@example.com",
            "typeCode": "SUBS",
            "typeName": "Subscribed",
            "firstName": "John",
            "lastName": "Doe",
            "authTypeCode": "EMAI",
            "authTypeName": "Email",
            "isActive": true,
            "createdAt": "2023-01-15T08:30:00Z",
            "updatedAt": "2023-01-15T08:30:00Z",
            "verifiedAt": "2023-01-15T08:35:00Z",
            "lastLoginAt": "2023-06-15T14:20:00Z",
            "subscriptionExemptionStartsAt": null,
            "subscriptionExemptionEndsAt": null,
            "legacyUserId": null
        },
        {
            "id": 2,
            "username": "Jane Smith",
            "email": "jane@gmail.com",
            "typeCode": "SUBS",
            "typeName": "Subscribed",
            "firstName": "Jane",
            "lastName": "Smith",
            "authTypeCode": "GOOG",
            "authTypeName": "Google OAuth",
            "isActive": true,
            "createdAt": "2023-02-20T10:15:00Z",
            "updatedAt": "2023-02-20T10:15:00Z",
            "verifiedAt": "2023-02-20T10:20:00Z",
            "lastLoginAt": "2023-06-14T09:30:00Z",
            "subscriptionExemptionStartsAt": null,
            "subscriptionExemptionEndsAt": null,
            "legacyUserId": 42
        }
    ],
    "total": 42
}

Headers:

Content-Range: items 0-9/42
Accept-Range: items
Access-Control-Expose-Headers: Content-Range
X-Total-Count: 42

Note: The Content-Range header indicates the range of items returned and the total count.

GET /api/users/me

Get current user profile (requires authentication)

Headers:

Authorization: Bearer ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr...

Response (200 OK):

{
    "id": 1,
    "username": "John Doe",
    "email": "john@example.com",
    "typeCode": "SUBS",
    "typeName": "Subscribed",
    "firstName": "John",
    "lastName": "Doe",
    "authTypeCode": "EMAI",
    "authTypeName": "Email",
    "isActive": true,
    "createdAt": "2023-01-15T08:30:00Z",
    "updatedAt": "2023-01-15T08:30:00Z",
    "verifiedAt": "2023-01-15T08:35:00Z",
    "lastLoginAt": "2023-06-15T14:20:00Z",
    "subscriptionExemptionStartsAt": null,
    "subscriptionExemptionEndsAt": null,
    "legacyUserId": null
}

Error Responses:

{
    "message": "User not authenticated"
}

Notes:

  • Does not require CSRF token as it's a GET request (only mutation methods require CSRF)
GET /api/users/metrics

Gets a list of overall numbers on user data (requires authentication)

Headers:

Authorization: Bearer ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr...

Response (200 OK):

{
    "data": [
        {
            "id": 0,
            "totalFreeUsers": 0,
            "totalYearlyFreeUsers": 0,
            "totalYearlyCreatedUsers": 3,
            "monthlyIncompleteRegs": 0,
            "totalMonthlyFreeUsers": 0,
            "totalMonthlyExpiredUsers": 3,
            "totalMonthlyCreatedUsers": 0,
            "totalUserswithNoSubscription": 2,
            "totalLegacyUsers": 1500,
            "totalMigratedLegacyUsers": 1400,
            "totalNonMigratedLegacyUsers": 100
        }
    ],
    "total": 1
}

Error Responses:

{
    "message": "We could not collect any data on the users."
}

Notes:

  • This endpoint gets total numbers for different user metrics for the dashboard
  • Does not require CSRF token as it's a GET request (only mutation methods require CSRF)
  • Returns metrics including:
    • totalFreeUsers - Total active users with NONS user type or SUBS type with 100% discount promotion
    • totalYearlyFreeUsers - Same as totalFreeUsers but created in current year
    • totalYearlyCreatedUsers - Total active users created in current year
    • monthlyIncompleteRegs - Active users created in current month with no verified_at date
    • totalMonthlyFreeUsers - Same as totalFreeUsers but created in current month
    • totalMonthlyExpiredUsers - Active users whose subscription expired in current month
    • totalMonthlyCreatedUsers - Total active users created in current month
    • totalUserswithNoSubscription - Active users with NONS type, expired subscription, or no subscription
    • totalLegacyUsers - Total active users with legacy accounts
    • totalMigratedLegacyUsers - Total active users with legacy accounts who have migrated to the new system
    • totalNonMigratedLegacyUsers - Total active users with legacy accounts who have not migrated to the new system
GET /api/users/verification-requests

List all user verification requests with filtering, sorting, and pagination (requires authentication)

Headers:

Authorization: Bearer ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr...

Query Parameters:

  • sort - JSON array with field name and direction ["fieldName","ASC|DESC"]
    Available sort fields: id, userId, requestTypeCode, requestTypeName, verificationCode, createdOn, attempts, username, email, firstName, lastName, isActive
    Example: sort=["createdOn","DESC"] - Sort by creation date in descending order
  • page - Page number (1-based)
    Example: page=1 - Get the first page
  • perPage - Number of items per page
    Example: perPage=10 - Show 10 items per page
  • filter - JSON object with field name/value pairs for filtering {"fieldName1":"value1","fieldName2":value2}
    Example: filter={"requestTypeCode":"RPWR"} - Filter verification requests with type code "RPWR" (password reset)

    Available filters:
    • q - Global search across verification code, request type code, request type name, username, email, first name, and last name
    • requestTypeCode - Filter by request type code (REGR for registration, RPWR for password reset)
    • requestTypeName - Filter by request type name (partial match, case-insensitive)
    • verificationCode - Filter by verification code (partial match, case-insensitive)
    • username - Filter by username (partial match, case-insensitive)
    • email - Filter by email address (partial match, case-insensitive)
    • firstName - Filter by first name (partial match, case-insensitive)
    • lastName - Filter by last name (partial match, case-insensitive)
    • isActive - Filter by user active status (true/false)
    • userId - Filter by specific user ID (exact match)
    • attempts - Filter by number of verification attempts (exact match)
    • createdOn - Filter by creation date (exact date or date range)


    Special filter: Global Search
    Using the key q in the filter will search across key text columns:
    Example: filter={"q":"reset"} - Find verification requests with "reset" in any searchable field (verificationCode, requestTypeCode, requestTypeName, username, email, firstName, lastName)

Example Requests:

GET /api/users/verification-requests?page=1&perPage=10&sort=["createdOn","DESC"]&filter={"requestTypeCode":"RPWR"}
GET /api/users/verification-requests?page=1&perPage=20&filter={"q":"john","isActive":true}
GET /api/users/verification-requests?filter={"requestTypeName":"Password","username":"smith"}
GET /api/users/verification-requests?filter={"userId":42,"attempts":0}

Response (200 OK):

{
    "data": [
        {
            "id": 1,
            "userId": 42,
            "requestTypeCode": "RPWR",
            "requestTypeName": "Reset Password",
            "verificationCode": "abc123def456", 
            "createdOn": "2023-06-15T14:30:00Z",
            "attempts": 0,
            "username": "johndoe",
            "email": "john@example.com",
            "firstName": "John",
            "lastName": "Doe",
            "isActive": true
        },
        {
            "id": 2,
            "userId": 37,
            "requestTypeCode": "REGR",
            "requestTypeName": "Email Verification",
            "verificationCode": "xyz789uvw456",
            "createdOn": "2023-06-14T10:15:00Z",
            "attempts": 1,
            "username": "janesmith",
            "email": "jane@example.com",
            "firstName": "Jane",
            "lastName": "Smith",
            "isActive": true
        }
    ],
    "total": 42
}

Headers:

Content-Range: items 0-9/42
Accept-Range: items
Access-Control-Expose-Headers: Content-Range
X-Total-Count: 42

Note: This endpoint includes verification codes and user details along with verification request information for improved usability and administration.

Notes:

  • Does not require CSRF token as it's a GET request (only mutation methods require CSRF)
GET /api/users/:id

Get a specific user by ID (requires authentication)

Headers:

Authorization: Bearer ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr...

Response (200 OK):

{
    "id": 2,
    "username": "Jane Doe",
    "email": "jane@example.com",
    "typeCode": "SUBS",
    "typeName": "Subscribed",
    "firstName": "Jane",
    "lastName": "Doe",
    "authTypeCode": "GOOG",
    "authTypeName": "Google OAuth",
    "isActive": true,
    "createdAt": "2023-02-20T10:15:00Z",
    "updatedAt": "2023-02-20T10:15:00Z",
    "verifiedAt": "2023-02-20T10:20:00Z",
    "lastLoginAt": "2023-06-14T09:30:00Z",
    "subscriptionExemptionStartsAt": null,
    "subscriptionExemptionEndsAt": null,
    "legacyUserId": null
}

Error Responses:

{
    "message": "User not found"
}

{
    "message": "User not authenticated"
}

Notes:

  • Does not require CSRF token as it's a GET request (only mutation methods require CSRF)
POST /api/users/verification-requests/resend-email

Resends verification email to selected users (requires authentication and CSRF token)

Headers:

Authorization: Bearer ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr...
x-csrf-token: a8d7f9c6e5b4a3c2d1e0f9a8d7f6c5b4a3

Request Body:

{
    "emails": ["john@example.com", "jane@example.com"]  // Array of email addresses
}

Response (200 OK):

{
    "code": 200,
    "message": "Successfully sent verification codes."
}

Error Responses:

{
    "message": "One or more users not found."
}

Notes:

  • This endpoint resends existing verification codes to the users with the specified email addresses
  • It will locate the appropriate verification request (registration or password reset) and resend it
  • This is useful when users report they haven't received their verification email
  • The system will send verification emails appropriate to the existing request type
  • Requires CSRF token as it's a POST request that triggers email sending
PUT /api/users/me

Update current user profile (requires authentication and CSRF token)

Headers:

Authorization: Bearer ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr...
x-csrf-token: a8d7f9c6e5b4a3c2d1e0f9a8d7f6c5b4a3

Request Body:

{
    "username": "johnsmith",
    "email": "johnsmith@example.com",
    "firstName": "John",
    "lastName": "Smith"
}

Response (200 OK):

{
    "id": 1,
    "username": "johnsmith",
    "email": "johnsmith@example.com",
    "typeCode": "SUBS",
    "typeName": "Subscribed",
    "firstName": "John",
    "lastName": "Smith",
    "isActive": true,
    "createdAt": "2023-01-15T08:30:00Z",
    "updatedAt": "2023-06-10T14:20:00Z",
    "verifiedAt": "2023-01-15T08:35:00Z",
    "subscriptionExemptionStartsAt": null,
    "subscriptionExemptionEndsAt": null,
    "legacyUserId": null
}

Error Responses:

{
    "message": "User not authenticated"
}

{
    "message": "User not found"
}

Notes:

  • All fields in the request body are optional for partial updates
  • The system automatically updates the corresponding Stripe customer if one exists
  • Requires CSRF token as it's a PUT request that modifies user data
PUT /api/users/:id

Update any user by ID (requires admin authentication and CSRF token)

Headers:

Authorization: Bearer ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr...
x-csrf-token: a8d7f9c6e5b4a3c2d1e0f9a8d7f6c5b4a3

Request Body:

{
    "username": "johnsmith",
    "email": "johnsmith@example.com",
    "firstName": "John",
    "lastName": "Smith",
    "userTypeCode": "SUBS",
    "isActive": true,
    "subscriptionExemptionStartsAt": "2024-01-01T00:00:00Z",
    "subscriptionExemptionEndsAt": "2024-12-31T23:59:59Z"
}

Response (200 OK):

{
    "id": 2,
    "username": "johnsmith",
    "email": "johnsmith@example.com",
    "typeCode": "SUBS",
    "typeName": "Subscribed",
    "firstName": "John",
    "lastName": "Smith",
    "isActive": true,
    "createdAt": "2023-01-15T08:30:00Z",
    "updatedAt": "2023-06-10T14:20:00Z",
    "verifiedAt": "2023-01-15T08:35:00Z",
    "subscriptionExemptionStartsAt": "2024-01-01T00:00:00Z",
    "subscriptionExemptionEndsAt": "2024-12-31T23:59:59Z",
    "legacyUserId": null
}

Error Responses:

{
    "message": "User not authenticated"
}

{
    "message": "User not found"
}

Notes:

  • This endpoint is restricted to admin users only
  • All fields in the request body are optional for partial updates
  • Admin can update userTypeCode (SUBS, NONS) and isActive status
  • The system automatically updates the corresponding Stripe customer if one exists
  • Requires CSRF token as it's a PUT request that modifies user data
PUT /api/users/verification-requests/new-request-code

Update verification requests with a new code (requires authentication and CSRF token)

Headers:

Authorization: Bearer ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr...
x-csrf-token: a8d7f9c6e5b4a3c2d1e0f9a8d7f6c5b4a3

Request Body:

{  
    "userReqList":[
        {
            "userId": 3,
            "request_type_code": "REGR"  // "REGR" for registration, "RPWR" for password reset
        },
        {
            "userId": 5,
            "request_type_code": "RPWR"
        }
    ]
}

Response (200 OK):

{
    "code": 200,
    "message": "Successfully created new verification requests.",
    "verificationCodes": [
        {
            "userId": 3,
            "verificationCode": "abc123def456",
            "requestType": "REGR"
        },
        {
            "userId": 5,
            "verificationCode": "xyz789uvw012",
            "requestType": "RPWR"
        }
    ]
}

Error Responses:

{
    "message": "One or more users not found."
}

Notes:

  • This endpoint generates new verification codes and sends them via email to the specified users
  • The request body should contain an array of user_id and request_type_code pairs
  • Valid request_type_code values are "REGR" (registration) and "RPWR" (password reset)
  • The system will send verification emails appropriate to the request type
  • Requires CSRF token as it's a PUT request that modifies data and triggers email sending
DELETE /api/users/:id

Delete a user by ID (requires authentication and CSRF token)

Headers:

Authorization: Bearer ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr...
x-csrf-token: a8d7f9c6e5b4a3c2d1e0f9a8d7f6c5b4a3

Response: 204 No Content

Error Responses:

{
    "message": "User not found"
}

{
    "message": "User not authenticated"
}

Notes:

  • This is a permanent deletion operation and cannot be undone
  • Requires CSRF token as it's a DELETE request that permanently removes data
DELETE /api/users/verification-requests/:id

Delete a verification request by ID (requires admin authentication and CSRF token)

Headers:

Authorization: Bearer ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr...
x-csrf-token: a8d7f9c6e5b4a3c2d1e0f9a8d7f6c5b4a3

Response: 204 No Content

Error Responses:

{
    "message": "Verification request not found"
}

{
    "message": "User not authenticated"
}

{
    "message": "Administrator access required"
}

Notes:

  • This endpoint is restricted to admin users only
  • This is a permanent deletion operation and cannot be undone
  • Deleting a verification request will prevent users from completing registration or password reset flows
  • Requires CSRF token as it's a DELETE request that permanently removes data
  • Recommended for admin use only to clean up orphaned or expired verification requests