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:
- You must have an AffiniPay payment integration. You’ll use the credentials you obtained during the OAuth process to submit payment information on behalf of your users, who are AffiniPay merchants.
- Your users must have both your mobile app and the target app installed.
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>
2: Create a deep link URL with payment details
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.
- To deep link to the AffiniPay app, use
androidaffinipay
. - To deep link to the CPACharge app, use
androidcpacharge
.
You must include the required parameters publicKey
and continue
in the deep link URL.
Required parameters
Parameter | Type | Description |
---|---|---|
publicKey | String | The merchant’s public key. |
continue | String | The scheme name for your mobile app (partnerapp is used in the examples on this page). |
Optional parameters
Parameter | Type | Description |
---|---|---|
amount | String | The amount to charge, in terms of the currency’s smallest unit. For USD, this is the amount in cents. |
accountName | String | The name of the merchant account. |
demoMode | String | Whether the transaction is a demo transaction (if set to 1 ) or live transaction (if set to 0 ). |
disableCardReader | String | Whether 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 ). |
requireCvv | String | Whether CVV is required for manual transactions (if set to 1 ) or CVV is not required for manual transactions (if set to 0 ). |
requireSwipeCvv | String | Whether CVV is required for swiper transactions (if set to 1 ) or CVV is not required for swiper transactions (if set to 0 ). |
requiredPaymentFields | String | Which fields are required for manual transactions, such as cvv,address1,postal_code . |
swipeRequiredPaymentFields | String | Which fields are required for swiper transactions, such as cvv,address1,postal_code . |
trustAccount | String | Whether 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:
Parameter | Type | Description |
---|---|---|
success | String | Whether tokenization was successful (true ) or not (false ). |
reason | String | When the tokenization fails, details are returned, such as “User cancelled the charge” or “The one-time token cannot be created”. |
clientDetailsInfo | JSON String | When 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@aexample.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:
- Hand off the payment token and payment details to your backend server, which is already integrated with AffiniPay.
- Create a charge from your backend server.