Turning on MFA with phone OTP
Multi-factor authenticationAn authenticated user turns on the phone_otp second factor — the multi-method counterpart of TOTP enrolment (scenario 26). Requires a verified phone first (scenario 29); a phone-first account already qualifies.
- GET /v1/me/mfa/methods → review what is already enrolled
- POST /v1/me/mfa/phone/enroll → 202, an OTP is sent to the caller's verified phone
- POST /v1/me/mfa/phone/enroll/confirm → enables phone_otp; recovery codes returned ONCE if this is the first method
/v1/me/mfa/methodsauthList enrolled MFA methodshasMfaEnabled is true when ≥ 1 method is confirmed; methods lists phone_otp and/or totp with their confirmedAt.
Field guide — what each value means & where it comes fromno inputs
Bodyless GET — no input fields. Requires a valid bearer access token (the gateway injects x-gateway-context from it); a missing/invalid context yields 403 forbidden.
GET https://api.kerja.team/v1/me/mfa/methodsResponse guide — what comes back & what each value means4 fields
200 OK, JSON { data } envelope (not raw). No notable headers (no no-store on this read endpoint).
data.hasMfaEnabledbooleanalwaystrue— Caller has >=1 confirmed MFA method; show MFA-enabled state and offer disable/add-method actions.false— No confirmed MFA method; prompt the user to enrol a second factor.
data.methodsarray<object>alwaysdata.methods[].methodstringalwaysphone_otp— SMS one-time-passcode method is enrolled; offer phone-OTP disable/manage.totp— Authenticator-app TOTP method is enrolled; offer TOTP disable/manage.
data.methods[].confirmedAtstring (ISO 8601 date-time)always/v1/me/mfa/phone/enrollauthBegin phone-OTP MFA enrolmentNo body — the verified phone IS the target. A verified phone is a PREREQUISITE: without one this returns 409 conflict; link one first (scenario 29).
Field guide — what each value means & where it comes fromno inputs
No request body, path, or query inputs. Authenticated call only: the gateway must inject a valid gateway context (caller identity) — the enrollment targets the caller's already-verified phone, so the user supplies nothing in the request itself.
POST https://api.kerja.team/v1/me/mfa/phone/enrollResponse guide — what comes back & what each value means1 field
202 Accepted with a JSON { data } envelope; response is no-store (Cache-Control: no-store, not cached). An OTP is sent to the caller's verified phone over SMS/WhatsApp; confirm it at POST /v1/me/mfa/phone/enroll/confirm.
data.statusstringalwaysaccepted— Enrollment started; an OTP (purpose=mfa) was sent to the verified phone. Proceed to POST /v1/me/mfa/phone/enroll/confirm with the received code.
/v1/me/mfa/phone/enroll/confirmauthConfirm phone-OTP MFAThe OTP sent to your phone. Enables the phone_otp method and returns 8 recovery codes ONCE if this is your first method — save them immediately (regenerate later via scenario 27). A user may hold BOTH phone_otp and totp; the recovery-code pool is shared, and phone_otp is the method advertised at login when both are confirmed. After enabling, every future login carries an MFA hop (scenario 12 on a known device, 13 on a new one).
Field guide — what each value means & where it comes from1 field
One body field carrying the phone OTP; also requires a live authenticated session (Bearer accessToken + gateway context, both auto-handled by the tester, not typed here).
codebodystringrequiredout-of-bandPOST https://api.kerja.team/v1/me/mfa/phone/enroll/confirmResponse guide — what comes back & what each value means1 field
200 OK, no-store (Cache-Control), { data } envelope. recoveryCodes is present only when this is the user's first MFA method; otherwise data is returned empty.
data.recoveryCodesstring[]conditional