Deep linking from your Android mobile app

You can use deep linking to navigate users from your mobile app to payment screens in the AffiniPay, CPACharge, or LawPay mobile app (the target app). Using these payment screens and an optional AffiniPay card reader or manual entry, your users submit card payment information securely in the target app and then return seamlessly to your mobile app. Your backend system then submits the charge.

To take advantage of deep linking:

Obtain the payment token

1: Set a scheme name to identify your mobile app

To set the scheme name for your mobile app, add the following code to AndroidManifest.xml. In this example, partnerapp is the scheme name.

android:launchMode="singleTask"

      <intent-filter>            
        <action android:name="android.intent.action.VIEW" />            
        <category android:name="android.intent.category.DEFAULT" />            
        <category android:name="android.intent.category.BROWSABLE" />            
        <data android:scheme="partnerapp" />        
      </intent-filter>

After adding this code, AndroidManifest.xml should look like this:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  package="com.example.partnerapp.android">
  <application
      android:allowBackup="true"
      android:icon="@mipmap/ic_launcher"
      android:label="@string/app_name"
      android:roundIcon="@mipmap/ic_launcher_round"
      android:supportsRtl="true"
      android:theme="@style/AppTheme"
      android:launchMode="singleTask">
      <activity android:name=".MainActivity">
          <intent-filter>
              <action android:name="android.intent.action.MAIN" />
              <category android:name="android.intent.category.LAUNCHER" />
          </intent-filter>
          <intent-filter>
              <action android:name="android.intent.action.VIEW" />
              <category android:name="android.intent.category.DEFAULT" />
              <category android:name="android.intent.category.BROWSABLE" />
              <data android:scheme="partnerapp" />
          </intent-filter>
      </activity>
  </application>
</manifest>

You must create the URL that will initiate the deep linking process from your mobile app. Here is an example URL:

androidlawpay://charge?amount=100&publicKey=m_Nz_JZ1wDEoSP7uRTQnIqY&accountName=Operating&demoMode=1&disableCardReader=0&requireCvv=0&requireSwipeCvv=1&trustAccount=0&&requiredPaymentFields=cvv,address1,postal_code&swipeRequiredPaymentFields=cvv,address1,postal_code&continue=partnerapp://

The deep link URL starts with the scheme name for the target app. In this example, androidlawpay is the scheme name and it provides a deep link to the LawPay app.

You must include the required parameters publicKey and continue in the deep link URL.

Required parameters

ParameterTypeDescription
publicKeyStringThe merchant’s public key.
continueStringThe scheme name for your mobile app (partnerapp is used in the examples on this page).

Optional parameters

ParameterTypeDescription
amountStringThe amount to charge, in terms of the currency’s smallest unit. For USD, this is the amount in cents.
accountNameStringThe name of the merchant account.
demoModeStringWhether the transaction is a demo transaction (if set to 1) or live transaction (if set to 0).
disableCardReaderStringWhether the card reader should be disabled and transactions should be manual entry only (if set to 1) or the card reader should be enabled (if set to 0).
requireCvvStringWhether CVV is required for manual transactions (if set to 1) or CVV is not required for manual transactions (if set to 0).
requireSwipeCvvStringWhether CVV is required for swiper transactions (if set to 1) or CVV is not required for swiper transactions (if set to 0).
requiredPaymentFieldsStringWhich fields are required for manual transactions, such as cvv,address1,postal_code.
swipeRequiredPaymentFieldsStringWhich fields are required for swiper transactions, such as cvv,address1,postal_code.
trustAccountStringWhether the account type is Trust (if set to 1) or not (if set to 0).

3: Send the payment token request to the target app

Add the following lines of code in MainActivity.kt to send the payment token request (including the deep link URL) to the target app.

import android.content.Intent
import android.net.Uri

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    view.findViewById<Button>(R.id.button_first).setOnClickListener {
        val url = "androidlawpay://charge?amount=100&publicKey=m_Nz_JZ1wDEoSP7uRTQnIqY&accountName=Operating&demoMode=1&disableCardReader=0&requireCvv=0&requireSwipeCvv=1&trustAccount=0&&requiredPaymentFields=cvv,address1,postal_code&swipeRequiredPaymentFields=cvv,address1,postal_code&continue=partnerapp://"
        val intent = Intent(Intent.ACTION_VIEW)
        intent.data = Uri.parse(url)
        startActivity(intent)
    }
}

4: Parse the response

After the payment details are processed, the target app returns the following parameters:

ParameterTypeDescription
successStringWhether tokenization was successful (true) or not (false).
reasonStringWhen the tokenization fails, details are returned, such as “User cancelled the charge” or “The one-time token cannot be created”.
clientDetailsInfoJSON StringWhen a payment token is created, the token ID and the payer details submitted in the target app are returned. Here is an example: {\"id\":\"ONZ-48zBR-SrR1wh3UNcAw\",\"email\":\"abc@affinipay.com\",\"phone\":\"(123) 456-7890\",\"reference\":\"Ref Value\",\"city\":\"Austin\",\"country\":\"US\",\"name\":\"John Doe\",\"address1\":\"A/502 Street Lane\",\"address2\":\"Near Cross Road\",\"postalCode\":\"37701\"}

Add the following code to MainActivity.kt to parse this data.

private fun handleIntent() {
      val action: String? = intent?.action
      val data: Uri? = intent?.data
      Log.d("handleIntent", data.toString())
      if (data != null) {
            parseUri(data)
      }
}

fun parseUri(uri: Uri?) {
      if (uri != null) {
          val success = uri.getQueryParameter("success")
          Log.d("parseUri", "success: " + success)
          if (success.equals("true")) {
                val oneTimeToken = uri.getQueryParameter("oneTimeToken")
                showAlert("Success", message = "One-time-token received : " + oneTimeToken)
            }
            else if (success.equals("false")) {
                val reason = uri.getQueryParameter("reason")
                if (reason != null) {
                    showAlert("Error", message = reason)
                }
            }
        };
}

After adding this code, MainActivity.kt should look like this:

package com.example.partnerapp.android

import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.Button
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {
    private val btnCharge: Button? = null
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        handleIntent()
    }
    override fun onNewIntent(intent: Intent?) {
        super.onNewIntent(intent)
        handleIntent()
    }
    fun createCharge(view: View) {
        Log.d("ChargeButton", "Charge button clicked")
        val url = "androidlawpay://charge?amount=100&publicKey=m_Nz_JZ1wDEoSP7uRTQnIqY&accountName=Operating&demoMode=1&disableCardReader=0&requireCvv=0&requireSwipeCvv=1&trustAccount=0&&requiredPaymentFields=cvv,address1,postal_code&swipeRequiredPaymentFields=cvv,address1,postal_code&continue=partnerapp://"
        val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
        startActivity(intent)
    }
    private fun handleIntent() {
        val action: String? = intent?.action
        val data: Uri? = intent?.data
        Log.d("handleIntent", data.toString())
        if (data != null) {
            parseUri(data)
        }
    }

    fun parseUri(uri: Uri?) {
        if (uri != null) {
            val success = uri.getQueryParameter("success")
            Log.d("parseUri", "success: " + success)
            if (success.equals("true")) {
                val oneTimeToken = uri.getQueryParameter("oneTimeToken")
                showAlert("Success", message = "One-time-token received : " + oneTimeToken)
            }
            else if (success.equals("false")) {
                val reason = uri.getQueryParameter("reason")
                if (reason != null) {
                    showAlert("Error", message = reason)
                }
            }
        };
    }

    fun showAlert(title: String, message: String) {
        val builder = AlertDialog.Builder(this)
        builder.setTitle(title)
        builder.setMessage(message)
        builder.setIcon(android.R.drawable.ic_dialog_info)
        builder.setPositiveButton("Ok"){dialogInterface, which ->
            Toast.makeText(applicationContext,"clicked ok",Toast.LENGTH_LONG).show()
        }
        val alertDialog: AlertDialog = builder.create()
        alertDialog.setCancelable(false)
        alertDialog.show()
    }
}

Submit the charge

To submit the charge:

  1. Hand off the payment token and payment details to your backend server, which is already integrated with AffiniPay.
  2. Create a charge from your backend server.