# Integration Guide

Every Banxa Native integration shares the same core steps: establish an identity, get a price, check eligibility, then execute payment. The payment method guides — bank transfer, Apple Pay, Google Pay, cards — each pick up from where this page leaves off.

Read this page once. Then follow the guide for your payment method.

## Prerequisites

Before you begin:

- **HMAC API credentials** — API key and secret from the Merchant Dashboard. Required for all server-to-server calls.
- **A backend** — all Native API calls use server-to-server HMAC authentication. Client-side API calls are not supported.
- **An `identityReference` strategy** — a stable per-user identifier that you own. See [Choosing an identityReference](/products/native-api/docs/how-it-works/identity-reference) before proceeding.
- **The Banxa React Native SDK** — required for card, Apple Pay, and Google Pay payments. Not required for bank transfers.


Install the SDK and its peer dependencies:


```bash
npm install @banxa-official/react-native-sdk @primer-io/react-native react-native-webview
cd ios && pod install
```

Initialise the SDK once at app startup:


```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'
});
```

For full SDK configuration options, see the [React Native SDK Reference](/products/native-api/docs/sdk/sdk-reference).

## Two integration approaches

Before diving into the steps below, decide how much of the flow you want to own. This guide documents the full control approach — steps 1–4 below apply to that path.

### Full control

Your backend handles identity, pricing, and eligibility before payment is invoked. You call the SDK only at the payment step. Any screens for collecting KYC requirements are yours — your design, your brand, your UX.

This is the recommended approach for most Banxa Native integrations.

### Quick start

Call `createOrderAndShowPrimerCheckout` without running eligibility first. The SDK creates the order and Banxa routes the user automatically: verified users go directly to the native payment sheet; users who need KYC are routed to a Banxa-hosted WebView where Banxa handles verification.


```typescript
const result = await banxa.buy.createOrderAndShowPrimerCheckout(orderRequest, {
  paymentMethod: 'applePay', // 'card' | 'applePay' | 'googlePay'
  callbacks: {
    onCheckoutComplete: () => { /* payment succeeded */ },
    onError: (error) => { /* payment failed or unavailable */ },
    onDismiss: () => { /* user dismissed */ },
  },
});

if (isPrimerCheckoutWebViewResult(result)) {
  // Banxa routed to hosted WebView (KYC required or payment method unavailable natively)
  // render <CheckoutWebView {...result.webViewProps} />
}
```

The trade-off: Banxa runs eligibility internally and you don't see the result. If the user needs KYC, it happens in Banxa's WebView — outside your product.

Use quick start when you want the simplest possible path to a working integration — for example, during early development — or when you're explicitly comfortable with Banxa handling KYC for users who need it. It is available for the React Native SDK only. If you choose this path, skip steps 3 and 4 below.

## Step 1 — Establish an identityReference

Create an identity record for the user before checking eligibility. The minimum required field is `identityReference` — include any personal details you already have, as they reduce the likelihood of requirements being returned at eligibility.


```http
POST /eapi/v0/identities/basic
Content-Type: application/json

{
  "identityReference": "partner-abc123",
  "email": "user@example.com",
  "dateOfBirth": "1990-01-15"
}
```

For returning users, reuse the existing `identityReference`. If you don't have it stored, see [Choosing an identityReference](/products/native-api/docs/how-it-works/identity-reference) for retrieval options and all new-user flow variants.

Never recreate an identity
If you attempt to create an identity for an email that already exists in Banxa, you will receive a `422` with code `81`: `"This identity exists for this reference or email address."` Do not retry the creation. Instead, retrieve the existing identity using `GET /eapi/v0/identities/{identityReference}?email=user@example.com` — Banxa returns the actual `identityReference` linked to that email, regardless of what value you supply in the path parameter.

If you verify users with Sumsub, share the verification token at this point. Token sharing satisfies `NAME`, `DOB`, `SELFIE`, and `DOCUMENT` requirements upfront so eligibility is more likely to return `paymentReady: true` on the first check. See [KYC Token Sharing](/products/native-api/docs/how-it-works/kyc-token-sharing).

## Step 2 — Get pricing

There are two pricing endpoints:

| Endpoint | Rate locked? | Expiry to manage? |
|  --- | --- | --- |
| `GET /eapi/v0/price` | No | No |
| `GET /eapi/v0/quote` | Yes — `quoteId` with 3-minute TTL | Yes |


This guide uses indicative pricing. It can be called at any point in the flow and has no expiry to handle. The trade-off is that the rate is not locked — if you display a price and then create the ramp without refreshing, the rate may have moved and the user receives a different amount than shown. Refresh the price close to ramp creation to minimise the gap.

The locked quote (`GET /eapi/v0/quote`) eliminates this risk but is only supported for bank transfer ramp creation — the React Native SDK and Embedded Payment Button do not accept a `quoteId`.


```http
GET /eapi/v0/price?fiat=AUD&crypto=USDT&blockchain=TRON&method=payid-bank-transfer&transactionType=ONRAMP&fiatAmount=500
```

Pass `fiatAmount` or `cryptoAmount` — not both. If you're building a bank transfer integration and want to lock the rate shown on the confirmation screen, see [Pricing & Quote ID](/products/native-api/docs/how-it-works/quotes-and-pricing).

## Step 3 — Check eligibility

Before every transaction, confirm the user is cleared to proceed. Eligibility evaluates the user's identity state against the transaction context — amount, payment method, and jurisdiction.


```http
POST /eapi/v0/identities/transactions/eligibility
Content-Type: application/json

{
  "identityReference": "partner-abc123",
  "method": "payid-bank-transfer",
  "transactionType": "ONRAMP",
  "fiat": "AUD",
  "crypto": "USDT",
  "blockchain": "TRON",
  "fiatAmount": "500"
}
```

**Response: cleared to proceed**


```json
{
  "paymentReady": true,
  "requirements": []
}
```

**Response: additional information required**


```json
{
  "paymentReady": false,
  "requirements": ["OCCUPATION", "SOURCE_FUNDS"]
}
```

Do not create a ramp or invoke the SDK when `paymentReady` is `false`. See [Interpreting Eligibility](/products/native-api/docs/how-it-works/interpreting-eligibility) for the full requirements dictionary.

## Step 4 — Handle requirements (if any)

When eligibility returns requirements, collect the missing information in your UX and submit it before re-checking.

For structured fields (`NAME`, `DOB`, `ADDRESS`, `OCCUPATION`, `SOURCE_FUNDS`, `PURPOSE_OF_TX`, `TIN`, `DOCUMENT`, `POA`):


```http
PATCH /eapi/v0/identities
Content-Type: application/json

{
  "identityReference": "partner-abc123",
  "email": "user@example.com",
  "occupationIndustry": "Consulting, IT, or business services",
  "occupation": "IT developer",
  "sourceOfFunds": "Salary"
}
```

`email` is required on every PATCH request. Partial updates are supported — include only the fields you're updating.

For `SELFIE` — complete KYC provider token sharing first. Token sharing may satisfy multiple requirements in a single call. Then submit any remaining structured fields via PATCH. See [KYC Token Sharing](/products/native-api/docs/how-it-works/kyc-token-sharing).

After submitting, re-run eligibility. Repeat until `paymentReady: true`.


```mermaid
flowchart TD
    A[POST /eligibility] --> B{paymentReady?}
    B -->|true| C([Proceed to payment])
    B -->|false| D[Collect requirements in your UX]
    D --> E{SELFIE required?}
    E -->|Yes| F[POST /identities/share/token\nKYC token sharing]
    E -->|No| G[PATCH /identities\nStructured fields]
    F --> G
    G --> A
```

## Step 5 — Execute payment

Once `paymentReady: true` is confirmed, proceed to your payment method guide for the execution step:

Bank Transfer
Fully API-driven. No SDK required. Banxa returns funding instructions for the user to complete the transfer.

Apple Pay
Native payment sheet via React Native SDK, or Embedded Payment Button for web apps. Requires platform setup.

Google Pay
Native payment sheet via React Native SDK, or Embedded Payment Button for web apps. Requires app-level approval for the SDK path.

Cards
Primer card input drawer via React Native SDK. Requires 3DS SDK setup.

## Tracking transaction status

Transactions are asynchronous. Configure a webhook endpoint to receive status updates:


```json
{
  "order_id": "b7f1ffbb2f1bd7a5e2ba152b4049d234",
  "status": "COMPLETED",
  "status_date": "2026-04-17 03:45:00",
  "external_reason": "...",
  "fiat_currency": "AUD",
  "fiat_amount": "500.00",
  "crypto_coin": "USDT",
  "crypto_amount": "324.51",
  "transaction_hash": "0x..."
}
```

Acknowledge every webhook with a `200` response immediately, then process asynchronously. You can also poll directly using `GET /eapi/v0/ramps/{id}`. See [Webhooks](/products/native-api/docs/transaction-lifecycle/webhooks) for the full payload schema and status values.