Skip to main content
On this page

Requirements#

To integrate the DEUNA Android SDK, make sure your project meets the following requirements:

  • Minimum SDK version: minSdkVersion 24 or 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")
    }
}

If your project does not use dependencyResolutionManagement, add the repository in the root build.gradle:

build.gradleGROOVY
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")
}

Initialize#

Kotlin
import com.deuna.maven.DeunaSDK
import com.deuna.maven.shared.Environment

You 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):

Kotlin
DeunaSDK.initialize(
    environment = Environment.SANDBOX, // Environment.SANDBOX or Environment.PRODUCTION
    publicApiKey = "YOUR_PUBLIC_API_KEY"
)

val deunaSDK = DeunaSDK.shared

Flow or screen instance

Create an instance for a specific checkout screen or ViewModel:

Kotlin
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:

Kotlin
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

ParameterTypeDialogEmbeddedDescription
contextContext✅❌Required for dialog. Activity context providing UI resources and window token.
orderTokenString✅✅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.
callbacksPaymentWidgetCallbacks✅✅Required. Event listeners (onSuccess, onError, onClosed, onCardBinDetected, onInstallmentSelected, onPaymentProcessing, onEventDispatch).
userTokenString?✅✅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.
styleFileString?✅✅Optional. UUID provided by DEUNA to apply custom theme branding (colors, typography, logo).
paymentMethodsList<Map<String, Any>>?✅✅Optional. Single payment method list for direct forms flow (e.g. listOf(mapOf("paymentMethod" to "bnpl", "processors" to listOf("kueski")))).
languageString?✅✅Optional. Language code ("es", "en", "pt"). Overrides merchant default configuration.
behaviorWidgetBehavior?✅✅Optional. Flow customization, such as WidgetBehavior(paymentMethods = mapOf("flowType" to "twoStep")) for PayPal, or Split Payments splitPayments.
fraudCredentialsMap<String, Any>?✅✅Optional. Anti-fraud provider credentials (e.g. mapOf("RISKIFIED" to mapOf("storeDomain" to "example.com"))).
domainString?✅✅Optional. Overrides default base host (https://pay.deuna.io).
hidePayButtonBoolean❌✅Optional. Hides the built-in pay button in embedded mode when your application renders a native button.

Available experiences#

ExperienceMethodConfiguration typeImportant input
Payment WidgetinitPaymentWidget(...)PaymentWidgetConfigurationcontext, orderToken, PaymentWidgetCallbacks
Payment VaultinitElements(...)ElementsWidgetConfigurationcontext, ElementsCallbacks; types may be omitted
Click to PayinitElements(...)ElementsWidgetConfigurationtypes = listOf(mapOf("name" to "click_to_pay"))
Next ActioninitNextAction(...)NextActionWidgetConfigurationcontext, orderToken, NextActionCallbacks
VoucherinitVoucherWidget(...)VoucherWidgetConfigurationcontext, 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.

Kotlin
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.

  1. Manifest configuration: Ensure your checkout Activity is configured with adjustResize in AndroidManifest.xml:
AndroidManifest.xmlXML
<activity
    android:name=".CheckoutActivity"
    android:windowSoftInputMode="adjustResize" />
  1. Compose scroll integration: Place DeunaWidget inside a vertical scroll container and wire setOnScrollByCallback to the Compose ScrollState:
Kotlin
@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:

Kotlin
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
        }
    }
}
MethodDescriptionReturn 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.

Kotlin
deunaSDK.initPaymentWidget(
    context = this,
    orderToken = "YOUR_ORDER_TOKEN",
    callbacks = callbacks,
    paymentMethods = listOf(
        mapOf(
            "paymentMethod" to "bnpl",
            "processors" to listOf("kueski")
        )
    )
)

Configuration priority resolution

PrioritySourceBehavior
1 (Highest)paymentMethods in .initPaymentWidget()Direct forms flow: Opens immediately into the single specified payment method form (e.g., Kueski), bypassing the method selector.
2include_payment_options in order creationMulti-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)

Kotlin
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:

Kotlin
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

Kotlin
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):

Kotlin
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:

Kotlin
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):

Kotlin
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)

Kotlin
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

Kotlin
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

ParameterTypeDialogEmbeddedDescription
contextContext✅❌Required for dialog. Activity context.
callbacksElementsCallbacks✅✅Required. Event listeners (onSuccess, onError, onClosed, onEventDispatch).
userInfoUserInfo?✅✅Customer's firstName, lastName, and email. Required for Click to Pay.
userTokenString?✅✅Optional. DEUNA bearer token. If passed, omit userInfo.
typesList<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.
orderTokenString?✅✅Optional. Unique order token. Customer details can be extracted from billing_address.
styleFileString?✅✅Optional. Theme customization UUID.
widgetExperienceElementsWidgetExperience?✅✅Optional. showSavedCardFlow (card saving toggle) and defaultCardFlow (save as default toggle).
domainString?✅✅Optional. Overrides host (https://elements.deuna.com).
hidePayButtonBoolean❌✅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.

Kotlin
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:

Kotlin
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.

Kotlin
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#

Kotlin
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

ProviderGradle Dependency / AAR PlacementRequired Parameters
MERCADOPAGOimplementation("com.mercadolibre.android.device:sdk:4.0.1")(None required - pass emptyMap())
RISKIFIEDimplementation("com.riskified:android-sdk:1.11.0:nogoogle@aar")storeDomain
CYBERSOURCEapp/libs/cybersource/*.aarorgId, merchantId (Optional: fpServer)
SIGNIFYDapp/libs/signifyd/*.aarorgId (Optional: fpServer)
ACCERTIFYapp/libs/accertify/*.aar + transitive dependenciesConfig files in src/main/assets/ (Optional: locationConsent, phoneConsent)

Accertify assets and transitive dependencies

  1. AAR and dependencies: Place inmobile.aar and inmobile-common.aar in app/libs/accertify/, and add transitive dependencies:
app/build.gradleGROOVY
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")
}
  1. 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:
      PROPERTIES
      registerUrl=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

  1. Add the Mercado Libre repository in settings.gradle.kts:
settings.gradle.ktsKotlin
dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()
        maven(url = "https://artifacts.mercadolibre.com/repository/android-releases/")
    }
}
  1. Add the dependency in app/build.gradle.kts:
app/build.gradle.ktsKotlin
dependencies {
    implementation("com.mercadolibre.android.device:sdk:4.0.1")
}
  1. Pre-warm fingerprinting early: Mercado Pago requires up to 3.5 seconds to perform hardware profiling. Call initializeFraudProviders in Application.onCreate or MainActivity.onCreate:
Kotlin
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

Kotlin
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:

Kotlin
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, generateFraudId resolves to null.

Callback and lifecycle reference#

Callback / MethodDialogEmbeddedDescription
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:

Kotlin
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.

In this section