verifyPinOtp method

Future<OtpVerifyResult> verifyPinOtp({
  1. required String userId,
  2. required String otpCode,
})

Verifies an OTP code for admin PIN reset via the merchant API.

On success, returns an OtpVerifyResult with a resetToken that can be used to authorize the actual PIN reset.

Implementation

Future<OtpVerifyResult> verifyPinOtp({
  required String userId,
  required String otpCode,
}) async {
  final trace = await monitoringService.createTrace(name: 'verifyPinOtp', operation: 'PIN_OTP_VERIFY');

  try {
    _ensureInitialised();
    _ensureMerchantApiConfigured();

    final response = await client.post(
      url: '$_merchantApiUrl/PinResetOtp/Verify',
      requestData: {
        'userId': userId,
        'otpValue': otpCode,
      },
      user: _user,
    );

    if (response?.statusCode == 200 && response?.data != null) {
      final data = response!.data as Map<String, dynamic>;
      return OtpVerifyResult(
        verified: data['success'] as bool? ?? true,
        resetToken: data['resetToken'] as String?,
        resetTokenExpiry: data['resetTokenExpiry'] as String?,
      );
    }

    // 400 = invalid/expired OTP
    if (response?.data != null) {
      final data = response!.data as Map<String, dynamic>;
      return OtpVerifyResult(
        verified: false,
        error: data['error'] as String? ?? UserPinsErrorCodes.otpInvalidOrExpired.message,
      );
    }

    return OtpVerifyResult(
      verified: false,
      error: UserPinsErrorCodes.otpVerifyFailed.message,
    );
  } on AuthException catch (e) {
    logger.error(this, 'AuthException verifying PIN OTP: ${e.message}', error: e);
    return OtpVerifyResult(verified: false, error: e.message);
  } catch (e, s) {
    logger.error(this, 'Error verifying PIN OTP', error: e, stackTrace: s);
    return OtpVerifyResult(
      verified: false,
      error: UserPinsErrorCodes.otpVerifyFailed.message,
    );
  } finally {
    trace.stop();
  }
}