This guide walks through a complete Banxa Hosted Checkout integration using the React Native SDK. By the end, you'll have a working buy flow: fetch a live quote, create an order, present the checkout in a WebView, and retrieve the final order status.
- A React Native mobile app (iOS, Android, or both).
- Your Banxa partner reference and API key (sandbox for development, production after approval).
- A configured webhook endpoint (optional but recommended for order status tracking).
npm install @banxa-official/react-native-sdk react-native-webviewFor iOS, install the pods:
cd ios && pod installreact-native-webview is a peer dependency.
Create a single Banxa client instance at app startup. Keep it in a shared service or context so it can be reused across screens.
import { Banxa } from '@banxa-official/react-native-sdk';
const banxa = new Banxa({
apiKey: 'YOUR_API_KEY',
partner: 'your-partner-id',
environment: 'sandbox', // or 'production'
});| Field | Description |
|---|---|
apiKey | Your Banxa API key. |
partner | Your partner identifier (e.g., binance, metamask). |
environment | 'sandbox' or 'production'. Defaults to 'production'. |
baseUrl | Optional. Overrides the environment-derived base URL. |
Call the Quote API to retrieve live pricing before presenting an amount to the customer. Call this close to when you show the price — crypto rates move quickly, and stale quotes can differ from the final checkout price.
const quote = await banxa.prices.getBuyQuote({
fiat: 'USD',
crypto: 'BTC',
fiatAmount: '100',
paymentMethodId: '1',
blockchain: 'bitcoin',
});
console.log('Crypto amount:', quote.cryptoAmount);
console.log('Processing fee:', quote.processingFee);
console.log('Network fee:', quote.networkFee);Either fiatAmount or cryptoAmount must be provided. For sell quotes, use banxa.prices.getQuote('sell', { ... }).
Create a buy order once the customer confirms.
const order = await banxa.buy.createOrder({
externalCustomerId: 'user-123',
fiat: 'USD',
crypto: 'BTC',
fiatAmount: '100',
paymentMethodId: '1',
walletAddress: '1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa',
redirectUrl: 'https://yourapp.com/success',
});externalCustomerId— your stable customer identifier, used by Banxa to recognise returning customers.fiat,crypto, and eitherfiatAmountorcryptoAmount.paymentMethodId— pre-selects the payment method.walletAddress— the customer's receiving wallet address.redirectUrl— where the customer is returned after checkout.
{
"checkoutUrl": "https://partner.banxa.com/portal?expires=xxx&oid=xxx&signature=xxx",
"id": "191fa5b4b1f45e1cf784422e09317d56",
"externalOrderId": "a4b427ccb872a1744b317456bd0d165f",
"externalCustomerId": "user-123",
"fiat": "CAD",
"fiatAmount": "1000.00",
"crypto": "USDC",
"cryptoAmount": null,
"blockchain": "TRON"
}| Field | Description |
|---|---|
checkoutUrl | Banxa-hosted checkout URL to present to the customer. |
id | Banxa order ID. Store this — you'll use it for order lookup. |
externalOrderId | Your internal order reference, if provided at creation. null if not. |
externalCustomerId | Your customer identifier as supplied. |
fiat, fiatAmount, crypto, cryptoAmount, blockchain | Order parameters as supplied. If cryptoAmount or fiatAmount wasn't provided, it will be null. |
Use initializeCheckoutWebView to configure the props for the CheckoutWebView component, then render it.
import { CheckoutWebView } from '@banxa-official/react-native-sdk';
import { useState } from 'react';
function BuyCryptoScreen() {
const [webViewProps, setWebViewProps] = useState(null);
const handleBuyPress = async () => {
const order = await banxa.buy.createOrder({
externalCustomerId: 'user-123',
fiat: 'USD',
crypto: 'BTC',
fiatAmount: '100',
paymentMethodId: '1',
walletAddress: '1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa',
redirectUrl: 'https://yourapp.com/success',
});
const props = banxa.buy.initializeCheckoutWebView(order, {
onClose: () => setWebViewProps(null),
onSuccess: (url) => { /* payment succeeded */ setWebViewProps(null); },
onFailure: (url) => { /* payment failed */ setWebViewProps(null); },
returnUrlOnSuccess: 'https://yourapp.com/success',
returnUrlOnFailure: 'https://yourapp.com/failure',
});
setWebViewProps(props);
};
return (
<>
<Button onPress={handleBuyPress} title="Buy BTC" />
{webViewProps && <CheckoutWebView {...webViewProps} />}
</>
);
}The WebView detects navigation to your return URLs automatically and triggers the corresponding callback.
Some payment methods — iDEAL, Klarna, and PayPal — cannot complete inside a WebView. These methods require the customer to be redirected outside your app to the provider (bank, Klarna, or PayPal). There is no automatic return, so partners should design a post-payment UX — for example, a confirmation screen with a link back to the app.
The SDK also supports a native payment sheet via Primer for card, Apple Pay, and Google Pay payments. This is a more advanced integration designed for partners who verify their own users and run their own KYC — see Banxa Native. Talk to Banxa if you'd like to discuss whether this is relevant for your integration.
After the customer completes checkout, retrieve the final order status via the SDK.
const orderDetails = await banxa.buy.getOrder(order.id);
if (orderDetails.status === 'complete') {
// Notify the user, update your database, etc.
}For the full list of order statuses and their meanings, see Order Statuses.
To list buy orders for a specific customer:
const userOrders = await banxa.buy.getOrdersByAccount('user-123');This returns orders tied to that externalCustomerId. For a full list of all orders across all customers (reconciliation, reporting), use the Banxa API directly — this isn't exposed through the SDK.
The SDK's onSuccess callback fires when the customer completes checkout, but for reliable order status tracking you should configure webhooks on your backend.
Webhooks fire for every order status change. Configure your webhook URL in the Partner Dashboard.
→ See Webhooks for payload structure and security.
The typical pattern:
- SDK
onSuccesscallback → optimistic UI update ("your order is processing"). - Webhook to your backend → authoritative order state.
- Backend pushes update to the app (or app re-fetches order on resume).
Wrap SDK calls in try/catch. The SDK throws BanxaSDKError objects for API and network failures.
import { Banxa, BanxaSDKError } from '@banxa-official/react-native-sdk';
try {
const order = await banxa.buy.createOrder({ /* ... */ });
} catch (error) {
if (error instanceof BanxaSDKError) {
console.error('Banxa API error:', error.message);
console.error('Error code:', error.code);
console.error('Status code:', error.statusCode);
} else {
console.error('Unknown error:', error);
}
}Show user-facing messages only from validated error fields — don't expose raw error strings that may include internal detail.
Use the sandbox environment for all development and testing:
const banxa = new Banxa({
apiKey: 'YOUR_SANDBOX_API_KEY',
partner: 'your-partner-id',
environment: 'sandbox',
});For test credentials (mobile numbers, card numbers, PIN codes, KYC data), see Sandbox Test Data.
- SDK Reference — full method reference.
- Webhooks — configure webhook notifications.
- Order Statuses — full status reference.
- Sandbox Test Data — credentials and test values for testing.