Skip to main content
On this page

Use the DEUNA Android SDK to show complete Checkout, Payment Widget, Payment Vault, Click to Pay, next-action, voucher, and native Google Pay experiences in Kotlin applications. The SDK supports Android API 22 and later.

Install#

Add JitPack to dependency resolution and pin a release of the SDK.

settings.gradle.ktsKotlin
dependencyResolutionManagement {
  repositories {
    google()
    mavenCentral()
    maven(url = "https://jitpack.io")
  }
}
app/build.gradle.ktsKotlin
android {
  defaultConfig {
    minSdk = 22
  }
}

dependencies {
  implementation("com.github.deuna-developers:deunasdk:<version>")
}

Choose and pin <version> from the repository’s releases. Test upgrades in sandbox before promoting them to production.

Initialize#

Create one SDK instance with the public API key for the selected environment and retain it for the owning flow.

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

val deunaSDK = DeunaSDK(
  environment = Environment.SANDBOX,
  publicApiKey = "YOUR_PUBLIC_API_KEY",
)

For an application-wide instance, initialize the shared SDK once:

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

val deunaSDK = DeunaSDK.shared

Open Payment Widget in a modal#

Build typed callbacks and pass an Activity or another valid UI Context:

Kotlin
import com.deuna.maven.initPaymentWidget
import com.deuna.maven.widgets.payment_widget.PaymentWidgetCallbacks

val callbacks = PaymentWidgetCallbacks().apply {
  onSuccess = { order ->
    deunaSDK.close()
    showConfirmation(order)
  }
  onError = { error -> showRetry(error) }
  onClosed = { action -> showCart(action) }
  onPaymentProcessing = { disablePayButton() }
  onEventDispatch = { event, payload ->
    analytics.track(event.name, payload)
  }
}

deunaSDK.initPaymentWidget(
  context = this,
  orderToken = orderToken,
  callbacks = callbacks,
  language = "en",
)

The modal host manages the widget and redirect views. Call close() when your success or error flow is complete; it waits for an active external URL to close before releasing the widget.

Available experiences#

ExperienceMethodImportant input
Complete CheckoutinitCheckout(...)context, orderToken, CheckoutCallbacks
Payment WidgetinitPaymentWidget(...)context, orderToken, PaymentWidgetCallbacks
Payment VaultinitElements(...)context, ElementsCallbacks; types may be omitted
Click to PayinitElements(...)types = listOf(mapOf("name" to "click_to_pay"))
Next ActioninitNextAction(...)Token for the order that requires another action
VoucherinitVoucherWidget(...)Token for the voucher order

All modal methods accept optional language, fraud, custom user-agent, and domain inputs where supported. Do not override domain unless DEUNA gives you a specific integration host.

Embed a widget#

Embedded mode uses a typed configuration and DeunaWidget. This Jetpack Compose example renders Payment Widget and destroys its WebView with the screen lifecycle.

Kotlin
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.viewinterop.AndroidView
import com.deuna.maven.web_views.deuna.DeunaWidget
import com.deuna.maven.web_views.deuna.extensions.build
import com.deuna.maven.widgets.configuration.PaymentWidgetConfiguration

val configuration = remember(orderToken) {
  PaymentWidgetConfiguration(
    sdkInstance = deunaSDK,
    orderToken = orderToken,
    callbacks = callbacks,
  )
}

val widget = remember { mutableStateOf<DeunaWidget?>(null) }

AndroidView(
  factory = { context ->
    DeunaWidget(context).apply {
      widgetConfiguration = configuration
      build()
      widget.value = this
    }
  },
)

DisposableEffect(Unit) {
  onDispose { widget.value?.destroy() }
}

Call resume() and pause() when the containing lifecycle starts and stops. For a widget inside a vertically scrolling screen, pass AutoResizeConfig in the configuration and connect setOnScrollByCallback to the parent scroll state.

If your application owns the pay button, set hidePayButton = true in the configuration and call the embedded DeunaWidget extension submit { result -> ... } from the button tap.

Payment Vault and Click to Pay#

Payment Vault is the default Elements experience. Pass either an authenticated userToken or enough UserInfo to identify the customer.

Kotlin
import com.deuna.maven.initElements
import com.deuna.maven.shared.ElementsCallbacks
import com.deuna.maven.shared.domain.UserInfo

val elementsCallbacks = ElementsCallbacks().apply {
  onSuccess = { credential -> useSavedCredential(credential) }
  onError = { error -> showRetry(error) }
  onClosed = { action -> showPaymentMethods(action) }
}

deunaSDK.initElements(
  context = this,
  orderToken = orderToken,
  userInfo = UserInfo(email = "ada@example.com"),
  types = listOf(mapOf("name" to "vault")),
  callbacks = elementsCallbacks,
)

Use "click_to_pay" instead of "vault" for Click to Pay.

Native Google Pay#

Check both merchant configuration and device support before rendering your Google Pay button. The result is cached by the SDK.

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

deunaSDK.getWalletsAvailable(
  context = this,
  params = GetWalletsAvailableParams(
    orderToken = orderToken,
    userInfo = userInfo,
  ),
) { wallets, error ->
  if (error != null) {
    showWalletError(error)
    return@getWalletsAvailable
  }

  googlePayButton.isVisible = WalletProvider.GOOGLE_PAY in wallets
}

After availability succeeds, launch the sheet from the button tap. initElements requires the availability call first.

Kotlin
googlePayButton.setOnClickListener {
  deunaSDK.initElements(
    context = this,
    orderToken = orderToken,
    userInfo = userInfo,
    types = listOf(mapOf("name" to WalletProvider.GOOGLE_PAY.name)),
    callbacks = elementsCallbacks,
  )
}

See Google Pay for merchant enrollment, testing, and tokenization details.

Continue a pending action#

Use the same order token when DEUNA reports that the payment requires a supported 3DS challenge or redirect.

Kotlin
deunaSDK.initNextAction(
  context = this,
  orderToken = orderToken,
  callbacks = nextActionCallbacks,
)

The SDK opens supported external URLs and returns to the active widget. Use callback state for the interface and a verified webhook for fulfillment.

Open a voucher#

Kotlin
deunaSDK.initVoucherWidget(
  context = this,
  orderToken = orderToken,
  callbacks = voucherCallbacks,
)

Voucher callbacks follow the same success, error, close, and event-dispatch lifecycle as the other payment experiences.

Fraud-device data#

Pre-initialize configured native fraud providers early, such as in Application.onCreate, to reduce latency later in the payment flow.

Kotlin
DeunaSDK.initializeFraudProviders(
  context = applicationContext,
  params = mapOf("MERCADOPAGO" to emptyMap<String, Any>()),
  onError = { message -> logFraudError(message) },
)

Generate the combined identifier when your order or risk flow needs it:

Kotlin
deunaSDK.generateFraudId(
  context = this,
  callback = { fraudId -> attachFraudId(fraudId) },
)

Include only the fraud-provider dependencies and configuration assigned to your account. See Integrate device fingerprint.

Callback and lifecycle reference#

Callback or methodUse it for
onSuccessUpdate the interface after the experience succeeds.
onErrorHandle a typed PaymentsError or ElementsError.
onClosedDistinguish customer and SDK-controlled closure.
onEventDispatchObserve supported checkout or Elements lifecycle events.
onCardBinDetectedReact to card BIN detection in Payment Widget or Elements.
onInstallmentSelectedReact to an installment-plan selection.
onPaymentProcessingPrevent duplicate payment actions.
close()Dismiss the active modal after external views have closed.

Official examples and source#

See the example’s ExploreViewModel.kt for configuration factories and EmbeddedScreen.kt for WebView lifecycle handling.