Skip to content
Last updated

Android SDK Integration Guide

This guide walks through a complete Banxa Hosted Checkout integration in a native Android app using the Banxa Android SDK. By the end you will have a working buy flow: initialise the SDK once, render the StartPayment composable when the customer confirms, and confirm the final order status from your backend.

The Android SDK is headless and Compose-first. There is no Banxa Activity to launch and no WebView for you to manage. You supply an order request and callback lambdas, and the SDK presents checkout and reports the outcome.

For the full API surface, see the Android SDK Reference.


Before you start

Prerequisites

  • A native Android app on API level 24 or above, using Kotlin 2.0 or above with the Compose Compiler Gradle plugin.
  • Jetpack Compose enabled in your project. The SDK's payment entry point is a composable.
  • Your Banxa partner reference and API key. Use sandbox for development, production after approval.
  • A configured webhook endpoint. Optional but recommended for order status tracking.

Install the SDK

The Android SDK is distributed as an AAR. Copy it into your module's libs directory and reference it from your Gradle build file.

dependencies {
    implementation(files("libs/BanxaPayment-1.0.0.aar"))
}
AAR distribution

The Android SDK is not currently published to a Maven repository, so it does not resolve by coordinate and does not update through your dependency manager. Contact Banxa to obtain the AAR and to be notified when a new version is released.


Step 1: Initialise the SDK

Build a BanxaConfig and initialise once at app launch.

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

Banxa.initialize(config)
FieldDescription
apiKeyYour v2 API key from the merchant dashboard.
partnerIDYour partner identifier.
environmentEnvironment.SANDBOX or Environment.PRODUCTION. Credentials are not interchangeable.

Step 2: Get a quote

Fetch live pricing before you show an amount to the customer. Call this close to when the price is displayed, because crypto rates move quickly and quotes are indicative.

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

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

result.onSuccess { quote ->
    println("Pay ${quote.fiatAmount}, receive ${quote.cryptoAmount}")
    println("Fees: processing=${quote.processingFee}, network=${quote.networkFee}")
}

Provide either fiatAmount or cryptoAmount. Quotes carry no quote id, so there is nothing to pass into the payment call.

Use the same repository to populate your currency and payment method selectors at runtime rather than hardcoding values. See the Android SDK Reference.


Step 3: Start the payment

Render the StartPayment composable when the customer confirms.

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. Confirm the authoritative state from your backend.
    },
    banxaDidFail = { error ->
        // API, validation, network, decoding, or checkout failure.
    },
    banxaDidDismiss = {
        // The customer closed checkout without completing.
    }
)

Required fields

FieldNotes
fiat, crypto, fiatAmountThe order amounts and assets.
paymentMethodIdThe payment method to use.
walletAddressThe customer's receiving wallet address.
emailThe customer's email address.
redirectUrlWhere the customer returns after checkout.

Pass externalCustomerId as well. It is your stable per-customer identifier, and Banxa uses it to recognise returning customers so they do not repeat KYC.

Do not create orders in advance

StartPayment creates the order and presents checkout together, which keeps the order inside the one-minute window in which Banxa checkout must be loaded. Render it at the moment the customer confirms. There is no supported pattern for creating an order early and presenting it later.

A missing memo can permanently lose funds

XRP, XLM, EOS, and ATOM require a memo or tag. Pass it as walletAddressTag on CreateOrderRequest.


Step 4: Handle the outcome

All three callbacks have a default no-op implementation, so supply only what you need.

CallbackFires when
banxaDidReceiveCheckoutThe customer completed payment.
banxaDidFailAny Banxa, network, validation, or checkout failure.
banxaDidDismissThe customer closed checkout without completing.

banxaDidReceiveCheckout is a UI signal, not the authoritative order state. Do not credit the customer on it.


Step 5: Confirm order status

The SDK does not expose order lookup. Confirm the final state from your backend using the Banxa API.

Only terminal statuses are final. Do not credit the customer until the order reaches complete. For the full list, see Order Statuses, and for lookup see Order Lookup.


Step 6: Handle webhooks

Webhooks fire on every order status change and are the reliable mechanism for order tracking. Configure your webhook URL in the merchant dashboard.

The typical pattern:

  • Success callback: optimistic UI update, "your order is processing".
  • Webhook to your backend: authoritative order state.
  • Backend pushes the update to the app, or the app re-fetches on resume.

See Webhooks for payload structure and signature verification. Webhook signatures are verified with your HMAC secret, not the v2 x-api-key.


Google Pay approval

When your Android app presents Google Pay, Google requires app-level approval before you can process live payments. Banxa holds Google Pay approval for its own website, and that approval applies only when the customer is redirected to an external browser or a Custom Chrome Tab, not when Google Pay is presented inside your app.

Start the approval process early. It is the most common cause of a delayed Android launch.


KYC camera access

Banxa runs KYC inside the checkout the SDK presents. Declare android.permission.CAMERA in your manifest and request it at runtime before the customer reaches verification. Without it, document capture fails and the customer cannot complete KYC.


Testing

Use sandbox for all development:

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

Banxa.initialize(config)

Google Pay can be tested on a physical Android device or on an emulator with Google Play Services installed.

For test credentials, see Sandbox Test Data.


Native payment sheet

The SDK presents a native payment sheet for card and Google Pay when the customer is cleared for it, and falls back to Banxa checkout when they are not. Driving that behaviour explicitly, including reading the eligibility result and acting on outstanding requirements, is a Banxa Native capability for partners who verify their own users and run their own KYC. See Banxa Native, or talk to Banxa about whether it is relevant to your integration.


Next steps