# SDK Integration Guide

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.

## Before you start

### Prerequisites

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


### Install the SDK


```bash
npm install @banxa-official/react-native-sdk react-native-webview
```

For iOS, install the pods:


```bash
cd ios && pod install
```

`react-native-webview` is a peer dependency.

## Step 1 — Initialise the SDK

Create a single `Banxa` client instance at app startup. Keep it in a shared service or context so it can be reused across screens.


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


## Step 2 — Get a quote

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.


```typescript
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', { ... })`.

## Step 3 — Create an order

Create a buy order once the customer confirms.


```typescript
const order = await banxa.buy.createOrder({
  externalCustomerId: 'user-123',
  fiat: 'USD',
  crypto: 'BTC',
  fiatAmount: '100',
  paymentMethodId: '1',
  walletAddress: '1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa',
  redirectUrl: 'https://yourapp.com/success',
});
```

### Required fields

- `externalCustomerId` — your stable customer identifier, used by Banxa to recognise returning customers.
- `fiat`, `crypto`, and either `fiatAmount` or `cryptoAmount`.
- `paymentMethodId` — pre-selects the payment method.
- `walletAddress` — the customer's receiving wallet address.
- `redirectUrl` — where the customer is returned after checkout.


### Response


```json
{
  "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`. |


## Step 4 — Present the checkout

Use `initializeCheckoutWebView` to configure the props for the `CheckoutWebView` component, then render it.


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

### Payment methods that can't run in a WebView

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.

### Native payment sheet (Primer)

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](https://banxa-enterprise.redocly.app/enterprise-api/v0-beta). Talk to Banxa if you'd like to discuss whether this is relevant for your integration.

## Step 5 — Look up order status

After the customer completes checkout, retrieve the final order status via the SDK.


```typescript
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](/products/hosted-checkout/docs/transaction-lifecycle/order-statuses).

### Retrieving orders by customer

To list buy orders for a specific customer:


```typescript
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](/products/hosted-checkout/docs/api-integration/api-integration-overview) directly — this isn't exposed through the SDK.

## Step 6 — Handle webhooks (recommended)

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](/products/hosted-checkout/docs/transaction-lifecycle/webhooks) for payload structure and security.

The typical pattern:

- SDK `onSuccess` callback → 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).


## Error handling

Wrap SDK calls in try/catch. The SDK throws `BanxaSDKError` objects for API and network failures.


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

## Testing

Use the sandbox environment for all development and testing:


```typescript
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](/products/hosted-checkout/docs/testing/sandbox-test-data).

## Next steps

- [SDK Reference](/products/hosted-checkout/docs/sdk-integration/sdk-reference) — full method reference.
- [Webhooks](/products/hosted-checkout/docs/transaction-lifecycle/webhooks) — configure webhook notifications.
- [Order Statuses](/products/hosted-checkout/docs/transaction-lifecycle/order-statuses) — full status reference.
- [Sandbox Test Data](/products/hosted-checkout/docs/testing/sandbox-test-data) — credentials and test values for testing.