Email Management
Flow Summary
The current email module has two flows:
Set Email Flow
Step 1. Send OTPPOST /api/v1/auth/set-email/otp
Step 2. Verify and savePOST /api/v1/auth/set-email/verification
Replace Email Flow
Step 1. Send OTP (current)POST /api/v1/auth/reset-email/current-email/otp
Step 2. Verify (current)POST /api/v1/auth/reset-email/current-email/verification
Step 3. Send OTP (new)POST /api/v1/auth/reset-email/new-email/otp
Step 4. Verify (new)POST /api/v1/auth/reset-email/new-email/verification
In development environments, OTP is currently hardcoded to 123456.
All routes below should be treated as protected routes and sent with:
Authorization: Bearer <access_token>
Set Email (For Users Without A Verified Email)
Use this when the user registered without a verified email, or has a stored email that is still unverified.
1. Send OTP
POST /api/v1/auth/set-email/otp
Request
{
"email": "user@example.com"
}
Success response
{
"status_code": 200,
"message": "OTP sent successfully",
"data": {
"set_email_session_id": "9b7f1b4d-7c75-4d14-bec8-0d03b0f809d6",
"expires_at": 300
}
}
Current rules
- If the user already has a stored email value, the submitted email must match that stored value after lowercase/trim normalization.
- If the user has no email yet, the service checks that the new email is not already used by another user.
- The OTP session is stored in Redis for 5 minutes.
- The handler reuses the email-reset OTP message key for this step.
2. Verify OTP And Save Email
POST /api/v1/auth/set-email/verification
Request
{
"set_email_session_id": "9b7f1b4d-7c75-4d14-bec8-0d03b0f809d6",
"otp_code": "123456"
}
Success response
{
"status_code": 200,
"message": "Email reset successfully",
"data": {
"success": true,
"message": "Email address set and verified successfully."
}
}
Notes
- The OTP session purpose must be
set_email. - On success, the service updates
emailand setsis_email_verified = true. - The OTP session is deleted after a successful verification.
- The handler reuses the email-reset success message key even though this is the set-email flow.
Reset Email (Replace An Existing Email)
This is a 4-step flow.
1. Send OTP To Current Email
POST /api/v1/auth/reset-email/current-email/otp
Request
{
"email": "current@example.com"
}
Success response
{
"status_code": 200,
"message": "Email reset initiated successfully",
"data": {
"current_email_session_id": "f2b4a8f8-0f5f-4a8d-9b20-8f2a1f4f34c2",
"email": "current@example.com",
"expires_at": 300
}
}
Notes
- The submitted current email must match the logged-in user’s registered email after lowercase/trim normalization.
- The OTP session is stored in Redis for 5 minutes.
- This step sends OTP through the email service, not SMS.
2. Verify Current Email OTP
POST /api/v1/auth/reset-email/current-email/verification
Request
{
"current_email_session_id": "f2b4a8f8-0f5f-4a8d-9b20-8f2a1f4f34c2",
"otp_code": "123456"
}
Success response
{
"status_code": 200,
"message": "Current email verified successfully",
"data": {
"success": true,
"message": "Current email verified successfully. You can now proceed to change email address.",
"new_email_session_id": "12dc8cb8-cdf5-4f1a-b5ec-c0fd7184bfe2"
}
}
Notes
- This consumes the OTP session from step 1.
- The service creates a
new_email_session_idthat unlocks step 3. - That intermediate reset session is stored in Redis for 10 minutes.
3. Send OTP To New Email
POST /api/v1/auth/reset-email/new-email/otp
Request
{
"new_email": "new@example.com",
"new_email_session_id": "12dc8cb8-cdf5-4f1a-b5ec-c0fd7184bfe2"
}
Success response
{
"status_code": 200,
"message": "OTP sent successfully",
"data": {
"new_email_session_id": "12dc8cb8-cdf5-4f1a-b5ec-c0fd7184bfe2",
"expires_at": 300
}
}
Notes
- The
new_email_session_idmust come from step 2 and must belong to the current user. - The new email must not already exist.
- The OTP for the new email uses the same
new_email_session_idvalue as the OTP session UUID. - Resending is limited to once per minute for the same
new_email_session_id. When blocked, the response includesretry_after. - This step sends OTP through the email service.
4. Verify New Email OTP And Update
POST /api/v1/auth/reset-email/new-email/verification
Request
{
"new_email_session_id": "12dc8cb8-cdf5-4f1a-b5ec-c0fd7184bfe2",
"otp_code": "123456"
}
Success response
{
"status_code": 200,
"message": "Email reset successfully",
"data": {
"success": true,
"message": "Email address updated successfully."
}
}
Notes
- The OTP session purpose must be
reset_email. - If the user has a
cardholder_id, the service updates the cardholder email on UQPay before saving the local email. - The service updates
emailin the local database, then deletes the OTP session.
Common Failure Cases
400: invalid email format, invalid OTP, expired session, or wrong session purpose403: resend requested too quickly, or reset session does not belong to the current user404: user not found409: new email already exists
Integration Notes
- Use
set-emailonly for users who still need to verify or attach an email. - Use
reset-emailwhen replacing an already registered email. - The OTP steps here are route-specific and do not use
/connect/token.