For the complete documentation index, see llms.txt. Append
.mdto 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.
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.
| Requirement | Version |
|---|---|
| Android API level | 24 and above |
| Kotlin | 2.0 and above, with the Compose Compiler Gradle plugin |
| Jetpack Compose | Enabled in your project |
You also need a Banxa partner account, which supplies the apiKey and partnerID used to configure the SDK.
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")
}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.
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)| Method | Required | Description |
|---|---|---|
apiKey(String) | Yes | Your Banxa API key from the merchant dashboard. |
partnerID(String) | Yes | Your partner identifier. |
environment(Environment) | Yes | Environment.SANDBOX or Environment.PRODUCTION. |
primerTheme(PrimerTheme) | No | Overrides the payment sheet colour tokens. See Payment sheet theming. |
| Environment | Host |
|---|---|
Environment.SANDBOX | https://api.banxa-sandbox.com |
Environment.PRODUCTION | https://api.banxa.com |
Sandbox and production credentials are separate and are not interchangeable.
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.
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.
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.
| Callback | Fires when |
|---|---|
banxaDidReceiveCheckout | The customer completed payment. Receives a checkout result. |
banxaDidFail | Any Banxa, network, validation, or checkout failure. |
banxaDidDismiss | The customer closed the checkout UI without completing. |
| Field | Populated when |
|---|---|
paymentId | The native payment sheet was used. |
orderId | The native payment sheet was used. |
status | The native payment sheet was used. |
rawQuery | The 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.
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.
| Field | Type | Required | Description |
|---|---|---|---|
paymentMethodId | String | Yes | Banxa payment method id, for example google-pay. |
crypto | String | Yes | Crypto asset symbol, for example ETH. |
fiat | String | Yes | Fiat currency code, for example EUR. |
fiatAmount | String | Yes | Fiat amount as a string. |
walletAddress | String | Yes | Destination wallet address. |
email | String | Yes | Customer email address. |
redirectUrl | String | Yes | URL the customer returns to after the fallback flow. |
id | String? | No | Your order id. |
blockchain | String? | No | Explicit blockchain network. |
cryptoAmount | String? | No | Crypto amount when ordering by crypto value. |
walletAddressTag | String? | No | Tag or memo for chains that require it. |
subPartnerId | String? | No | Sub-partner identifier. |
metadata | String? | No | Opaque metadata string. |
externalCustomerId | String? | No | Your customer identifier. Pass the same value you use as identityReference. |
externalOrderId | String? | No | Your order reference. |
discountCode | String? | No | Promotion or discount code. |
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.
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)
)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 field | Type | Notes |
|---|---|---|
id | String | Payment method id, for example apple-pay. |
name | String | Display name. |
description | String? | Human-readable description. |
supportedFiats | List<String> | Fiat codes available for this method. |
val result = repository.getCountries(
partner = config.partner,
apiKey = config.apiKey
)| Type | Fields |
|---|---|
Country | id, description, states: List<CountryState> |
CountryState | id, description |
The country list is the same for buy and sell.
val result = repository.getFiats(
partner = config.partner,
apiKey = config.apiKey,
orderType = "buy"
)| Type | Fields |
|---|---|
Fiat | id, description, symbol?, supportedPaymentMethods: List<FiatPaymentMethod> |
FiatPaymentMethod | id, name, minimum?, maximum? |
val result = repository.getCrypto(
partner = config.partner,
apiKey = config.apiKey,
orderType = "buy"
)| Type | Fields |
|---|---|
Crypto | id, description, blockchains: List<Blockchain> |
Blockchain | id, 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.
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 field | Type | Required | Notes |
|---|---|---|---|
fiat | String | Yes | Fiat currency code. |
crypto | String | Yes | Crypto asset symbol. |
blockchain | String | Yes | Blockchain network. |
paymentMethodId | String | Yes | Payment method id. |
fiatAmount | String? | Conditional | Provide this or cryptoAmount. |
cryptoAmount | String? | Conditional | Provide this or fiatAmount. |
externalCustomerId | String? | No | Your customer identifier. |
ipAddress | String? | No | Customer IP for regional pricing. |
discountCode | String? | No | Promotion or discount code. |
Quote field | Type | Notes |
|---|---|---|
paymentMethodId | String | Payment method the quote applies to. |
cryptoAmount | String | Crypto the customer receives. |
fiatAmount | String | Fiat the customer spends. |
processingFee | String? | Banxa processing fee in fiat. |
networkFee | String? | Blockchain network fee in fiat. |
discount | QuoteDiscount? | 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.
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.
| Capability | Use instead |
|---|---|
| Identity creation, KYC sharing, document sharing | Native 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 reconciliation | Webhooks and the Native API |
| Off-ramp (sell) | Native API. The SDK covers on-ramp payment execution only |
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.
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 id | Supported fiats |
|---|---|
debit-credit-card | AED, 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-pay | AUD, EUR, USD |
apple-pay | AUD, EUR, GBP, USD |
payid-bank-transfer | AUD |
pix | BRL |
zar-bank-transfer | ZAR |
pse | COP |
khipu | CLP |
interac-bank-transfer | CAD |
klarna-paynow | EUR |
ideal-bank-transfer | AUD, EUR |
sepa-bank-transfer | EUR |
gbp-bank-transfer | GBP |
spei | MXN |
- Integration Guide: end-to-end walkthrough.
- Google Pay: app approval and platform setup.
- Cards: 3D Secure setup.
- Interpreting Eligibility: the requirements dictionary and remediation loop.