Skip to main content
NetPOS enables merchants to accept payments through bank transfers by generating virtual account numbers for customers. This payment method is ideal for customers who prefer direct bank transfers over card payments.

Overview

Pay-by-Transfer allows merchants to display virtual account details that customers can transfer money to from their mobile banking apps or internet banking platforms.
Virtual account numbers are uniquely generated for each merchant and can be used for multiple transactions.

Payment Flow

1

Retrieve Merchant Details

System fetches the merchant’s virtual account details from the payment gateway
2

Display Account Information

Show bank name, account number, and account name in a bottom sheet dialog
3

Customer Transfers

Customer initiates a bank transfer to the displayed account using their banking app
4

Payment Confirmation

Transaction is automatically confirmed and recorded in the merchant’s account

Implementation

PayByTransferBottomSheetDialogFragment

This fragment displays the virtual account details to the merchant:
PayByTransferBottomSheetDialogFragment.kt
@Singleton
@AndroidEntryPoint
class PayByTransferBottomSheetDialogFragment @Inject constructor() : 
    BottomSheetDialogFragment() {
    
    private lateinit var binding: LayoutPayWithTransferBinding
    private lateinit var bankNameTv: TextView
    private lateinit var accountNumTv: TextView
    private lateinit var accountNameTv: TextView
    private lateinit var buttonDone: Button
    
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        binding = DataBindingUtil.inflate(
            inflater, 
            R.layout.layout_pay_with_transfer, 
            container, 
            false
        )
        return binding.root
    }
    
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        init()
    }
    
    override fun onResume() {
        super.onResume()
        buttonDone.setOnClickListener {
            dismiss()
        }
    }
    
    private fun init() {
        with(binding) {
            bankNameTv = bank
            accountNameTv = accountName
            accountNumTv = accountNumber
            buttonDone = btnDone
        }
    }
}

PayByTransferService

The service interface for retrieving merchant virtual account details:
PayByTransferService.kt
interface PayByTransferService {
    @GET("getUserAccount/{NetpluspayMid}")
    fun getMerchantDetails(
        @Header("Authorization") token: String,
        @Path("NetpluspayMid") partnerId: String
    ): Single<Response<MerchantDetailsResponse>>
}

API Endpoint

GET /getUserAccount/{NetpluspayMid}

Response Model

The merchant details response contains the virtual account information:
MerchantDetailsResponse.kt
data class MerchantDetailsResponse(
    val user: MerchantDetail
)

data class MerchantDetail(
    val acctNumber: String,      // Virtual account number
    val bank: String,             // Bank name
    val businessName: String,     // Merchant business name
    val merchantId: String,       // Merchant ID
    val partnerId: String,        // Partner ID
    val terminalId: String        // Terminal ID
)

Response Example

{
  "user": {
    "acctNumber": "1234567890",
    "bank": "Providus Bank",
    "businessName": "ABC Store",
    "merchantId": "MID12345",
    "partnerId": "PID67890",
    "terminalId": "TID54321"
  }
}

Account Information Display

The bottom sheet dialog displays the following information:
FieldDescriptionSource
Bank NameName of the bank holding the virtual accountuser.bank
Account NumberVirtual account number for transfersuser.acctNumber
Account NameBusiness name registered for the accountuser.businessName

Usage Flow

1. Initiate Pay-by-Transfer

Merchant selects the Pay-by-Transfer option from the payment methods menu.

2. Fetch Account Details

The app retrieves the merchant’s virtual account details:
val token = "Bearer ${authToken}"
val netplusPayMid = user.netplusPayMid

payByTransferService.getMerchantDetails(token, netplusPayMid)
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe { response, error ->
        response?.let {
            if (it.isSuccessful) {
                val merchantDetails = it.body()?.user
                displayAccountDetails(merchantDetails)
            }
        }
        error?.let {
            showError("Failed to retrieve account details")
        }
    }

3. Display Account Information

Populate the bottom sheet dialog with account details:
fun displayAccountDetails(details: MerchantDetail?) {
    details?.let {
        binding.bank.text = it.bank
        binding.accountNumber.text = it.acctNumber
        binding.accountName.text = it.businessName
        
        bottomSheetDialog.show()
    }
}

4. Customer Transfer

The customer uses the displayed account information to initiate a bank transfer from their mobile banking app.

5. Complete Transaction

Once the customer confirms the transfer in their banking app, the merchant clicks “Done” to dismiss the dialog.
The merchant should verify that the payment has been received in their account before completing the transaction or releasing goods/services.

Account Verification

Merchants should implement proper verification workflow:
1

Display Account

Show virtual account details to customer
2

Customer Transfers

Customer completes transfer in their banking app
3

Check Balance

Merchant verifies payment receipt via banking app or account statement
4

Confirm Transaction

Merchant confirms receipt and completes the transaction

Integration Requirements

Authentication

Pay-by-Transfer requires proper authentication:
  • Authorization Token - Valid Bearer token for API authentication
  • Merchant ID - NetPlus Pay merchant identifier

User Credentials

The following merchant details must be configured:
val user = Singletons.gson.fromJson(
    Prefs.getString(PREF_USER, ""), 
    User::class.java
)
val netplusPayMid = user.netplusPayMid
val merchantId = user.merchantId
val terminalId = user.terminal_id

Error Handling

Error: 401 UnauthorizedCause: Invalid or expired authentication tokenSolution: Refresh the authentication token and retry
Error: 404 Not FoundCause: Invalid NetPlus Pay Merchant ID or merchant not registeredSolution: Verify merchant registration and credentials
Error: Connection timeout or failedCause: No internet connectivity or server unreachableSolution: Check network connection and retry

Bottom Sheet UI Components

The Pay-by-Transfer bottom sheet includes:
  • Bank Name Label - “Bank Name:”
  • Bank Name Value - Dynamic bank name
  • Account Number Label - “Account Number:”
  • Account Number Value - Dynamic 10-digit account number
  • Account Name Label - “Account Name:”
  • Account Name Value - Business name

Best Practices

Verify Receipt

Always verify payment receipt before completing the transaction

Account Display

Display account details clearly and allow customers to copy the information

Error Handling

Implement proper error handling for API failures and network issues

Session Management

Ensure authentication tokens are valid before making API calls

Transaction Records

Pay-by-Transfer transactions are automatically recorded in:
  • Local Database - Transaction history stored locally
  • Backend System - Synced with NetPOS backend for reconciliation
  • Bank Statement - Reflected in merchant’s bank account statement

Additional Features

Copy to Clipboard

Implement clipboard functionality for easy sharing:
fun copyAccountNumber(accountNumber: String) {
    val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
    val clip = ClipData.newPlainText("Account Number", accountNumber)
    clipboard.setPrimaryClip(clip)
    Toast.makeText(context, "Account number copied", Toast.LENGTH_SHORT).show()
}

Share Account Details

Allow merchants to share account information:
fun shareAccountDetails(bank: String, accountNumber: String, accountName: String) {
    val shareText = """
        Bank: $bank
        Account Number: $accountNumber
        Account Name: $accountName
    """.trimIndent()
    
    val shareIntent = Intent(Intent.ACTION_SEND).apply {
        type = "text/plain"
        putExtra(Intent.EXTRA_TEXT, shareText)
    }
    context.startActivity(Intent.createChooser(shareIntent, "Share Account Details"))
}
Virtual account numbers remain active and can be reused for multiple transactions. There’s no need to generate new account numbers for each transaction.

Payment Overview

Learn about all available payment methods

Transaction History

View and manage transaction records

Build docs developers (and LLMs) love