The system supports different authentication types based on the authentication method used during registration:
| Code | Name | Description | Set During |
|---|---|---|---|
| EMAI | 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:
/api/users
List all users (requires authentication)
Headers:
Authorization: Bearer ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr...
Query Parameters:
sort - JSON array with field name and direction
["fieldName","ASC|DESC"]
id, username, email, firstName, lastName, createdAt, updatedAt, verifiedAt, typeName, authTypeName, isActive, userTypeCode, authTypeCode, lastLoginAt
sort=["username","ASC"] - Sort by username in ascending order
page - Page number (1-based)
page=1 - Get the first page
perPage - Number of items per page
perPage=10 - Show 10 items per page
filter - JSON object with field name/value pairs for filtering
{"fieldName1":"value1","fieldName2":value2}
filter={"username":"John","isActive":true} - Filter active users with username containing "John"
q - Global search across username, email, first name, last name, user type name, and authentication type nameusername - 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
"null" for unverified users
"!null" for verified users
lastLoginAt - Filter by last login
"null" for users who never logged in
"!null" for users who have logged in
legacyUserId - Filter by legacy user ID
"null" for non-legacy users
"!null" for legacy users
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)q in the filter will search across all text columns:
filter={"q":"John","isActive":true} - Find active users with "John"
in any text field
"null" to find records with NULL values or "!null" to find records with non-NULL values:
filter={"verifiedAt":"null"} - Find unverified users
filter={"lastLoginAt":"!null"} - Find users who have logged in
filter={"legacyUserId":"null"} - Find non-legacy users
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.
/api/users/full
List all users with full details including subscription and promotion information (requires admin authentication)
Headers:
Authorization: Bearer ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr...
Query Parameters:
Same as /api/users endpoint, with additional filterable fields for subscription and promotion data.
sort - JSON array with field name and directionpage - Page number (1-based)perPage - Number of items per pagefilter - JSON object with filters for user, subscription, and promotion fieldsAdditional Available Filters:
subscriptionStatus, subscriptionPlanName, subscriptionPlanAmount, subscriptionChargedAmount, stripeCustomerId, stripeSubscriptionIdpromotionName, promotionCode, couponName, couponTypeCode, discountPercentage, discountAmountshopifyPromotionName, shopifyDurationDays, shopifyPercentOff, shopifyPromotionAppliedAtAdditional Sortable Fields:
subscriptionPlanAmount - Sort by plan amount (in cents)subscriptionChargedAmount - Sort by actual amount charged after discounts (in cents)subscriptionStatus - Sort by subscription statuspromotionCode - Sort by promotion codeshopifyPromotionName - Sort by Shopify promotion nameshopifyDurationDays - Sort by Shopify promotion duration in daysshopifyPercentOff - Sort by Shopify promotion discount percentageshopifyPromotionAppliedAt - Sort by when the Shopify promotion was applieddiscountPercentage - Sort by discount percentageResponse (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",
"subscriptionExemptionStartsAt": null,
"subscriptionExemptionEndsAt": null,
"legacyUserId": null,
"lastLoginAt": "2023-06-15T14:20:00Z",
"subscriptionId": 42,
"subscriptionPlanId": 1,
"subscriptionPlanName": "Monthly",
"subscriptionPlanInterval": "month",
"subscriptionPlanAmount": 1500,
"subscriptionPlanCurrency": "usd",
"subscriptionPlanTrialPeriodDays": 14,
"subscriptionChargedAmount": 1200,
"stripeCustomerId": "cus_abc123",
"stripeSubscriptionId": "sub_xyz789",
"subscriptionStatus": "active",
"currentPeriodStart": "2023-06-01T00:00:00Z",
"currentPeriodEnd": "2023-07-01T00:00:00Z",
"pauseCollectionResumesAt": null,
"nextBillingDate": "2023-07-01T00:00:00Z",
"trialStart": "2023-01-15T08:35:00Z",
"trialEnd": "2023-01-29T08:35:00Z",
"cancelAtPeriodEnd": false,
"canceledAt": null,
"subscriptionCreatedAt": "2023-01-15T08:40:00Z",
"subscriptionUpdatedAt": "2023-06-01T00:00:00Z",
"promotionRedemptionId": 5,
"promotionId": 3,
"promotionName": "Summer Special",
"promotionCode": "SUMMER20",
"promotionDescription": "20% off for summer",
"couponId": 2,
"couponName": "Summer Discount",
"couponTypeCode": "DISC",
"couponTypeName": "Discount Percentage",
"discountPercentage": 20,
"trialDays": null,
"couponDurationTypeCode": "ONCE",
"couponDurationTypeName": "Once",
"durationInMonths": null,
"durationDays": null,
"stripeDiscountId": "di_abc123",
"promotionAppliedAt": "2023-01-15T08:40:00Z",
"shopifyPromotionId": 5561,
"shopifyPromotionName": "Shopify-99001",
"shopifyOrderId": 12,
"shopifyDurationDays": 30,
"shopifyPercentOff": null,
"shopifyPromotionAppliedAt": "2026-03-15T09:00:00Z"
}
],
"total": 42
}
Headers:
Content-Range: items 0-9/42 Accept-Range: items Access-Control-Expose-Headers: Content-Range X-Total-Count: 42
Error Responses:
{
"message": "Administrator access required"
}
Notes:
shopifyPromotion* fields contain details of the active Shopify promotion (if any). Shopify promotions affect billing timing only and are tracked separately from regular promotions. These fields are only populated while the Shopify pause period is currently active. shopifyPromotionAppliedAt is the ISO timestamp when the Shopify promotion was applied.subscriptionChargedAmount shows the actual amount the user is charged after applying any discount (in cents). If there's a 20% discount on a $15 plan, subscriptionChargedAmount would be 1200 (cents)/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:
/api/users/metrics
Gets a list of overall numbers on user data (requires authentication)
Headers:
Authorization: Bearer ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr...
Query Parameters (optional):
| Parameter | Type | Description |
|---|---|---|
startDate |
string (YYYY-MM-DD) | Start of the date range for monthly metrics. Defaults to the first day of the current month. |
endDate |
string (YYYY-MM-DD) | End of the date range for monthly metrics (exclusive). Defaults to the first day of the next month. |
Example: /api/users/metrics?startDate=2026-03-01&endDate=2026-04-01
Response (200 OK):
{
"data": [
{
"id": 0,
"monthlyCreatedUsers": 0,
"monthlyPaidUsers": 0,
"monthlyFreeUsers": 0,
"monthlyTrialUsers": 5,
"monthlyUsersWithNoSubscription": 0,
"monthlyActiveUsers": 3,
"monthlyIncompleteRegs": 0,
"monthlyIncompleteVerification": 0,
"monthlyIncompleteSubscrptions": 0,
"monthlySubscriptionIncome": 14500,
"monthlyNewMonthlySubscriptionIncome": 4500,
"monthlyNewAnnualSubscriptionIncome": 28800,
"yearlyCreatedUsers": 3,
"yearlyPaidUsers": 12,
"yearlyFreeUsers": 0,
"yearlyTrialUsers": 8,
"yearlyUsersWithNoSubscription": 0,
"yearlyActiveUsers": 10,
"yearlySubscriptionIncome": 145000,
"yearlyNewMonthlySubscriptionIncome": 54000,
"yearlyNewAnnualSubscriptionIncome": 288000,
"totalCreatedUsers": 120,
"totalPaidUsers": 45,
"totalFreeUsers": 0,
"totalTrialUsers": 15,
"totalUsersWithNoSubscription": 2,
"totalActiveUsers": 95,
"totalMonthlySubscriptionIncome": 125000,
"totalAnnualSubscriptionIncome": 720000,
"totalLegacyUsers": 1500,
"totalMigratedLegacyUsers": 1400,
"totalNonMigratedLegacyUsers": 100
}
],
"total": 1
}
Error Responses:
{
"message": "We could not collect any data on the users."
}
Notes:
startDate and endDate query parameters apply only to monthly metrics. Yearly and total metrics always use their fixed windows (current calendar year and all-time respectively)./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"]
id, userId, requestTypeCode, requestTypeName, verificationCode, createdOn, attempts, username, email, firstName, lastName, isActive
sort=["createdOn","DESC"] - Sort by creation date in descending order
page - Page number (1-based)
page=1 - Get the first page
perPage - Number of items per page
perPage=10 - Show 10 items per page
filter - JSON object with field name/value pairs for filtering
{"fieldName1":"value1","fieldName2":value2}
filter={"requestTypeCode":"RPWR"} - Filter verification requests with type code "RPWR" (password reset)
q - Global search across verification code, request type code, request type name, username, email, first name, and last namerequestTypeCode - 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)q in the filter will search across key text columns:
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:
/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:
/api/users/full/:id
Get full user details by ID including subscription and promotion information (requires admin authentication)
Headers:
Authorization: Bearer ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr...
URL Parameters:
id - User ID (integer)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",
"subscriptionExemptionStartsAt": null,
"subscriptionExemptionEndsAt": null,
"legacyUserId": null,
"lastLoginAt": "2023-06-15T14:20:00Z",
"subscriptionId": 42,
"subscriptionPlanId": 1,
"subscriptionPlanName": "Monthly",
"subscriptionPlanInterval": "month",
"subscriptionPlanAmount": 1500,
"subscriptionPlanCurrency": "usd",
"subscriptionPlanTrialPeriodDays": 14,
"subscriptionChargedAmount": 1200,
"stripeCustomerId": "cus_abc123",
"stripeSubscriptionId": "sub_xyz789",
"subscriptionStatus": "active",
"currentPeriodStart": "2023-06-01T00:00:00Z",
"currentPeriodEnd": "2023-07-01T00:00:00Z",
"pauseCollectionResumesAt": null,
"nextBillingDate": "2023-07-01T00:00:00Z",
"trialStart": "2023-01-15T08:35:00Z",
"trialEnd": "2023-01-29T08:35:00Z",
"cancelAtPeriodEnd": false,
"canceledAt": null,
"subscriptionCreatedAt": "2023-01-15T08:40:00Z",
"subscriptionUpdatedAt": "2023-06-01T00:00:00Z",
"promotionRedemptionId": 5,
"promotionId": 3,
"promotionName": "Summer Special",
"promotionCode": "SUMMER20",
"promotionDescription": "20% off for summer",
"couponId": 2,
"couponName": "Summer Discount",
"couponTypeCode": "DISC",
"couponTypeName": "Discount Percentage",
"discountPercentage": 20,
"trialDays": null,
"couponDurationTypeCode": "ONCE",
"couponDurationTypeName": "Once",
"durationInMonths": null,
"durationDays": null,
"stripeDiscountId": "di_abc123",
"promotionAppliedAt": "2023-01-15T08:40:00Z",
"shopifyPromotionId": 5561,
"shopifyPromotionName": "Shopify-99001",
"shopifyOrderId": 12,
"shopifyDurationDays": 30,
"shopifyPercentOff": null,
"shopifyPromotionAppliedAt": "2026-03-15T09:00:00Z"
}
Error Responses:
{
"message": "Administrator access required"
}
{
"message": "User not found"
}
Notes:
shopifyPromotion* fields contain details of the active Shopify promotion (if any). Shopify promotions affect billing timing only and are tracked separately from regular promotions. These fields are only populated while the Shopify pause period is currently active. shopifyPromotionAppliedAt is the ISO timestamp when the Shopify promotion was applied./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:
/api/users/me/verify-update
Verify and update current user profile with email change (requires authentication and CSRF token)
Headers:
Authorization: Bearer ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr... x-csrf-token: a8d7f9c6e5b4a3c2d1e0f9a8d7f6c5b4a3
Request Body:
{
"email": "johnsmith@example.com",
"firstName": "John",
"lastName": "Smith",
"username": "johnsmith",
"verificationCode": "123456"
}
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:
{
"error": "Invalid verification code",
"message": "The verification code is incorrect. 4 attempts remaining.",
"code": "INVALID_CODE",
"attemptsRemaining": 4
}
{
"error": "No verification request found",
"message": "No pending email update verification. Please request a new update.",
"code": "NO_VERIFICATION_REQUEST"
}
{
"error": "Too many attempts",
"message": "Maximum verification attempts exceeded. Please request a new update.",
"code": "MAX_ATTEMPTS_EXCEEDED"
}
{
"error": "Email already in use",
"message": "This email address is already associated with another account",
"code": "EMAIL_EXISTS"
}
{
"message": "User not authenticated"
}
Notes:
/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) - When email is NOT changing:
{
"id": 1,
"username": "johnsmith",
"email": "john@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
}
Response (200 OK) - When email IS changing:
{
"emailVerificationRequired": true,
"message": "Verification code sent to johnsmith@example.com. Please verify to complete the update."
}
Error Responses:
{
"message": "User not authenticated"
}
{
"message": "User not found"
}
{
"message": "Email address is already in use",
"code": "EMAIL_EXISTS"
}
{
"message": "Failed to send verification email"
}
Notes:
/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"
}
{
"message": "Email address is already in use",
"code": "EMAIL_EXISTS"
}
Notes:
/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:
/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:
/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: