Skip to content
Last updated

Android SDK Reference

For the complete documentation index, see llms.txt. Append .md to any page URL for its markdown version.

The Banxa Android SDK (BanxaPaymentSDK) is the payment execution layer of Banxa Native for native Android apps. It is the Kotlin counterpart to the React Native SDK: used alongside the Native API to present the native payment sheet for cards, Apple Pay, and Google Pay, the payment methods that cannot be handled through the API alone due to PCI requirements.

Bank transfers are handled directly by the Native API and do not involve the SDK. For the end-to-end integration walkthrough, see the Integration Guide.


Which parts are relevant for Banxa Native

Your backend still owns orchestration

In a Banxa Native integration your backend handles pricing, identity, and eligibility through the Native API. The SDK's role is limited to payment execution: the StartPayment composable and its callback lambdas.

The SDK also ships configuration and quote helpers. Prefer the equivalent Native API endpoints for those, so that configuration and pricing stay on one authenticated surface. The helpers are documented below for completeness.


Requirements

RequirementVersion
Android API level24 and above
Kotlin2.0 and above, with the Compose Compiler Gradle plugin
Jetpack ComposeEnabled in your project

You also need a Banxa partner account, which supplies the apiKey and partnerID used to configure the SDK.


Installation

The Android SDK is published to Maven Central. Add the dependency to your module's Gradle build file.

dependencies {
    implementation("com.banxa.nativepaymentssdk:android-payments-sdk:1.0.0")
}
Maven Central

The SDK is published to Maven Central as com.banxa.nativepaymentssdk:android-payments-sdk. Make sure mavenCentral() is listed in your repositories block. Check the Maven Central listing for the current version before pinning.


Configuration

Build a BanxaConfig and initialise the SDK once at app launch.

val config = BanxaConfig.Builder()
    .apiKey("YOUR_API_KEY")
    .partnerID("your-partner-id")
    .environment(Environment.SANDBOX)
    .build()

Banxa.initialize(config)

BanxaConfig.Builder

MethodRequiredDescription
apiKey(String)YesYour Banxa API key from the merchant dashboard.
partnerID(String)YesYour partner identifier.
environment(Environment)YesEnvironment.SANDBOX or Environment.PRODUCTION.
primerTheme(PrimerTheme)NoOverrides the payment sheet colour tokens. See Payment sheet theming.

Environments

EnvironmentHost
Environment.SANDBOXhttps://api.banxa-sandbox.com
Environment.PRODUCTIONhttps://api.banxa.com

Sandbox and production credentials are separate and are not interchangeable.


Starting a payment

StartPayment is a composable. Render it when the customer confirms, and supply the callback lambdas you need.

StartPayment(
    createOrderRequest = CreateOrderRequest(
        fiat = "EUR",
        crypto = "ETH",
        fiatAmount = "40",
        cryptoAmount = null,
        walletAddress = "0x0000000000000000000000000000000000000000",
        redirectUrl = "your-app-scheme://banxa-return",
        paymentMethodId = "debit-credit-card",
        email = "[email protected]"
    ),
    banxaDidReceiveCheckout = { result ->
        // Payment succeeded.
        println("Paid: ${result.paymentId ?: result.rawQuery ?: "-"}")
    },
    banxaDidFail = { error ->
        // Any failure: API, validation, network, decoding, or checkout error.
        println("Failed: $error")
    },
    banxaDidDismiss = {
        // The customer closed the checkout UI without completing.
    }
)

StartPayment runs the full pipeline: it checks eligibility, creates the order, and presents the native payment sheet when a payment token is available. All callbacks have a default no-op implementation, so supply only what you need.

Gate on eligibility before you render StartPayment

Call POST /eapi/v0/eligibility from your backend and confirm paymentReady: true before invoking the SDK. The SDK performs its own internal eligibility check, but it does not expose the result or the requirements[] array to your app, so it cannot tell your user what is outstanding. Without the backend check you have no way to drive the KYC remediation loop.

See Interpreting Eligibility.

The SDK does not accept a quoteId. Use indicative pricing from GET /eapi/v0/price and re-price close to the point of payment to reduce rate drift.


Callbacks

CallbackFires when
banxaDidReceiveCheckoutThe customer completed payment. Receives a checkout result.
banxaDidFailAny Banxa, network, validation, or checkout failure.
banxaDidDismissThe customer closed the checkout UI without completing.

Checkout result

FieldPopulated when
paymentIdThe native payment sheet was used.
orderIdThe native payment sheet was used.
statusThe native payment sheet was used.
rawQueryThe fallback flow was used. Contains the terminal success URL query string.

Callbacks are a UI signal, not the authoritative order state. Confirm the final state from webhooks before you credit a customer.


Payment sheet theming

Pass a PrimerTheme to the config builder to override the payment sheet colour tokens.

val primerTheme = PrimerTheme(
    lightColorTokens = object : LightColorTokens() {
        override val primerColorBrand: Color = Color(0xFF6C5CE7)
        override val primerColorTextPrimary: Color = Color(0xFFD32E2E)
        override val primerColorBackground: Color = Color(0xFF9CFFA1)
    },
)

val config = BanxaConfig.Builder()
    .apiKey("YOUR_API_KEY")
    .partnerID("your-partner-id")
    .environment(Environment.SANDBOX)
    .primerTheme(primerTheme)
    .build()

Banxa.initialize(config)

Theming is optional. Without it, the payment sheet uses the default token set.


Models

CreateOrderRequest

FieldTypeRequiredDescription
paymentMethodIdStringYesBanxa payment method id, for example google-pay.
cryptoStringYesCrypto asset symbol, for example ETH.
fiatStringYesFiat currency code, for example EUR.
fiatAmountStringYesFiat amount as a string.
walletAddressStringYesDestination wallet address.
emailStringYesCustomer email address.
redirectUrlStringYesURL the customer returns to after the fallback flow.
idString?NoYour order id.
blockchainString?NoExplicit blockchain network.
cryptoAmountString?NoCrypto amount when ordering by crypto value.
walletAddressTagString?NoTag or memo for chains that require it.
subPartnerIdString?NoSub-partner identifier.
metadataString?NoOpaque metadata string.
externalCustomerIdString?NoYour customer identifier. Pass the same value you use as identityReference.
externalOrderIdString?NoYour order reference.
discountCodeString?NoPromotion or discount code.
A missing memo can permanently lose funds

XRP, XLM, EOS, and ATOM require a memo or tag. Pass it as walletAddressTag. An on-ramp to one of these chains without the memo can be unrecoverable.


Configuration endpoints

These helpers return a Result and require an initialised SDK. In a Banxa Native integration, prefer the equivalent Native API endpoints so that configuration stays on the HMAC-authenticated surface.

val repository = BanxaRepository(
    RetrofitClient.getApi(config.baseUrl, config.environment)
)

Payment methods

val result = repository.getPaymentMethods(
    partner = config.partner,
    apiKey = config.apiKey,
    orderType = "buy",
    fiat = "USD" // optional
)

result.onSuccess { methods ->
    methods.forEach { method ->
        println("${method.id}: ${method.name}")
    }
}
PaymentMethod fieldTypeNotes
idStringPayment method id, for example apple-pay.
nameStringDisplay name.
descriptionString?Human-readable description.
supportedFiatsList<String>Fiat codes available for this method.

Countries

val result = repository.getCountries(
    partner = config.partner,
    apiKey = config.apiKey
)
TypeFields
Countryid, description, states: List<CountryState>
CountryStateid, description

The country list is the same for buy and sell.

Fiats

val result = repository.getFiats(
    partner = config.partner,
    apiKey = config.apiKey,
    orderType = "buy"
)
TypeFields
Fiatid, description, symbol?, supportedPaymentMethods: List<FiatPaymentMethod>
FiatPaymentMethodid, name, minimum?, maximum?

Cryptocurrencies

val result = repository.getCrypto(
    partner = config.partner,
    apiKey = config.apiKey,
    orderType = "buy"
)
TypeFields
Cryptoid, description, blockchains: List<Blockchain>
Blockchainid, description, isDefaultBlockchain, address?, network?, minimum?, unsupportedCountries: Map<String, List<String>>

In unsupportedCountries, the key is a country code and the value is the restricted state codes. An empty list means the whole country is restricted.

Quotes

val result = repository.getQuote(
    partner = config.partner,
    apiKey = config.apiKey,
    orderType = "buy",
    request = QuoteRequest(
        fiat = "AUD",
        crypto = "ETH",
        blockchain = "ETH",
        paymentMethodId = "debit-credit-card",
        fiatAmount = "200"
    )
)
QuoteRequest fieldTypeRequiredNotes
fiatStringYesFiat currency code.
cryptoStringYesCrypto asset symbol.
blockchainStringYesBlockchain network.
paymentMethodIdStringYesPayment method id.
fiatAmountString?ConditionalProvide this or cryptoAmount.
cryptoAmountString?ConditionalProvide this or fiatAmount.
externalCustomerIdString?NoYour customer identifier.
ipAddressString?NoCustomer IP for regional pricing.
discountCodeString?NoPromotion or discount code.
Quote fieldTypeNotes
paymentMethodIdStringPayment method the quote applies to.
cryptoAmountStringCrypto the customer receives.
fiatAmountStringFiat the customer spends.
processingFeeString?Banxa processing fee in fiat.
networkFeeString?Blockchain network fee in fiat.
discountQuoteDiscount?Present when a discount code was applied.

Quotes carry no quote id and are not accepted by StartPayment. Do not cache them: call immediately before showing a price.


Error handling

Failures are surfaced through banxaDidFail. Banxa-originated failures are APIError, covering invalid URL, non-2xx server response, unauthorised (401), decoding failure, no network connectivity, missing credentials, uninitialised SDK, checkout failure, and unknown.

Show user-facing messages only from validated error fields. Do not expose raw error strings that may include internal detail.


Not available in the SDK

CapabilityUse instead
Identity creation, KYC sharing, document sharingNative API. See Identity and KYC
Eligibility result and requirements[]POST /eapi/v0/eligibility from your backend
Locked pricing (quoteId)Bank transfer ramps only. See Quotes and Pricing
Order lookup and reconciliationWebhooks and the Native API
Off-ramp (sell)Native API. The SDK covers on-ramp payment execution only

Google Pay approval

When your Android app presents Google Pay, Google requires app-level approval before you can process live payments. Banxa's own approval does not cover payments presented inside your app. Start the approval process early: it is the most common cause of a delayed Android launch. See the Google Pay guide.


Payment methods and supported fiats

Availability varies by partner, region, and order type. Treat getPaymentMethods or the Native API configuration endpoints as the source of truth. The table below is a static reference.

Payment method idSupported fiats
debit-credit-cardAED, ARS, AUD, BRL, CAD, CHF, CZK, DKK, EUR, GBP, HKD, IDR, INR, JPY, KRW, MXN, MYR, NGN, NOK, NZD, PHP, PLN, QAR, RUB, SAR, SEK, SGD, THB, TRY, TWD, USD, VND, ZAR
google-payAUD, EUR, USD
apple-payAUD, EUR, GBP, USD
payid-bank-transferAUD
pixBRL
zar-bank-transferZAR
pseCOP
khipuCLP
interac-bank-transferCAD
klarna-paynowEUR
ideal-bank-transferAUD, EUR
sepa-bank-transferEUR
gbp-bank-transferGBP
speiMXN

Next steps