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:
Staging Onboarding
- Once merchants are onboarded on Decfin, below credentials will be shared -
- Client ID
- Client Secret
- Consumer URN
- User Name (To access private repository)
- Password (To access private repository)
- Project ID
- SDK Version
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.
Note- Token will expire every 24 hours.
| Environment | Base URL |
|---|---|
| Staging | https://staging.api.decentro.tech |
| Production | https://api.decentro.tech |
Backend API Call Example:
curl --location 'https://staging.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.SANDBOX, // or SANDBOX/PRODUCTION
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
Staging Environment Testing
expiryTime- To be set for 15minutes to test success/ failure scenarios- For link expired scenario's set
expiryTimeto 1 minute.- Status of the mandate will change based on the
amountpassed in the below API-- Success scenario - 0 to 1500
- Failure scenario - 1501 to 3000
- On Staging environment, there might be a delay in callback/ status transition for success/ failure mandates.
- SDK might show mandate as "Active" but status check API might respond with "Pending" there will be a small delay, this is expected.
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}")
}
}
