Pay by App button

Drop-in button that hands the customer off to their bank's app (ABSA, Standard Bank, Capitec, etc.) via a deep link.

The PayByApp button lets a customer pay through their bank's mobile app rather than entering card details in your app. The button shows a chooser of installed bank apps; the customer picks one; Scan to Pay deep-links into that app to complete the payment.

It's useful when:

  • Your customer base prefers paying via their bank app
  • You want to avoid card-on-file registration overhead for first-time customers
  • You're integrating in a regulated context where keeping cardholder data out of your app is preferable

For the pure card-in-SDK flow, see Pay-by-Card button instead.


How it works

   Your app          Lib Lite SDK          Bank app             Scan to Pay
   ────────          ────────────          ────────             ───────────
        │                  │                    │                      │
   user taps               │                    │                      │
   PayByApp                │                    │                      │
        ├──────────────────►│                    │                      │
        │                  │  list installed     │                      │
        │                  │  bank apps          │                      │
        │                  │ ───┐                │                      │
        │                  │ ◄──┘                │                      │
        │ ◄──── chooser ───┤                    │                      │
        │                  │                    │                      │
   user picks bank          │                    │                      │
        ├──────────────────►│                    │                      │
        │                  │  deep-link launch   │                      │
        │                  ├───────────────────►│                      │
        │                  │                    │  user pays in their  │
        │                  │                    │  bank app            │
        │                  │                    │ ───────────────────► │
        │                  │                    │ ◄─────────────────── │
        │                  │  returns result    │                      │
        │                  │ ◄───────────────────                       │
        │ ◄── result ──────┤                                            │

Step 1 — Manifest entries

Add the PayByAppActivity to your AndroidManifest.xml:

<activity
    xmlns:tools="http://schemas.android.com/tools"
    android:name="com.eftcorp.liblite.PayByAppActivity"
    android:exported="true"
    tools:node="merge">

    <intent-filter android:autoVerify="true">
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data
            android:host="@string/deeplink_host"
            android:pathPrefix="@string/deeplink_path_prefix"
            android:scheme="@string/deeplink_scheme" />
    </intent-filter>
</activity>

Step 2 — String resources

In res/values/strings.xml, define your app's universal-link target — the SDK uses these so the bank app knows where to return after payment:

<string name="deeplink_scheme">https</string>
<string name="deeplink_host">sample.com</string>
<string name="deeplink_path_prefix">/prefix</string>

Replace with your own verified universal-link domain. The autoVerify="true" attribute requires the matching .well-known/assetlinks.json on that domain — see Android App Links docs for setup details.


Step 3 — Add the button to your layout

<com.eftcorp.liblite.paybyapp.PayByAppButton
    android:id="@+id/payByApp"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />

Step 4 — Register the result launcher

Same launcher pattern as the standard payment activity:

private final ActivityResultLauncher<Intent> libLiteActivityLauncher =
    registerForActivityResult(
        new ActivityResultContracts.StartActivityForResult(),
        result -> handleLibLiteResult(result.getResultCode(), result.getData())
    );

Step 5 — Launch the PayByApp activity

When the button is tapped, build and launch the intent. Note the additional deep-link extras compared to the Pay-by-Card flow:

public void startLibLiteActivityWithPayByApp(CodeBean codeBean) {
    Intent intent = new Intent(this, PayByAppActivity.class);
    intent.putExtra(LibLiteActivity.IN_APP_LINK_SCHEME,      getString(R.string.deeplink_scheme));
    intent.putExtra(LibLiteActivity.IN_APP_LINK_HOST,        getString(R.string.deeplink_host));
    intent.putExtra(LibLiteActivity.IN_APP_LINK_PATH_PREFIX, getString(R.string.deeplink_path_prefix));
    intent.putExtra(LibLiteActivity.IN_HASH,    "YOUR_SMS_HASH");
    intent.putExtra(LibLiteActivity.IN_API_KEY, "YOUR_API_KEY");
    intent.putExtra(LibLiteActivity.IN_CODE,    "1234567890");
    libLiteActivityLauncher.launch(intent);
}

Supported bank apps

The button discovers installed bank apps using their published deep-link schemes. Currently supported:

BankScheme
ABSAmasterpass.absa.scheme://
Standard Bankmasterpass.sbsa.scheme://
Nedbankmasterpass.nedbank.scheme://
FNBmasterpass.fnb.scheme://
Capitecmasterpass.capitec.scheme://
VodaPaymasterpass.vodapay.scheme://
Spendamasterpass.spenda.scheme://

The supported list is maintained by EFT Corporation — new banks are added in SDK minor releases. See Changelog.


Result handling

Identical to the standard payment activity — five possible result codes. See Payments.

The extra OUT_LOCATION value on LIBLITE_USER_CANCELLED is particularly useful for Pay-by-App: it tells you whether the customer cancelled in your app, the chooser, or after the bank-app handoff.


When no bank apps are installed

If none of the supported bank apps are installed, the button falls back to the standard Pay-by-Card flow — same UX as if you'd used PayByCardButton directly. The customer can register a card on the spot.


What's next