Android SDK
Install the DEUNA Android SDK and integrate modal, embedded, wallet, voucher, and next-action flows.
On this page
- Requirements
- Install
- Initialize
- Open Payment Widget
- Available experiences
- Embed a widget
- Filter and configure payment methods
- Dynamic styling and order refresh
- Payment Vault and Click to Pay
- Native Google Pay
- Continue a pending action
- Open a voucher
- Fraud-device data and fingerprinting
- Callback and lifecycle reference
- Official examples and source
Requirements#
To integrate the DEUNA Android SDK, make sure your project meets the following requirements:
- Minimum SDK version:
minSdkVersion 24or higher (Android API 24+) - Android Gradle Plugin (AGP): Version 8.5.1 or higher (required for Android 16 KB page size support)
- Programming language: Kotlin or Java
- DEUNA credentials: Active account and valid credentials (contact support@deuna.com if you experience delays obtaining credentials)
Install#
1. Add the JitPack repository
Add the JitPack repository inside the dependencyResolutionManagement block in your settings.gradle.kts (or settings.gradle):
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
maven(url = "https://jitpack.io")
}
}dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
maven { url 'https://jitpack.io' }
}
}If your project does not use dependencyResolutionManagement, add the repository in the root build.gradle:
allprojects {
repositories {
google()
mavenCentral()
maven { url 'https://jitpack.io' }
}
}2. Configure build.gradle and dependencies
Ensure your minSdk is 24 or higher, and add the DEUNA SDK dependency:
android {
defaultConfig {
minSdk = 24
}
}
dependencies {
implementation("com.github.deuna-developers:deuna-sdk-android:2.12.7")
}android {
defaultConfig {
minSdk 24
}
}
dependencies {
implementation 'com.github.deuna-developers:deuna-sdk-android:2.12.7'
}Initialize#
import com.deuna.maven.DeunaSDK
import com.deuna.maven.shared.EnvironmentYou can initialize the SDK in two ways depending on your app architecture:
Global shared instance
Initialize once during application startup (e.g., in your Application.onCreate):
DeunaSDK.initialize(
environment = Environment.SANDBOX, // Environment.SANDBOX or Environment.PRODUCTION
publicApiKey = "YOUR_PUBLIC_API_KEY"
)
val deunaSDK = DeunaSDK.sharedFlow or screen instance
Create an instance for a specific checkout screen or ViewModel:
val deunaSDK = DeunaSDK(
environment = Environment.SANDBOX,
publicApiKey = "YOUR_PUBLIC_API_KEY"
)Open Payment Widget#
The Payment Widget offers multiple payment methods to customers:
- Credit and debit cards: Visa, Mastercard, American Express, and co-branded cards.
- Alternative payment methods (APMs): OXXO, KueskiPay, Aplazo, Daviplata, Nequi, and more.
- Digital wallets: Google Pay and PayPal.
Display in a dialog
To present the payment widget in a DialogFragment, call initPaymentWidget passing an Activity Context:
import com.deuna.maven.initPaymentWidget
import com.deuna.maven.widgets.payment_widget.PaymentWidgetCallbacks
import com.deuna.maven.payments.PaymentsError
deunaSDK.initPaymentWidget(
context = this, // Activity context
orderToken = "YOUR_ORDER_TOKEN",
callbacks = PaymentWidgetCallbacks().apply {
onSuccess = { order ->
deunaSDK.close() // Close the DialogFragment
// YOUR CODE HERE: Handle successful payment (e.g. navigate to confirmation)
}
onError = { error ->
// Error handling
when (error.type) {
PaymentsError.Type.INITIALIZATION_FAILED -> {
deunaSDK.close()
// YOUR CODE HERE: Handle initialization failure (e.g. show alert or fallback)
}
PaymentsError.Type.PAYMENT_ERROR -> {
// YOUR CODE HERE: Handle payment processing failure (e.g. prompt retry)
}
else -> {}
}
}
onClosed = { action ->
// Widget closed: action == CloseAction.USER_ACTION or CloseAction.SYSTEM_ACTION
// YOUR CODE HERE: Handle dialog dismissal
}
onCardBinDetected = { metadata, refetchOrder ->
if (metadata != null) {
// YOUR CODE HERE: Handle card brand or BIN detection (e.g. apply discounts)
}
}
onInstallmentSelected = { metadata, refetchOrder ->
// YOUR CODE HERE: Handle installment plan selection
}
onPaymentProcessing = {
// YOUR CODE HERE: Payment processing started (e.g. disable UI buttons)
}
onEventDispatch = { event, payload ->
// YOUR CODE HERE: Track analytics event
}
},
userToken = "YOUR_USER_TOKEN", // optional
styleFile = "YOUR_STYLE_FILE_UUID", // optional
language = "en" // optional: "es", "en", "pt"
)Parameter Reference
| Parameter | Type | Dialog | Embedded | Description |
|---|---|---|---|---|
context | Context | ✅ | ❌ | Required for dialog. Activity context providing UI resources and window token. |
orderToken | String | ✅ | ✅ | Required. Unique token for the order created via DEUNA API. Important: Do not define a redirect_url in order creation if you want onSuccess to run in-app. |
callbacks | PaymentWidgetCallbacks | ✅ | ✅ | Required. Event listeners (onSuccess, onError, onClosed, onCardBinDetected, onInstallmentSelected, onPaymentProcessing, onEventDispatch). |
userToken | String? | ✅ | ✅ | Optional. Customer's DEUNA bearer token. Important: For saved cards to appear, the email linked to userToken must match billing_address.email from order creation. |
styleFile | String? | ✅ | ✅ | Optional. UUID provided by DEUNA to apply custom theme branding (colors, typography, logo). |
paymentMethods | List<Map<String, Any>>? | ✅ | ✅ | Optional. Single payment method list for direct forms flow (e.g. listOf(mapOf("paymentMethod" to "bnpl", "processors" to listOf("kueski")))). |
language | String? | ✅ | ✅ | Optional. Language code ("es", "en", "pt"). Overrides merchant default configuration. |
behavior | WidgetBehavior? | ✅ | ✅ | Optional. Flow customization, such as WidgetBehavior(paymentMethods = mapOf("flowType" to "twoStep")) for PayPal, or Split Payments splitPayments. |
fraudCredentials | Map<String, Any>? | ✅ | ✅ | Optional. Anti-fraud provider credentials (e.g. mapOf("RISKIFIED" to mapOf("storeDomain" to "example.com"))). |
domain | String? | ✅ | ✅ | Optional. Overrides default base host (https://pay.deuna.io). |
hidePayButton | Boolean | ❌ | ✅ | Optional. Hides the built-in pay button in embedded mode when your application renders a native button. |
Available experiences#
| Experience | Method | Configuration type | Important input |
|---|---|---|---|
| Payment Widget | initPaymentWidget(...) | PaymentWidgetConfiguration | context, orderToken, PaymentWidgetCallbacks |
| Payment Vault | initElements(...) | ElementsWidgetConfiguration | context, ElementsCallbacks; types may be omitted |
| Click to Pay | initElements(...) | ElementsWidgetConfiguration | types = listOf(mapOf("name" to "click_to_pay")) |
| Next Action | initNextAction(...) | NextActionWidgetConfiguration | context, orderToken, NextActionCallbacks |
| Voucher | initVoucherWidget(...) | VoucherWidgetConfiguration | context, orderToken, VoucherCallbacks |
All modal methods accept optional language, fraud, and domain inputs where supported. Do not override domain unless DEUNA assigns you a dedicated host.
Embed a widget#
To display the widget embedded inside your application with Jetpack Compose, use AndroidView and DeunaWidget.
import androidx.compose.foundation.layout.*
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import com.deuna.maven.DeunaSDK
import com.deuna.maven.web_views.deuna.DeunaWidget
import com.deuna.maven.web_views.deuna.extensions.build
import com.deuna.maven.widgets.configuration.PaymentWidgetConfiguration
import com.deuna.maven.widgets.payment_widget.PaymentWidgetCallbacks
@Composable
fun EmbeddedCheckoutScreen(
deunaSDK: DeunaSDK,
orderToken: String,
userToken: String? = null,
) {
// Retain the Deuna WebView instance across recompositions
val deunaWidget = remember { mutableStateOf<DeunaWidget?>(null) }
Column(modifier = Modifier.fillMaxSize().padding(16.dp)) {
Box(modifier = Modifier.fillMaxWidth().weight(1f)) {
AndroidView(
modifier = Modifier.fillMaxSize(),
factory = { context ->
DeunaWidget(context).apply {
this.widgetConfiguration = PaymentWidgetConfiguration(
sdkInstance = deunaSDK,
orderToken = orderToken,
userToken = userToken,
callbacks = PaymentWidgetCallbacks().apply {
onSuccess = { order ->
// YOUR CODE HERE: Handle successful payment
}
onError = { error ->
// YOUR CODE HERE: Handle payment error
}
onEventDispatch = { event, payload ->
// YOUR CODE HERE: Track analytics event
}
}
)
this.build() // Render the DEUNA widget
deunaWidget.value = this
}
}
)
}
}
// Explicitly clean up WebView resources when composable leaves composition
DisposableEffect(Unit) {
onDispose {
deunaWidget.value?.destroy()
}
}
}Auto-resize and keyboard handling
When you pass autoResizeConfig = AutoResizeConfig(initialHeightDp = 100), the widget switches to auto-resize mode: it grows and shrinks dynamically to match WebView content height, making it ideal for embedding inside a scrollable container.
- Manifest configuration: Ensure your checkout Activity is configured with
adjustResizeinAndroidManifest.xml:
<activity
android:name=".CheckoutActivity"
android:windowSoftInputMode="adjustResize" />- Compose scroll integration: Place
DeunaWidgetinside a vertical scroll container and wiresetOnScrollByCallbackto the ComposeScrollState:
@Composable
fun ScrollableCheckoutScreen(
deunaSDK: DeunaSDK,
widgetConfig: PaymentWidgetConfiguration,
) {
val scrollState = rememberScrollState()
val coroutineScope = rememberCoroutineScope()
Column(
modifier = Modifier
.fillMaxSize()
.verticalScroll(scrollState)
) {
// Content above widget...
AndroidView(
modifier = Modifier.fillMaxWidth(),
factory = { context ->
DeunaWidget(context).apply {
this.widgetConfiguration = widgetConfig
this.build()
}
},
update = { widget ->
// Wire the SDK scroll request to Compose ScrollState
widget.setOnScrollByCallback { amountPx ->
coroutineScope.launch {
scrollState.animateScrollBy(amountPx)
}
}
}
)
// Content below widget...
}
}Custom pay button (hidePayButton)
If your app renders its own native button outside the widget, pass hidePayButton = true and handle submission programmatically using isValid and submit:
PaymentWidgetConfiguration(
sdkInstance = deunaSDK,
orderToken = orderToken,
hidePayButton = true,
callbacks = callbacks
)
// When the user taps your custom native pay button:
deunaWidget.value?.isValid { isValid ->
if (isValid) {
deunaWidget.value?.submit { result ->
// result.status: "success" | "error"
// result.message: Detailed message
}
}
}| Method | Description | Return Value |
|---|---|---|
deunaWidget.isValid { valid -> ... } | Validates user input in active payment form. | Boolean |
deunaWidget.submit { result -> ... } | Submits payment equivalent to clicking the widget button. | SubmitResult (status: "success" or status: "error") |
Filter and configure payment methods#
Direct forms flow (paymentMethods)
The DEUNA checkout architectures support launching directly into an individual payment form—a pattern known as the forms flow.
While paymentMethods is typed as a list, internal checkout engines currently support only one element in this list. Supplying a single payment method opens the widget directly into that method's form (e.g. Kueski Pay BNPL), bypassing the method selector.
deunaSDK.initPaymentWidget(
context = this,
orderToken = "YOUR_ORDER_TOKEN",
callbacks = callbacks,
paymentMethods = listOf(
mapOf(
"paymentMethod" to "bnpl",
"processors" to listOf("kueski")
)
)
)Configuration priority resolution
| Priority | Source | Behavior |
|---|---|---|
| 1 (Highest) | paymentMethods in .initPaymentWidget() | Direct forms flow: Opens immediately into the single specified payment method form (e.g., Kueski), bypassing the method selector. |
| 2 | include_payment_options in order creation | Multi-method selection: Displays only the payment methods specified during order creation that are active on your account. |
| 3 (Fallback) | Merchant-level configuration (/payment-methods) | Full selector: If omitted in both SDK call and order payload, displays all active payment methods configured for your merchant account. |
PayPal configurations
Flow Type (flowType)
deunaSDK.initPaymentWidget(
context = this,
orderToken = orderToken,
behavior = WidgetBehavior(
paymentMethods = mapOf(
"flowType" to "twoStep" // "twoStep" (summary first) or "singleStep" (direct)
)
)
)Auto Purchase (express)
When customers have previously authorized quick payments with PayPal, enable immediate processing:
deunaSDK.initPaymentWidget(
context = this,
orderToken = orderToken,
callbacks = callbacks,
paymentMethods = listOf(
mapOf(
"paymentMethod" to "wallet",
"processors" to listOf("paypal_wallet"),
"configuration" to mapOf("express" to true)
)
)
)Split Payments with multiple cards
deunaSDK.initPaymentWidget(
context = this,
orderToken = orderToken,
behavior = WidgetBehavior(
paymentMethods = mapOf(
"creditCard" to mapOf(
"splitPayments" to mapOf(
"maxCards" to 2 // Maximum number of cards allowed
)
)
)
)
)Dynamic styling and order refresh#
Dynamically customize appearance (setCustomStyle)
Update widget styles dynamically (e.g. adapting branding upon card BIN detection):
callbacks = PaymentWidgetCallbacks().apply {
onCardBinDetected = { metadata, _ ->
deunaSDK.setCustomStyle(
data = mapOf(
"theme" to mapOf(
"colors" to mapOf(
"primaryTextColor" to "#023047",
"buttonPrimaryFill" to "#FFB703",
"buttonPrimaryText" to "#000000"
)
)
)
)
}
}Refresh order totals (refetchOrder)
When offering franchise-specific promotions (e.g., "20% off with Mastercard"), listen to onCardBinDetected, update the order on your backend, and notify the widget:
callbacks = PaymentWidgetCallbacks().apply {
onCardBinDetected = { metadata, _ ->
val cardBrand = metadata?.get("cardBrand") as? String
if (cardBrand == "Mastercard") {
// 1. Notify backend to apply promo
applyDiscountOnBackend(orderId, "MASTERCARD_20") {
// 2. Refresh widget totals
deunaSDK.refetchOrder { updatedOrder ->
println("Order refreshed with discount: $updatedOrder")
}
}
}
}
}Payment Vault and Click to Pay#
Payment Vault is a component of DEUNA Payment solutions that allows saving cards securely and paying via Click to Pay without processing regular checkouts.
Display in a dialog
To display Card Vault in a modal dialog, call initElements (omit types for default Vault):
import com.deuna.maven.initElements
import com.deuna.maven.shared.ElementsCallbacks
import com.deuna.maven.shared.domain.UserInfo
import com.deuna.maven.widgets.elements.ElementsWidgetExperience
deunaSDK.initElements(
context = this,
userToken = "<USER_TOKEN>", // optional if userInfo is provided
userInfo = UserInfo(
firstName = "Esteban", // optional if userToken is provided
lastName = "Posada", // optional if userToken is provided
email = "esteban@deuna.com" // required
),
callbacks = ElementsCallbacks().apply {
onSuccess = { response ->
deunaSDK.close() // Close the Vault widget
// YOUR CODE HERE: Handle card saved successfully
}
onError = { error ->
deunaSDK.close() // Close the widget on error
// YOUR CODE HERE: Handle error
}
onClosed = { action ->
// Widget closed: action == CloseAction.USER_ACTION or CloseAction.SYSTEM_ACTION
// YOUR CODE HERE: Handle widget dismissal
}
onEventDispatch = { type, response ->
// YOUR CODE HERE: Listen to widget events
}
},
orderToken = "YOUR_ORDER_TOKEN", // optional
widgetExperience = ElementsWidgetExperience( // optional
userExperience = ElementsWidgetExperience.UserExperience(
showSavedCardFlow = true, // optional: show card saving toggle
defaultCardFlow = true // optional: show toggle to save as default
)
)
)Display embedded (Jetpack Compose)
import com.deuna.maven.widgets.configuration.ElementsWidgetConfiguration
DeunaWidget(context).apply {
this.widgetConfiguration = ElementsWidgetConfiguration(
sdkInstance = deunaSDK,
orderToken = "YOUR_ORDER_TOKEN",
userInfo = UserInfo(
firstName = "Esteban",
lastName = "Posada",
email = "esteban@deuna.com"
),
callbacks = ElementsCallbacks().apply {
onSuccess = { response ->
// Explicitly release resources or update state
// YOUR CODE HERE: Handle card saved
}
onError = { error ->
// YOUR CODE HERE: Handle error
}
},
autoResizeConfig = AutoResizeConfig(initialHeightDp = 150)
)
this.build()
}Click to Pay
deunaSDK.initElements(
context = this,
userInfo = UserInfo( // mandatory for Click To Pay
firstName = "Esteban",
lastName = "Posada",
email = "esteban@deuna.com"
),
callbacks = ElementsCallbacks().apply {
onSuccess = { data ->
deunaSDK.close()
// YOUR CODE HERE: Handle Click to Pay success
}
onError = { error ->
deunaSDK.close()
// YOUR CODE HERE: Handle error
}
onClosed = { action ->
// YOUR CODE HERE: Handle widget dismissal
}
},
types = listOf(
mapOf("name" to "click_to_pay")
)
)Parameter Reference
| Parameter | Type | Dialog | Embedded | Description |
|---|---|---|---|---|
context | Context | ✅ | ❌ | Required for dialog. Activity context. |
callbacks | ElementsCallbacks | ✅ | ✅ | Required. Event listeners (onSuccess, onError, onClosed, onEventDispatch). |
userInfo | UserInfo? | ✅ | ✅ | Customer's firstName, lastName, and email. Required for Click to Pay. |
userToken | String? | ✅ | ✅ | Optional. DEUNA bearer token. If passed, omit userInfo. |
types | List<Map<String, Any>>? | ✅ | ✅ | Optional. Omit to render the default Card Vault experience. Pass listOf(mapOf("name" to "click_to_pay")) to render Click to Pay. |
orderToken | String? | ✅ | ✅ | Optional. Unique order token. Customer details can be extracted from billing_address. |
styleFile | String? | ✅ | ✅ | Optional. Theme customization UUID. |
widgetExperience | ElementsWidgetExperience? | ✅ | ✅ | Optional. showSavedCardFlow (card saving toggle) and defaultCardFlow (save as default toggle). |
domain | String? | ✅ | ✅ | Optional. Overrides host (https://elements.deuna.com). |
hidePayButton | Boolean | ❌ | ✅ | Optional. Hides button when embedded. Use isValid and submit for custom buttons. |
Native Google Pay#
Check merchant configuration and device capability before rendering a Google Pay button.
import com.deuna.maven.wallets.GetWalletsAvailableParams
import com.deuna.maven.wallets.WalletProvider
import com.deuna.maven.wallets.getWalletsAvailable
val userInfo = UserInfo(email = "ada@example.com")
val params = GetWalletsAvailableParams(
orderToken = "YOUR_ORDER_TOKEN",
userInfo = userInfo
)
deunaSDK.getWalletsAvailable(
context = this,
params = params
) { wallets, error ->
if (error != null) {
// YOUR CODE HERE: Handle wallet availability check error
return@getWalletsAvailable
}
// Check if Google Pay is available on this device and merchant account
val isGooglePayAvailable = WalletProvider.GOOGLE_PAY in wallets
// YOUR CODE HERE: Update Google Pay button visibility in UI
}After availability succeeds, launch Google Pay from the button action using initElements:
deunaSDK.initElements(
context = this,
userInfo = userInfo,
callbacks = ElementsCallbacks().apply {
onSuccess = { data ->
// YOUR CODE HERE: Handle Google Pay authorization success
}
onError = { error ->
// YOUR CODE HERE: Handle Google Pay error
}
onClosed = { action ->
// YOUR CODE HERE: Handle Google Pay sheet dismissal
}
},
types = listOf(
mapOf("name" to "GOOGLE_PAY")
),
orderToken = "YOUR_ORDER_TOKEN"
)See Google Pay for merchant enrollment and testing setup.
Continue a pending action#
Use the same order token when DEUNA reports that the payment requires a supported 3DS challenge or redirect.
import com.deuna.maven.widgets.next_action.NextActionCallbacks
deunaSDK.initNextAction(
context = this,
orderToken = "YOUR_ORDER_TOKEN",
callbacks = NextActionCallbacks().apply {
onSuccess = { order ->
deunaSDK.close()
// YOUR CODE HERE: Handle 3DS or action completion
}
onError = { error ->
deunaSDK.close()
// YOUR CODE HERE: Handle error
}
onClosed = { action ->
// YOUR CODE HERE: Handle modal dismissal
}
}
)The SDK opens supported external URLs and returns to the active widget. Use callback state for the interface and the authoritative DEUNA payment state for fulfillment.
Open a voucher#
import com.deuna.maven.widgets.voucher.VoucherCallbacks
deunaSDK.initVoucherWidget(
context = this,
orderToken = "YOUR_ORDER_TOKEN",
callbacks = VoucherCallbacks().apply {
onSuccess = { order ->
// YOUR CODE HERE: Handle voucher instructions display
}
onError = { error ->
// YOUR CODE HERE: Handle error
}
onClosed = { action ->
// YOUR CODE HERE: Handle widget dismissal
}
}
)Fraud-device data and fingerprinting#
The DEUNA Android SDK uses a modular architecture: it does not bundle third-party fraud SDKs by default. Only add the specific provider(s) you plan to use.
Supported Providers
| Provider | Gradle Dependency / AAR Placement | Required Parameters |
|---|---|---|
MERCADOPAGO | implementation("com.mercadolibre.android.device:sdk:4.0.1") | (None required - pass emptyMap()) |
RISKIFIED | implementation("com.riskified:android-sdk:1.11.0:nogoogle@aar") | storeDomain |
CYBERSOURCE | app/libs/cybersource/*.aar | orgId, merchantId (Optional: fpServer) |
SIGNIFYD | app/libs/signifyd/*.aar | orgId (Optional: fpServer) |
ACCERTIFY | app/libs/accertify/*.aar + transitive dependencies | Config files in src/main/assets/ (Optional: locationConsent, phoneConsent) |
Accertify assets and transitive dependencies
- AAR and dependencies: Place
inmobile.aarandinmobile-common.aarinapp/libs/accertify/, and add transitive dependencies:
dependencies {
implementation(fileTree(dir: "libs/accertify", include: ["*.aar"]))
implementation("io.insert-koin:koin-core:3.5.6")
implementation("androidx.biometric:biometric:1.1.0")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3")
}- Configuration Assets: Place two files inside
app/src/main/assets/:server_keys_message_hosted.json: The public encryption keys provided by Accertify.inmobile.properties: Configuration file with your merchant details:PROPERTIESregisterUrl=YOUR_INMOBILE_ENDPOINT_URL logUrl=YOUR_INMOBILE_ENDPOINT_URL accountGuid=YOUR_ACCOUNT_GUID serverKeysMessage=server_keys_message_hosted.json
Mercado Pago setup and early initialization
- Add the Mercado Libre repository in
settings.gradle.kts:
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
maven(url = "https://artifacts.mercadolibre.com/repository/android-releases/")
}
}- Add the dependency in
app/build.gradle.kts:
dependencies {
implementation("com.mercadolibre.android.device:sdk:4.0.1")
}- Pre-warm fingerprinting early: Mercado Pago requires up to 3.5 seconds to perform hardware profiling. Call
initializeFraudProvidersinApplication.onCreateorMainActivity.onCreate:
DeunaSDK.initializeFraudProviders(
context = applicationContext,
params = mapOf(
"MERCADOPAGO" to emptyMap<String, Any>()
),
onSuccess = {
// Fingerprint collected and ready in background
},
onError = { error ->
// Handle initialization error
}
)Direct call via generateFraudId
deunaSDK.generateFraudId(
context = this,
params = mapOf(
"RISKIFIED" to mapOf(
"storeDomain" to "yourdomain.com"
),
"ACCERTIFY" to mapOf(
"locationConsent" to true,
"phoneConsent" to false
),
"MERCADOPAGO" to emptyMap()
)
) { fraudId ->
// fraudId is a Base64-encoded JSON string, or null if failed
if (fraudId != null) {
println("Base64 Fraud ID: $fraudId")
}
}Pass fraudCredentials directly to widgets
When using DEUNA widgets, pass your credentials directly via fraudCredentials. The SDK generates the identifier internally at purchase time:
PaymentWidgetConfiguration(
sdkInstance = deunaSDK,
orderToken = "YOUR_ORDER_TOKEN",
callbacks = callbacks,
fraudCredentials = mapOf(
"RISKIFIED" to mapOf(
"storeDomain" to "yourdomain.com"
),
"MERCADOPAGO" to emptyMap()
)
)Behavior notes
- Zero-bloat & Crash-safe: If a provider is included in params but its native dependency was not linked, the SDK safely skips it without crashing.
- Parallel execution: All requested providers profile concurrently on background threads.
- Fallback behavior: If no valid providers are configured or available on the device,
generateFraudIdresolves tonull.
Callback and lifecycle reference#
| Callback / Method | Dialog | Embedded | Description |
|---|---|---|---|
onSuccess | ✅ | ✅ | Payment or card vault operation completed successfully. Receives order or credential payload. Call deunaSDK.close() (dialog) or destroy() (embedded). |
onError | ✅ | ✅ | Error occurred during initialization or payment processing. Receives typed PaymentsError or ElementsError. |
onClosed | ✅ | ❌ | Dialog closed. Receives CloseAction.USER_ACTION (dismissed manually) or CloseAction.SYSTEM_ACTION (closed via close()). |
onPaymentProcessing | ✅ | ✅ | Triggered when customer taps pay and payment processing begins. Use to disable buttons and show progress indicators. |
onCardBinDetected | ✅ | ✅ | Triggered when a card BIN is detected or cleared (null when user deletes the number). Use for franchise discounts. |
onInstallmentSelected | ✅ | ✅ | Triggered when customer selects deferred installments (null on full one-time payment). |
onEventDispatch | ✅ | ✅ | Emits all underlying CheckoutEvent or ElementsEvent occurrences with data payloads. |
close() | ✅ | ❌ | Dismisses the active modal dialog after external URL tabs have completed. |
destroy() | ❌ | ✅ | Cleans up the WebView resources when the containing composable unmounts. |
Handling errors (onError)
Inspect error.type to distinguish initialization failures from payment declines:
onError = { error ->
when (error.type) {
PaymentsError.Type.INITIALIZATION_FAILED -> {
// Widget failed to load; close dialog and notify user
deunaSDK.close()
}
PaymentsError.Type.PAYMENT_ERROR -> {
// Transaction declined or processor error; prompt retry
}
else -> {}
}
}Official examples and source#
See the example’s ExploreViewModel.kt for configuration factories and EmbeddedScreen.kt for WebView lifecycle handling.