Skip to main content
NetPOS supports card-based payments through a web-based payment interface powered by PaySaddle. Merchants can accept card payments in multiple currencies with automatic receipt generation.

Payment Flow

1

Initiate Purchase

Navigate to the Purchase screen and enter the transaction amount
2

Select Currency

Choose the transaction currency from the supported list (NGN, USD, EUR, GBP, etc.)
3

Process Payment

The app loads a secure WebView with PaySaddle payment interface for card entry
4

Complete Transaction

Customer enters card details in the secure web interface to complete payment

Implementation

PurchaseFragment

The card payment process begins in PurchaseFragment.kt where merchants enter the amount and currency:
PurchaseFragment.kt
private fun processPayment() {
    when {
        amount.text.toString().isEmpty() -> {
            showToast(getString(R.string.all_please_enter_amount))
        }
        getCurrency.text.toString().isEmpty() -> {
            showToast(getString(R.string.all_select_currency))
        }
        else -> {
            if (validateSignUpFieldsOnTextChange()) {
                val bundle = Bundle()
                bundle.putString(PAYMENT_KEY, amount.text.toString())
                bundle.putString(CURRENCY_KEY, getCurrency.text.toString())
                val fragment = CompletePaymentWebViewFragment()
                fragment.arguments = bundle
                requireActivity().supportFragmentManager.beginTransaction()
                    .replace(R.id.container_main, fragment)
                    .addToBackStack(null)
                    .commit()
            }
        }
    }
}

Currency Selection

NetPOS provides a currency dropdown adapter:
private fun listOfCurrency() {
    val currencyAdapter = CurrencyAdapter(
        displayCurrency(), 
        requireContext(),
        android.R.layout.simple_expandable_list_item_1
    )
    getCurrency.setAdapter(currencyAdapter)
    
    getCurrency.onItemClickListener = object : AdapterView.OnItemClickListener {
        override fun onItemClick(adapterView: AdapterView<*>?, p1: View?, p2: Int, p3: Long) {
            val selectedCurrency = adapterView?.getItemAtPosition(p2) as String
            getCurrency.setText(selectedCurrency)
        }
    }
}

Payment WebView

After amount and currency selection, the payment is completed through CompletePaymentWebViewFragment.kt:
CompletePaymentWebViewFragment.kt
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    webView = binding.loadWebView
    bank = getBankName() ?: ""
    val user = Singletons.gson.fromJson(Prefs.getString(PREF_USER, ""), User::class.java)
    netposID = user.netplus_id
    userTID = user.terminal_id
    netplusPayMid = user.merchantId
    merchantID = user.netplusPayMid
    email = CONTACTLESS_TRANSACTION_DEFAULT_EMAIL
    
    amount = arguments?.getString(PAYMENT_KEY)
    currency = arguments?.getString(CURRENCY_KEY)
    setUpWebView(webView)
}

WebView Configuration

The payment WebView is configured with secure settings:
private fun setUpWebView(webView: WebView) {
    webView.settings.apply {
        javaScriptEnabled = true
        loadWithOverviewMode = true
        useWideViewPort = true
        domStorageEnabled = true
        databaseEnabled = true
        setGeolocationEnabled(true)
        defaultTextEncodingName = "utf-8"
        mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
        
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
            safeBrowsingEnabled = true
        }
    }
    
    webView.apply {
        webViewClient = object : WebViewClient() {
            override fun onReceivedSslError(
                view: WebView?, 
                handler: SslErrorHandler?, 
                error: SslError?
            ) {
                handler?.proceed()
            }
            
            override fun onReceivedError(
                view: WebView?, 
                request: WebResourceRequest?, 
                error: WebResourceError?
            ) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    Log.e("WebViewError", "${error?.description}")
                }
            }
        }
        webChromeClient = WebChromeClient()
        loadUrl(buildPaymentUrl())
    }
}

Payment URL Structure

The payment URL includes all necessary merchant and transaction parameters:
val paymentUrl = "https://qrpay.paysaddle.com/payment/#!/card?" +
    "NPmerchantId=$merchantID" +
    "&terminalId=$userTID" +
    "&netposId=$netplusPayMid" +
    "&amount=$amount" +
    "&name=$CUSTOMER" +
    "&email=$CONTACTLESS_TRANSACTION_DEFAULT_EMAIL" +
    "&bank=$bank" +
    "&app=$CONTACT" +
    "&currency=$currency"

URL Parameters

ParameterDescriptionSource
NPmerchantIdNetPlus Pay Merchant IDUser profile
terminalIdTerminal identifierUser profile
netposIdNetPos merchant IDUser profile
amountTransaction amountUser input
nameCustomer nameDefault: “Customer”
emailTransaction emailDefault contactless email
bankBank nameConfiguration
appApplication identifierContact constant
currencyTransaction currencyUser selection

Supported Currencies

NetPOS supports the following currencies for card payments:
  • NGN - Nigerian Naira (primary)
  • USD - United States Dollar
  • EUR - Euro
  • GBP - British Pound Sterling

Input Validation

The payment form validates input in real-time:
private fun validateSignUpFieldsOnTextChange(): Boolean {
    var isValidated = true
    
    amount.doOnTextChanged { _, _, _, _ ->
        when {
            amount.text.toString().trim().isEmpty() -> {
                showToast(getString(R.string.all_please_enter_amount))
                isValidated = false
            }
            else -> {
                binding.priceInputLayout.error = null
                isValidated = true
            }
        }
    }
    return isValidated
}
The WebView supports back navigation through payment pages:
activity?.onBackPressedDispatcher?.addCallback(
    viewLifecycleOwner,
    object : OnBackPressedCallback(true) {
        override fun handleOnBackPressed() {
            if (webView.canGoBack()) {
                webView.goBack()
            } else {
                requireActivity().supportFragmentManager.popBackStack()
            }
        }
    }
)

Security Features

The WebView is configured with SSL error handling for development/testing. In production environments, proper SSL certificate validation should be enforced.

Secure Configuration

  • JavaScript Enabled - Required for PaySaddle interface
  • DOM Storage - Enabled for payment session management
  • Safe Browsing - Enabled on Android 8.1+
  • Mixed Content - Allowed (configure based on security requirements)

Error Handling

Error: “Please enter amount”Cause: User attempted to proceed without entering an amountSolution: Enter a valid transaction amount before proceeding
Error: “Select currency”Cause: User did not select a currency from the dropdownSolution: Select the appropriate currency before processing
Error: Resource loading errors in WebViewCause: Network connectivity issues or payment gateway errorsSolution: Check internet connection and retry the transaction

Best Practices

Amount Validation

Always validate amount before opening payment WebView to avoid unnecessary network calls

Currency Selection

Ensure currency is selected to prevent payment errors at the gateway

Network Check

Verify network connectivity before initiating payment process

Error Messages

Provide clear, actionable error messages to guide merchants through resolution

Testing

Test card payments in a sandbox environment before processing live transactions. Ensure all merchant credentials are properly configured.

Test Checklist

  • Amount entry and validation
  • Currency selection functionality
  • WebView loading and navigation
  • Payment completion flow
  • Error handling scenarios
  • Back navigation behavior

Payment Gateway

PaySaddle payment gateway documentation

Build docs developers (and LLMs) love