secure-pin or passkey method, or reactivating an inactive method. The identity is always taken from the authenticated session's JWT and cross-checked against the record's identity_id — a 404 is returned if the id does not belong to the caller. Exactly one of the following transitions is applied per request, determined by the record's current status/type combined with the fields supplied in the body; any other combination returns a 400:code while the record is pending (initial enrollment) or pending-deactivation (confirming a deactivation). For email-mobile methods this is checked against the emailed one-time code; for authenticator methods it is checked against the current TOTP code. On success from pending, the record becomes active; if it is an authenticator method, a fresh set of one-time backup codes is generated and returned in backup_codes (visible only in this response). On success from pending-deactivation, the record becomes inactive. Failed attempts are rate-limited: after 5 failed attempts within a 15-minute window, further attempts return a 429 until the window elapses.attestation_response while the record is a pending passkey method. The response is verified against the registration challenge issued when the method was created (which must not have expired), and the resulting credential must not already be registered to any identity. On success the record becomes active and its WebAuthn credential is stored.current_pin and new_pin while the record is an active secure-pin method. current_pin must match the currently configured PIN (rate-limited the same way as code verification, and returns 401 on mismatch); new_pin must be exactly 6 digits and must not be a trivially guessable sequence (all one digit, or an ascending/descending run such as 123456 or 654321).security_answers (both configured questions, in any order) and new_pin, but omit current_pin, while the record is an active secure-pin method. Both security answers must match the previously configured hashes (rate-limited the same way) before the same new_pin rules from the change-PIN transition apply.status: "pending-deactivation" while the record is active. Rejected with a 403 if this would leave the identity with zero remaining active login-context methods. For email-mobile methods this immediately emails a one-time confirmation code (expires in 5 minutes) that must then be supplied via the code-verification transition above to complete deactivation; other method types move to pending-deactivation without this endpoint generating a follow-up code.status: "inactive" with security_answers (both configured questions, in any order) while the record is an active secure-pin method. Both answers must match the previously configured hashes or a 400 is returned; this path is also subject to the same 5-attempts/15-minute rate limit.status: "inactive" while the record is an active passkey method. No further verification is required beyond the last-active-login-method check (403) described above.status: "active" while the record is inactive. No additional verification is required for this transition.curl --location --request PATCH '/identity-mfas/01HXYZ1234567890ABCDEFGHIJ' \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{
"code": "482913"
}'{
"message": "Identity MFA updated successfully",
"status": "success",
"data": {
"id": "01HXYZ1234567890ABCDEFGHIJ",
"identity_id": "01HABC9876543210ZYXWVUTSRQ",
"type": "authenticator",
"status": "active",
"contexts": [
"login"
],
"system_meta": {
"email": null,
"mobile": null,
"security_questions": null,
"has_backup_codes": true,
"passkey": null
},
"backup_codes": [
"8f2a1c7d",
"3e9b6f21",
"a04d7c88",
"1b5e9a33",
"6c7f2d10",
"d9e83a56",
"f42c1b09",
"7a3d6e94",
"0e5b8c72",
"2c9f4a61"
],
"created": 1722869520000,
"updated": 1722955920000
}
}