Loading, resume, session and generic errors
The step loads GET /v1/security/methods and GET /v1/security/verify/status in parallel before rendering anything interactive. Neither response is cached across the step, because status can change in another tab.
- Account (completed)
- Phone (current step)
- Email (not started)
- Account (completed)
- Phone (current step)
- Email (not started)
loading · methods + status in flight
Skeleton in the same layout as enter-phone, so nothing shifts. No Skip until policy is known: under required, Skip mustn't flash in and then disappear.
- Account (completed)
- Phone (current step)
- Email (not started)
already-verified · status.phoneVerified
For example, the user verified in another tab. Short notice, then an automatic redirect via nextAfterPhone() (check-inbox, or the app if email is off or already confirmed). It never asks again.
- Account (completed)
- Phone (completed)
- Email (current step)
Your phone is already verified. Taking you to the next step…
resumed · status.phonePending (Δ)
After a reload, the step resumes at enter-code with the cooldown and expiry restored from the server. The client has only phonePending.maskedPhone, never the full number. That's enough: confirm sends { code }, and Resend calls POST /verify/phone/resend with an empty body (Δ), which targets the server-held pending number. Change number goes back to an empty enter-phone.
- Account (completed)
- Phone (current step)
- Email (not started)
Enter your code
Enter the 6-digit code we sent to
+44 •••• •• 0123
sms-off-preflight · methods.verification.sms = false
The transport isn't configured (no SMS_SERVICE_URL), so the step is skipped via nextAfterPhone() before anything is shown. This frame documents the transient redirect. In practice the router skips the route.
- Account (completed)
- Phone · later (skipped, you can add it later)
- Email (current step)
Text verification isn't set up in this environment, so this step isn't shown. Continuing…
error-session · 401 NO_TOKEN / session expired
Only for a real session failure (once Δ separates it from code errors). Sign-in returns to the whole current location, nested and encoded, so the original target survives: /login?next=%2Fsignup%2Fphone%3Fnext%3D%252Fapps%252Fplan → /signup/phone?next=/apps/plan → /apps/plan. Because the sign-in target already points at this flow, the required-policy re-prompt doesn't wrap it again (see 01, no loop).
- Account (completed)
- Phone (current step)
- Email (not started)
Please sign in again
Your session ended before we could finish. Your account is already created — sign in and we'll bring you back here.
error-generic · network / 5xx (optional)
Unknown failure: Try again, or Skip. Raw server messages are never shown.
- Account (completed)
- Phone (current step)
- Email (not started)
Something went wrong
We couldn't reach the server. Check your connection and try again.
error-generic · network / 5xx (required)
Under required, a network error or unclassified 5xx is not retry-only: Continue for now (continue-without-phone) defers exactly like 503 and lockout, and the sign-in redirect re-prompts later.
- Account (completed)
- Phone (current step)
- Email (not started)
Something went wrong
We couldn't reach the server. Check your connection and try again. Or continue now, and we'll ask you to verify your phone next time you sign in.