# Android SDK Reference

The Banxa Android SDK (`BanxaPaymentSDK`) is a headless Kotlin interface to Banxa Hosted Checkout for native Android apps. You initialise it once and render the `StartPayment` composable to run a payment. The SDK checks eligibility, creates the order, presents checkout, and reports the outcome through callback lambdas.

For the end-to-end walkthrough, see the [Android SDK Integration Guide](/products/hosted-checkout/docs/sdk-integration/android-sdk-guide).

## Requirements

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


## Installation

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

```kotlin
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.

## Configuration

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

Banxa.initialize(config)
```

### BanxaConfig.Builder

| Method | Required | Description |
|  --- | --- | --- |
| `apiKey(String)` | Yes | Your v2 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 native payment sheet colour tokens. Relevant only when the native payment sheet is in use. See [Banxa Native](https://banxa-enterprise.redocly.app/enterprise-api/v0-beta). |


Requests use `x-api-key` authentication.

### Environments

| Environment | Host |
|  --- | --- |
| `Environment.SANDBOX` | `https://api.banxa-sandbox.com` |
| `Environment.PRODUCTION` | `https://api.banxa.com` |


The effective base URL is `<host>/{partnerID}/v2`. Sandbox and production credentials are separate and are not interchangeable.

## StartPayment

`StartPayment` is a composable. Render it when the customer confirms.

```kotlin
StartPayment(
    createOrderRequest = CreateOrderRequest(
        fiat = "EUR",
        crypto = "ETH",
        fiatAmount = "40",
        cryptoAmount = null,
        walletAddress = "0x0000000000000000000000000000000000000000",
        redirectUrl = "your-app-scheme://banxa-return",
        paymentMethodId = "debit-credit-card",
        email = "user@example.com"
    ),
    banxaDidReceiveCheckout = { result ->
        println("Paid: ${result.paymentId ?: result.rawQuery ?: "-"}")
    },
    banxaDidFail = { error ->
        println("Failed: $error")
    },
    banxaDidDismiss = {
        println("Customer dismissed checkout")
    }
)
```

`StartPayment` creates the order and presents checkout together. Render it when the customer confirms, not in advance, because Banxa checkout must be loaded within one minute of order creation.

Requires a prior `Banxa.initialize(config)` call.

## Callbacks

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

| Callback | Fires when |
|  --- | --- |
| `banxaDidReceiveCheckout` | The customer completed payment. Receives a checkout result. |
| `banxaDidFail` | Any Banxa, network, validation, or checkout failure. |
| `banxaDidDismiss` | The customer closed checkout without completing. |


### Checkout result

| 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` | Banxa checkout was used. Contains the terminal success URL query string. |


The success callback is a UI signal, not the authoritative order state. Confirm the final state from [webhooks](/products/hosted-checkout/docs/transaction-lifecycle/webhooks) or [Order Lookup](/products/hosted-checkout/docs/transaction-lifecycle/order-lookup) before you credit a customer.

## Models

### CreateOrderRequest

| 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 Banxa redirects to after checkout. |
| `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 stable customer identifier. |
| `externalOrderId` | String? | No | Your order reference. |
| `discountCode` | String? | No | Promotion 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 order to one of these chains without the memo can be unrecoverable.

## Configuration endpoints

Use these to populate payment method selectors and currency pickers at runtime instead of hardcoding values. Each returns a `Result`.

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

### Payment methods

`GET /{partnerID}/v2/payment-methods/{orderType}`. Optionally filter with `fiat`.

```kotlin
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} to ${method.supportedFiats}")
    }
}
```

| `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. |


### Countries

`GET /{partnerID}/v2/countries`. The list is the same for buy and sell.

```kotlin
val result = repository.getCountries(
    partner = config.partner,
    apiKey = config.apiKey
)
```

| Type | Fields |
|  --- | --- |
| `Country` | `id`, `description`, `states: List<CountryState>` |
| `CountryState` | `id`, `description` |


`states` is empty when the country has no state breakdown.

### Fiats

`GET /{partnerID}/v2/fiats/{orderType}`. Includes payment method minimum and maximum limits.

```kotlin
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?` |


### Cryptocurrencies

`GET /{partnerID}/v2/crypto/{orderType}`.

```kotlin
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.

### Quotes

`GET /{partnerID}/v2/quotes/{orderType}`. Do not cache: call immediately before showing a price.

```kotlin
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, for more accurate pricing. |
| `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. |


## 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. See [Error Codes](/products/hosted-checkout/docs/reference/error-codes).

## Not available in the SDK

| Capability | Reason | Alternative |
|  --- | --- | --- |
| Order lookup by id or customer | Not exposed | [Order Lookup](/products/hosted-checkout/docs/transaction-lifecycle/order-lookup) via the API |
| Full order list across all customers | Not exposed | `GET /{partnerRef}/v2/orders` via [API integration](/products/hosted-checkout/docs/api-integration/api-integration-overview) |
| KYC data sharing (Sumsub token share) | Requires HMAC authentication, which the SDK does not use | [KYC Sharing](/products/hosted-checkout/docs/identity-compliance/kyc-sharing) |
| Off-ramp (sell) orders | The SDK covers buy orders only | [Create Sell Order](/products/hosted-checkout/docs/api-integration/create-sell-order) |


## Payment methods and supported fiats

Availability varies by partner, region, and order type. Treat `getPaymentMethods` 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` |


For the full list, see [Supported Payment Methods](/products/hosted-checkout/docs/reference/supported-payment-methods).

## Next steps

- [Android SDK Integration Guide](/products/hosted-checkout/docs/sdk-integration/android-sdk-guide): end-to-end walkthrough.
- [Webhooks](/products/hosted-checkout/docs/transaction-lifecycle/webhooks): configure webhook notifications.
- [Order Statuses](/products/hosted-checkout/docs/transaction-lifecycle/order-statuses): full status reference.