Autopay android SDK integration guide
Overview
The Decentro UPI AutoPay Android SDK enables seamless integration of UPI recurring payments into your Android applications. Built with modern Android technologies including Jetpack Compose, the SDK handles the complete mandate creation flow from mobile number entry to UPI app selection and transaction processing.
Key Features
- Recurring Payments: Support for Onetime, Monthly, Weekly, Daily, Quarterly, Bimonthly, Fortnightly, Halfyearly, Yearly, Aspresented mandates.
- PSP Support: Works with all UPI apps (Google Pay, PhonePe, Paytm, BHIM, etc.)
- Customizable UI: Jetpack Compose-based UI with full theming support.
- Secure Authentication: JWT-based authentication with automatic token refresh.
- Easy Integration: Simple callback-based integration.
- Modern Architecture: Built with Kotlin, Coroutines, and Jetpack Compose.
- Production Ready: Comprehensive error handling and validation
- Flexible Configuration: Multiple flow options and customizable parameters
Prerequisites
Before integrating the SDK, ensure your development environment meets the following requirements:
System Requirements
- Android Studio: Arctic Fox (2020.3.1) or newer
- Minimum SDK: Android 7.0 (API level 24)
- Target SDK: Android 14 (API level 34)
- Kotlin: 1.9.0 or higher
- Gradle: 7.4 or higher
- Java: JDK 17 or higher
Business Requirements
- Merchants should be onboarded on Decentro
- UPI AutoPay feature enabled for your account
- Valid API credentials (Client ID, Client Secret, Consumer URN)
Callback URLs to be configured - IP whitelisting
Compliance Requirements
- Your application must comply with Decentro's integrity standards
- Proper handling of sensitive user data
- Implementation of security best practices
Installation
Step 1: Add Repository Configuration
Add the Decentro SDK repository to your project's settings.gradle file:
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
// Decentro SDK Repository
maven {
url = uri("https://gitlab.com/api/v4/projects/XXXX/packages/maven")
credentials {
username = project.findProperty("decentro.sdk.username")
password = project.findProperty("decentro.sdk.password")
}
authentication {
basic(BasicAuthentication)
}
}
}
}
Step 2: Add Credentials
Add your SDK access credentials to gradle.properties: (Note : We will share the username and password for the sdk)
Decentro SDK Credentials (provided by Decentro team)
decentro.sdk.username=your-deploy-token-username
decentro.sdk.password=your-deploy-token
Security Note: Never commit gradle.properties with actual credentials to version control. Add it to your .gitignore file.
Step 3: Add SDK Dependency
Add the Decentro SDK dependency to your app's build.gradle file:
dependencies {
implementation 'com.decentro.sdk:upi-autopay-sdk:1.X.X'
// Required dependencies (if not already included)
implementation 'androidx.activity:activity-compose:1.8.2'
implementation 'androidx.compose.material3:material3:1.1.2' }
Step 4: Update AndroidManifest.xml
Add the following permissions and configurations to your AndroidManifest.xml:
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<queries>
<intent>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="upi" />
</intent>
</queries>
<application android:allowBackup="true" android:theme="@style/Theme.AppCompat" ... >
</application>
</manifest>
Authentication Setup
Step 1: Obtain JWT Token
Before using the SDK, you need to obtain a JWT access token from your app. The SDK requires this token for authentication.
Backend API Call Example:
curl --location 'https://api.decentro.tech/sdk_exc/v2/auth/token' \
--header 'Content-Type: application/json' \
--header 'User-Agent: DecentroSDK/1.0' \
--data '{
"grant_type": "client_credentials",
"client_id": "xxxxxxxx",
"client_secret": "xxxxxxxx",
"ttl": 3600,
"apis": [
{
"endpoint": "/v3/payments/upi/autopay/mandate/status",
"query_parameters": null,
"request_payload": null
},
{
"endpoint": "/v3/banking/mobile_to_account",
"query_parameters": null,
"request_payload": null
},
{
"endpoint": "/v3/payments/upi/autopay/mandate/link",
"query_parameters": null,
"request_payload": null
},
{
"endpoint": "/v3/banking/account_validation/status",
"query_parameters": null,
"request_payload": null
},
{
"endpoint": "/decentro/read/get_upi_psp_mapping",
"query_parameters": null,
"request_payload": null
}
]
}'
Step 2: Initialize SDK Configuration
import com.decentro.sdk.DecentroUPIAutoPaySDK
class MyActivity : ComponentActivity() {
private fun initializeSDK() {
val config = DecentroUPIAutoPaySDK.Configuration(
accessToken = "your-jwt-access-token",
refreshToken = "your-jwt-refresh-token", // Optional but recommended
environment = DecentroUPIAutoPaySDK.Environment.PRODUCTION, // or SANDBOX/QA
enableLogging = BuildConfig.DEBUG // Enable logging in debug mode
)
DecentroUPIAutoPaySDK.initialize(this, config)
}
}
Integration Steps
Step 1: Create Mandate Details
Configure the mandate parameters according to your business requirements:
Decentro Create Mandate API - Link
val mandateDetails = DecentroUPIAutoPaySDK.MandateDetails(
referenceId = "MERCHANT_REF_${System.currentTimeMillis()}",
consumerUrn = "your-consumer-urn",
mandateName = "Monthly Subscription",
amount = 99.00,
frequency = "monthly", // daily, weekly, monthly, quarterly, yearly
purposeMessage = "Subscription Payment",
ruleType = "after", // after, before, On
amountRule = "MAX", // MAX, EXACT
startDate = "2026-02-01", // YYYY-MM-DD format
endDate = "2027-02-01", // YYYY-MM-DD format
expiryTime = 10, // Mandate creation timeout in minutes
defaultAmount = 99.00,
isManagedByDecentro = false,
isQrRequested = false,
isBlockFunds = false,
isRevokable = true,
isCollectRequest = false,
isTpv = false,
generatePspUri = true,
isDownpayment = false,
isFirstTxnAmount = false,
mandateActionCallbackSubscriberData = DecentroUPIAutoPaySDK.CallbackSubscriberData(
url = "https://your-webhook-url.com/callback",
method = "POST",
headers = mapOf("content-type" to "application/json")
)
)
Step 2: Configure UI Settings
Customize the SDK's appearance and behavior:
val uiConfig = DecentroUPIAutoPaySDK.SDKUIConfig(
isMobileToAccountEnabled = true, // Show mobile number screen
isMobileToAccountSkippable = true, // Allow users to skip mobile entry
mobileToAccountReferenceId = null, // Pre-fetched M2A reference (optional)
prefillMobileNumber = "+9198765432XX", // Pre-fill mobile number (optional)
isAccountDetailsEditable = true, // Allow editing account details
themeColor = "#2962FF", // Primary color (hex format)
fontColor = "#000000", // Text color (hex format)
logoUrl = null, // Your logo URL (optional)
brandLogo = "https://your-domain.com/logo.svg", // Brand logo for header
merchantName = "Your Company Name",
)
Step 3: Create Mandate Request
Combine all configurations into a single request object:
val mandateRequest = DecentroUPIAutoPaySDK.MandateRequest(
mandateDetails = mandateDetails,
uiConfig = uiConfig,
mobileToAccountConfig = DecentroUPIAutoPaySDK.MobileToAccountConfig(
purposeMessage = "auth-validation",
fetchBranchDetails = false
)
)
Step 4: Implement SDK Callback
Handle SDK responses with appropriate callbacks:
class MainActivity : ComponentActivity() {
private val sdkCallback = object : DecentroUPIAutoPaySDK.UPIAutoPayCallback {
override fun onSuccess(response: DecentroUPIAutoPaySDK.MandateResponse) {
// Mandate created successfully
Log.d(TAG, "Mandate ID: ${response.mandateId}")
Log.d(TAG, "Status: ${response.status}")
Log.d(TAG, "UPI ID: ${response.upiId}")
Log.d(TAG, "Transaction ID: ${response.transactionId}")
// Update your UI
showSuccessMessage("Mandate created successfully!")
// Store mandate ID for future reference
saveMandateId(response.mandateId)
// Navigate to success screen
navigateToSuccessScreen(response)
}
override fun onFailure(error: String, errorCode: String?) {
// Handle failure
Log.e(TAG, "SDK Error: $error, Code: $errorCode")
// Show error message to user
showErrorMessage(error)
// Handle specific error codes
when (errorCode) {
"SDK_NOT_INITIALIZED" -> initializeSDK()
"INVALID_TOKEN" -> refreshTokenAndRetry()
"NETWORK_ERROR" -> showNetworkErrorDialog()
else -> showGenericErrorDialog(error)
}
}
override fun onCancel() {
// User cancelled the flow
Log.d(TAG, "User cancelled mandate creation")
showMessage("Mandate creation cancelled")
}}}
Step 5: Launch SDK Flow
Start the UPI AutoPay mandate creation flow:
private fun startMandateCreation() {
try {
// Ensure SDK is initialized
if (!DecentroUPIAutoPaySDK.isInitialized()) {
initializeSDK()
}
// Launch mandate creation flow
DecentroUPIAutoPaySDK.startMandateCreation(
activity = this,
mandateRequest = mandateRequest,
callback = sdkCallback
)
} catch (e: Exception) {
Log.e(TAG, "Failed to start mandate creation", e)
showErrorMessage("Failed to start mandate creation: ${e.message}")
}
}
