Skip to content

Repository files navigation

Xendit Components Android

A drop-in payment UI SDK for Android that lets you accept payments through Xendit with minimal integration effort. Present a fully featured payment sheet in just a few lines of code.

Build Status Version License Platform

Features

  • Pre-built payment sheet — Full payment UI with channel selection, form validation, and error handling out of the box.
  • 3DS & redirect handling — Built-in WebView for 3D Secure challenges and redirect-based payment flows.
  • Customizable appearance — Configure colors, fonts, and corner radius to match your brand.
  • Jetpack Compose native — Built entirely with Material 3 and modern Compose components.
  • Secure by default — Client-side encryption of sensitive card data using ECDH + AES-GCM.

Requirements

Requirement Minimum
Android API 26 (Android 8.0)
Compile SDK 37
Kotlin 2.4+
Compose Bom 2026.05.01+

Getting Started

Quick Start (Kotlin)

import co.xendit.components.XenditComponents
import co.xendit.components.data.model.XenditPaymentResult

// 1. Initialize once at app startup (Application class or main Activity)
XenditComponents.initialize(appearance = XenditAppearance())

// 2. Present the payment sheet from a ComponentActivity
XenditComponents.present(
    activity = this,
    componentsSdkKey = "<your_components_sdk_key>"
) { result ->
    when (result) {
        is XenditPaymentResult.Success ->
            println("Payment succeeded: ${result.paymentRequestId}")
        is XenditPaymentResult.Failed ->
            println("Payment failed: ${result.error.message}")
        is XenditPaymentResult.Canceled ->
            println("Session canceled")
        is XenditPaymentResult.Expired ->
            println("Session expired")
        is XenditPaymentResult.Dismissed ->
            println("User dismissed")
    }
}

Quick Start (Java)

import co.xendit.components.XenditComponents;
import co.xendit.components.data.model.XenditPaymentResult;
import co.xendit.components.ui.style.XenditAppearance;

// 1. Initialize once at app startup
XenditComponents.INSTANCE.initialize(new XenditAppearance(), null);

// 2. Present the payment sheet from a ComponentActivity
XenditComponents.INSTANCE.present(
    this,
    "<your_components_sdk_key>",
    null,
    result -> {
        if (result instanceof XenditPaymentResult.Success) {
            XenditPaymentResult.Success success = (XenditPaymentResult.Success) result;
            System.out.println("Paid: " + success.getPaymentRequestId());
        } else if (result instanceof XenditPaymentResult.Failed) {
            XenditPaymentResult.Failed failed = (XenditPaymentResult.Failed) result;
            System.out.println("Error: " + failed.getError().getMessage());
        }
    }
);

The components_sdk_key is obtained from the Create Session API response on your backend.

Payment Method Preference

Merchants can control which payment methods are shown in the payment sheet by passing merchantPreferredPaymentMethod.

The SDK currently supports filtering to these payment methods only:

  • XenditComponentsPaymentType.CARDS
  • XenditComponentsPaymentType.EWALLET
  • XenditComponentsPaymentType.QR_CODE

Set It Globally During Initialization

Use this when you want the same payment method preference for every present() call.

import co.xendit.components.XenditComponents
import co.xendit.components.XenditComponentsPaymentType
import co.xendit.components.ui.style.XenditAppearance

XenditComponents.initialize(
    appearance = XenditAppearance(),
    merchantPreferredPaymentMethod = listOf(
        XenditComponentsPaymentType.CARDS,
        XenditComponentsPaymentType.EWALLET
    )
)

Override It Per Session

Use this when the payment methods should vary depending on the checkout flow.

import co.xendit.components.XenditComponents
import co.xendit.components.XenditComponentsPaymentType

XenditComponents.present(
    activity = this,
    componentsSdkKey = "<your_components_sdk_key>",
    merchantPreferredPaymentMethod = listOf(
        XenditComponentsPaymentType.QR_CODE
    )
) { result ->
    // handle result
}

Java

import java.util.Arrays;
import java.util.Collections;
import co.xendit.components.XenditComponents;
import co.xendit.components.XenditComponentsPaymentType;
import co.xendit.components.ui.style.XenditAppearance;

XenditComponents.INSTANCE.initialize(
    new XenditAppearance(),
    Arrays.asList(
        XenditComponentsPaymentType.CARDS,
        XenditComponentsPaymentType.EWALLET
    )
);

XenditComponents.INSTANCE.present(
    this,
    "<your_components_sdk_key>",
    Collections.singletonList(XenditComponentsPaymentType.QR_CODE),
    result -> {
        // handle result
    }
);

Note: Although XenditComponentsPaymentType includes other enum values, only CARDS, EWALLET, and QR_CODE are currently supported for merchant preference in the Android SDK. Unsupported values are ignored, and if no supported preference remains, the SDK falls back to the supported payment methods available in the session.

Appearance Customization

Use XenditAppearance to match the payment sheet to your app's brand. All color properties have built-in defaults — pass only the values you want to override.

Property Reference

Property Type Default Description
fontFamily FontFamily? null Custom font family for all text. Falls back to the bundled Inter font.
colorPrimary Color #0052FF Primary CTA color — pay button, selected states, checkmarks.
colorText Color #1A1C1E Main body text color.
colorTextSecondary Color #6B7280 Subtitle and caption text color.
colorTextPlaceholder Color #9CA3AF Placeholder text inside input fields.
colorDisabled Color #E5E7EB Background of disabled buttons and controls.
colorDanger Color #BA1A1A Error messages and invalid field borders.
colorBorder Color #E6E6E6 Input field outlines and dividers.
colorBackground Color #FFFFFF Sheet and page background.
qrForegroundColor Color #000000 Tint of the container shown around the QR code image.
qrBackgroundColor Color #FFFFFF Background of the container box behind the QR code image.
borderRadius Dp 8.dp Corner radius for buttons, fields, and cards.

Kotlin

import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.unit.dp
import co.xendit.components.XenditComponents
import co.xendit.components.ui.style.XenditAppearance

val customFont = FontFamily(
    Font(R.font.your_font_regular,   FontWeight.Normal,   FontStyle.Normal),
    Font(R.font.your_font_medium,    FontWeight.Medium,   FontStyle.Normal),
    Font(R.font.your_font_semibold,  FontWeight.SemiBold, FontStyle.Normal),
    Font(R.font.your_font_bold,      FontWeight.Bold,     FontStyle.Normal)
)

val appearance = XenditAppearance(
    fontFamily            = customFont,
    colorPrimary          = Color(0xFF0052FF),
    colorText             = Color(0xFF1A1C1E),
    colorTextSecondary    = Color(0xFF6B7280),
    colorTextPlaceholder  = Color(0xFF9CA3AF),
    colorDisabled         = Color(0xFFE5E7EB),
    colorDanger           = Color(0xFFBA1A1A),
    colorBorder           = Color(0xFFE6E6E6),
    colorBackground       = Color(0xFFFFFFFF),
    qrForegroundColor     = Color(0xFF000000),
    qrBackgroundColor     = Color(0xFFFFFFFF),
    borderRadius          = 12.dp
)

XenditComponents.initialize(appearance = appearance)

XenditComponents.present(
    activity = this,
    componentsSdkKey = "<your_components_sdk_key>"
) { result ->
    when (result) {
        is XenditPaymentResult.Success ->
            println("Payment succeeded: ${result.paymentRequestId}")
        is XenditPaymentResult.Failed ->
            println("Payment failed: ${result.error.message}")
        is XenditPaymentResult.Canceled ->
            println("Session canceled")
        is XenditPaymentResult.Expired ->
            println("Session expired")
        is XenditPaymentResult.Dismissed ->
            println("User dismissed")
    }
}

Java

import androidx.compose.ui.graphics.Color;
import androidx.compose.ui.text.font.Font;
import androidx.compose.ui.text.font.FontFamily;
import androidx.compose.ui.text.font.FontWeight;
import androidx.compose.ui.unit.DpKt;
import co.xendit.components.XenditComponents;
import co.xendit.components.data.model.XenditPaymentResult;
import co.xendit.components.ui.style.XenditAppearance;
import java.util.Arrays;

FontFamily customFont = new FontFamily(Arrays.asList(
    new Font(R.font.your_font_regular,  FontWeight.Companion.getNormal(),   FontStyle.Companion.getNormal()),
    new Font(R.font.your_font_semibold, FontWeight.Companion.getSemiBold(), FontStyle.Companion.getNormal()),
    new Font(R.font.your_font_bold,     FontWeight.Companion.getBold(),     FontStyle.Companion.getNormal())
));

XenditAppearance appearance = new XenditAppearance(
    customFont,
    new Color(0xFF0052FFL),  // colorPrimary
    new Color(0xFF1A1C1EL),  // colorText
    new Color(0xFF6B7280L),  // colorTextSecondary
    new Color(0xFF9CA3AFL),  // colorTextPlaceholder
    new Color(0xFFE5E7EBL),  // colorDisabled
    new Color(0xFFBA1A1AL),  // colorDanger
    new Color(0xFFE6E6E6L),  // colorBorder
    new Color(0xFFFFFFFFL),  // colorBackground
    new Color(0xFF000000L),  // qrForegroundColor
    new Color(0xFFFFFFFFL),  // qrBackgroundColor
    DpKt.getDp(12)           // borderRadius
);

XenditComponents.INSTANCE.initialize(appearance);

XenditComponents.INSTANCE.present(
    this,
    "<your_components_sdk_key>",
    null,
    result -> {
        if (result instanceof XenditPaymentResult.Success) {
            String id = ((XenditPaymentResult.Success) result).getPaymentRequestId();
            System.out.println("Paid: " + id);
        } else if (result instanceof XenditPaymentResult.Failed) {
            String msg = ((XenditPaymentResult.Failed) result).getError().getMessage();
            System.out.println("Error: " + msg);
        }
    }
);

Tip: XenditComponents.initialize() can be called multiple times. Each call replaces the active appearance for all subsequent present() calls, allowing runtime theme switching without restarting the session.

Dismissing Manually

XenditComponents.dismiss()

Calling dismiss() triggers the onPaymentResult callback with XenditPaymentResult.Canceled and removes the payment UI from the activity.

Installation

Gradle (Kotlin DSL)

Add Maven Central to your settings.gradle.kts if not already present:

dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()
    }
}

Then add the dependency to your app module's build.gradle.kts:

dependencies {
    implementation("co.xendit:components:1.0.0")
}

Gradle (Groovy DSL)

dependencies {
    implementation 'co.xendit:components:1.0.0'
}

Documentation & Examples

Resource Description
API Reference Full API documentation for session creation and payment flows.
Example App Sample Jetpack Compose app demonstrating SDK integration.

Privacy

See PRIVACY.md for a full breakdown of data collected, how it is used, whether it is linked to the end user's identity, and whether it is used for tracking — formatted for Google Play Data Safety.

License

Xendit Components Android is available under the Apache License 2.0. See the LICENSE file for more info.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages