Skip to content

Repository files navigation

PaymentSetu Android SDK (Checkout)

A secure UPI checkout SDK for the PaymentSetu payment gateway. Your backend creates the order (with the secret API key); the app opens the resulting payment URL via Chrome Custom Tabs (with a WebView fallback) and returns a typed result through the Activity Result API.

  • ✅ Kotlin, minSdk 21, published as an AAR
  • No API key in the app — the secret key stays on your server
  • ✅ Chrome Custom Tabs (best UPI-app compatibility) + WebView fallback
  • ✅ Typed PaymentResult via the Activity Result API
  • ✅ Deep-link return handling built in

⚠️ Security model — read this first

Your PaymentSetu API key is a secret (it authenticates the API and signs webhooks). Never ship it in an app. This SDK is deliberately a checkout SDK, not an API client:

[Your App]  --request order-->  [Your Backend]  --create_order (secret key)-->  [PaymentSetu]
[Your App]  <---payment_url---  [Your Backend]  <---------payment_url----------
[Your App]  --- opens payment_url via this SDK --->  UPI payment
[PaymentSetu]  --webhook (payment result)-->  [Your Backend]   ← source of truth
[Your App]  --confirm order status-->  [Your Backend]

A PaymentResult.Success from this SDK means the customer returned — not that money was captured. Always confirm the order with your backend (which knows the real state from the webhook) before delivering goods/services. Use the server SDKs (PHP / Node / .NET) for order creation and webhook verification.


Installation

Once published:

// app/build.gradle.kts
dependencies {
    implementation("com.paymentsetu:checkout:1.0.0")
}

To build the AAR from source (this repo ships without the Gradle wrapper jar):

cd android-sdk
gradle wrapper            # once, to generate ./gradlew
./gradlew :paymentsetu:assembleRelease
# output: paymentsetu/build/outputs/aar/paymentsetu-release.aar

Or just open the android-sdk folder in Android Studio.


Setup

1. Declare your redirect (deep-link) scheme

The SDK detects the return from payment via a deep link into your app. Pick a unique scheme and set it as a manifest placeholder:

// app/build.gradle.kts
android {
    defaultConfig {
        manifestPlaceholders["paymentSetuRedirectScheme"] = "myapp"
    }
}

This wires up the SDK's redirect receiver for URLs like myapp://paymentsetu/callback. (You do not need to add an intent-filter yourself — the library manifest does it using this placeholder.)

2. Create the order on your backend with a matching redirect_url

When your server calls create_order, set redirect_url to the same deep link you'll pass to the SDK, e.g. myapp://paymentsetu/callback. After payment, PaymentSetu redirects there, which reopens your app.


Usage

import com.paymentsetu.checkout.CheckoutOptions
import com.paymentsetu.checkout.PaymentResult
import com.paymentsetu.checkout.PaymentSetuCheckout

class CheckoutActivity : ComponentActivity() {

    private val checkout =
        registerForActivityResult(PaymentSetuCheckout.Contract()) { result ->
            when (result) {
                is PaymentResult.Success -> {
                    // The customer returned. CONFIRM with your backend before fulfilling.
                    confirmOrderWithBackend(result.orderId)
                }
                is PaymentResult.Failed    -> showError(result.reason)
                is PaymentResult.Cancelled -> showCancelled()
            }
        }

    private fun startPayment() = lifecycleScope.launch {
        // 1. Ask YOUR backend to create the order and return a payment_url.
        val order = api.createOrder(amountPaisa = 10000)  // your API, server uses secret key

        // 2. Launch checkout.
        checkout.launch(
            CheckoutOptions(
                paymentUrl = order.paymentUrl,
                redirectUrl = "myapp://paymentsetu/callback", // must match order redirect_url
                orderId = order.orderId,
            )
        )
    }
}

CheckoutOptions

Field Required Notes
paymentUrl The payment_url your backend got from create_order.
redirectUrl Deep link the SDK watches for; must equal the order's redirect_url.
orderId Echoed back in the result.
toolbarColor Custom Tab toolbar color (@ColorInt).
allowWebViewFallback Default true; use a WebView if no browser supports Custom Tabs.

PaymentResult

  • Success(orderId, returnUri, data) — customer returned; verify server-side.
  • Failed(orderId, reason, returnUri?, data) — explicit failure or no browser/WebView.
  • Cancelled(orderId?) — customer dismissed the payment screen.

data holds any query parameters present on the redirect URL (e.g. status, txn_utr) when PaymentSetu includes them.


How return detection works

  1. SDK opens paymentUrl in a Custom Tab.
  2. Customer pays (UPI apps launch from the browser).
  3. PaymentSetu redirects to your redirect_url deep link.
  4. PaymentSetuRedirectActivity (registered via your scheme) receives it and hands it back to the SDK, which parses it into a PaymentResult.
  5. If the customer just closes the tab, the SDK reports Cancelled.

On devices with no Custom Tabs-capable browser, the SDK falls back to an in-app WebView that also routes upi:/intent: links to installed UPI apps.


Testing

The framework-free redirect logic has JVM unit tests:

./gradlew :paymentsetu:testDebugUnitTest

Requirements

  • Android minSdk 21+
  • AndroidX

License

MIT — see LICENSE.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages