Appearance
Forgot password flow
Branches on whether the entered email belongs to a registered user. Three calls in sequence — request the OTP, confirm the OTP, then set the new password — all brand-authenticated, since the user has no session yet.
Play the flow
Both branches — the address is registered, or it is not. Press Play to watch either one; the steps name the three calls that chain through the app.
4:4713
batch
log in for full access
don't have an account?
sign up
sam@example.com
password
forgot password?
Space plays and pauses, ← and → step. Screens marked not designed yet are ones the documented flow requires but that have no design — they are drawn from the steps, not invented.
Stages
API calls by stage
| Stage | Action | API call | Auth |
|---|---|---|---|
| 1–2 | Page loads, email typed | No call | — |
| 3 | Tap Reset Password | POST /api/v1/mobile/resetPassword — payload takes exactly one of email / phoneNumber (xor), and phone_prefix is required with a phone number | Brand |
| 3a | "Email not registered" | Same call. The branch is not a separate endpoint — it is success: false on the response body, at HTTP 200 | Brand |
| 4–5 | Submit the OTP | POST /api/v1/mobile/resetPassword/confirm — otp plus exactly one of email / phoneNumber. Returns { message, token }; that token is the passwordToken for stages 6–7 | Brand |
| 6–7 | New password + Confirm | POST /api/v1/mobile/changePassword/:passwordToken — payload.password (min 8) | Brand |
| 8 | Success | No call. changePassword is not documented as returning a session, so a landing on the home page needs POST /api/v1/mobile/login afterwards | Brand |
The whole reset happens in-app
resetPassword/confirm returns { message, token }, and that token is what goes in changePassword/:passwordToken. No email link, no deep link, no universal-link handling — the three calls chain through the app.
One caution: the token is a full customer JWT, signed with the same config as a login token. Use it as the path parameter and discard it. Storing it would "sign in" someone who never proved a password.
The single-identifier rule
resetPassword uses Joi's xor, so sending both email and phoneNumber fails just as surely as sending neither. If the design ever offers "reset by email or SMS" on one screen, the client must send only the chosen one.
Paths
Email not registered Login Page → More login options → Email & Password Login Page → Forgot password → Forgot Password Page → enter email → Reset Password button → user not found → "Email not registered" popup
Email registered Login Page → More login options → Email & Password Login Page → Forgot password → Forgot Password Page → enter email → Reset Password button → user found → OTP popup → enter OTP → new password + re-enter password → Confirm → Success
Open questions
- After the "email not registered" popup — does it return to the form, or offer a link to Signup?
- Where does Success land? Back to the login page, or straight into the home page with a session? If it is the home page, the app has to log in again (see stage 8).
- OTP wrong / expired handling and resend not defined.
resetPasswordcan be called again to reissue; no retry limit is documented. - Revealing whether an email is registered is a user-enumeration signal. Common alternative is a neutral "if this email exists, we've sent a code" message. Worth a deliberate decision rather than a default — and note the decision is server-side: the popup exists because the endpoint distinguishes the two cases in its response.
- New password vs re-entered password mismatch: no path defined. Client-side only —
changePasswordtakes onepassword.