switching clears the token & responses
No token
25

Turning on MFA with phone OTP

Multi-factor authentication

An 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.

  1. GET /v1/me/mfa/methods → review what is already enrolled
  2. POST /v1/me/mfa/phone/enroll → 202, an OTP is sent to the caller's verified phone
  3. POST /v1/me/mfa/phone/enroll/confirm → enables phone_otp; recovery codes returned ONCE if this is the first method
GET/v1/me/mfa/methodsauthList enrolled MFA methods

hasMfaEnabled 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.

Bearer token
GET https://api.kerja.team/v1/me/mfa/methods
↩︎Response 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.hasMfaEnabledbooleanalways
True when the caller has at least one confirmed MFA method (phone_otp and/or totp). The client uses it to show whether MFA is active overall and to gate enrol/disable affordances.
  • trueCaller has >=1 confirmed MFA method; show MFA-enabled state and offer disable/add-method actions.
  • falseNo confirmed MFA method; prompt the user to enrol a second factor.
data.methodsarray<object>always
List of the caller's enrolled (confirmed) MFA methods. Empty array when none are enrolled. The client iterates it to render active factors and offer the correct enrol/disable actions per method.
data.methods[].methodstringalways
The kind of second factor for this entry. Identifies which enrol/disable flow applies to the row.
  • phone_otpSMS one-time-passcode method is enrolled; offer phone-OTP disable/manage.
  • totpAuthenticator-app TOTP method is enrolled; offer TOTP disable/manage.
data.methods[].confirmedAtstring (ISO 8601 date-time)always
Timestamp when this method was confirmed/activated. The client can display when the factor was enabled.
POST/v1/me/mfa/phone/enrollauthBegin phone-OTP MFA enrolment

No 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.

Bearer token
POST https://api.kerja.team/v1/me/mfa/phone/enroll
↩︎Response 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.statusstringalways
Fixed acknowledgement that phone-OTP MFA enrollment has begun and an OTP was dispatched to the caller's verified phone. The client uses this to confirm the request was accepted, then prompts the user for the OTP code to submit to the enroll/confirm endpoint.
  • acceptedEnrollment started; an OTP (purpose=mfa) was sent to the verified phone. Proceed to POST /v1/me/mfa/phone/enroll/confirm with the received code.
POST/v1/me/mfa/phone/enroll/confirmauthConfirm phone-OTP MFA

The 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).

⛓ Needs an out-of-band value?
Request body (JSON)
ℹ︎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-band
The numeric one-time passcode (default 6 digits) that was sent by SMS to the phone the user is enrolling at POST /v1/me/mfa/phone/enroll (§3.24). The user must retrieve it from their phone's SMS and paste it here; it proves possession of the phone and activates the phone_otp method.
Bearer token
POST https://api.kerja.team/v1/me/mfa/phone/enroll/confirm
↩︎Response 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
Array of one-time recovery codes (16-hex-char strings) from the shared recovery-code pool. Returned ONLY when this phone_otp enrollment is the user's first MFA method; shown once and never again, so the client must surface them for the user to store. Absent on subsequent enrollments.