# iOS SDK Reference

The Banxa iOS SDK (`BanxaPaymentSDK`) is a headless Swift interface to Banxa Hosted Checkout for native iOS apps. You configure it once and start a payment with a single call. The SDK checks eligibility, creates the order, presents checkout, and reports the outcome on a delegate.

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

## Requirements

| Requirement | Version |
|  --- | --- |
| iOS | 13.1 and above |
| Xcode | 16 and above |
| Swift | 6.0 and above |


The public surface is `@MainActor` isolated and built on Swift concurrency.

## Installation

### Swift Package Manager

```swift
dependencies: [
    .package(url: "https://github.com/BanxaOfficial/ios-payment-sdk", from: "1.0.0")
]
```

```swift
.target(
    name: "YourApp",
    dependencies: [
        .product(name: "BanxaPaymentSDK", package: "ios-payment-sdk")
    ]
)
```

### Through Xcode

1. Select **File, Add Package Dependencies**.
2. Enter the repository URL.
3. Select **BanxaPaymentSDK** and add it to your app target.


The SDK transitively pulls in the payment provider SDK. You do not import or reference it directly.

## Configuration

```swift
import BanxaPaymentSDK

let config = BanxaConfig(
    apiKey: "YOUR_API_KEY",
    partnerID: "your-partner-id",
    environment: .sandbox
)

BanxaPaymentSDK.shared.configure(config: config)
BanxaPaymentSDK.shared.delegate = self
```

### BanxaConfig

| Field | Type | Required | Description |
|  --- | --- | --- | --- |
| `apiKey` | String | Yes | Your v2 API key from the merchant dashboard. |
| `partnerID` | String | Yes | Your partner identifier. |
| `environment` | `Environment` | Yes | `.sandbox` or `.production`. |


Requests use `x-api-key` authentication.

### Environments

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


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

## startPayment

```swift
BanxaPaymentSDK.shared.startPayment(request: request, controller: self)
```

| Parameter | Description |
|  --- | --- |
| `request` | A `CreateOrderRequest`. |
| `controller` | The `UIViewController` that hosts the checkout presentation. |


`startPayment` creates the order and presents checkout in a single call. It returns nothing: results arrive on the delegate. Call it when the customer confirms, not in advance, because Banxa checkout must be loaded within one minute of order creation.

Requires a prior `configure(config:)` call. Otherwise it fails with `APIError.sdkNotConfigured`.

## BanxaPaymentSDKDelegate

Three methods, each with a default no-op implementation. All callbacks are delivered on the main actor. All callback types are Banxa-owned: you never import or reference the underlying payment provider SDK.

```swift
extension MyViewController: BanxaPaymentSDKDelegate {

    func banxaDidCompleteCheckout(_ result: BanxaCheckoutResult) { }

    func banxaDidFail(error: Error) { }

    func banxaDidDismiss() { }
}
```

| Method | Fires when |
|  --- | --- |
| `banxaDidCompleteCheckout(_:)` | The customer completed payment. |
| `banxaDidFail(error:)` | Any Banxa, network, validation, or checkout failure. Banxa-originated failures are `APIError`. |
| `banxaDidDismiss()` | The customer closed checkout without completing. |


### BanxaCheckoutResult

| 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 |
|  --- | --- | --- | --- |
| `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. |
| `paymentMethodID` | String? | Yes | Banxa payment method id, for example `debit-credit-card`. |
| `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. |


paymentMethodID is optional in the type, required in practice
`paymentMethodID` is declared as an optional in the Swift signature, but Banxa requires a value. Omitting it fails at payment execution rather than at compile time, so the compiler will not catch it for you. Always pass an id returned by `fetchPaymentMethods`.

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

All configuration calls are `async throws` and require a configured SDK with non-blank credentials.

### Countries

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

```swift
let countries = try await BanxaPaymentSDK.shared.fetchCountries()
```

| Type | Fields |
|  --- | --- |
| `Country` | `id`, `description`, `states: [CountryState]?` |
| `CountryState` | `id`, `description` |


### Fiats

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

```swift
let fiats = try await BanxaPaymentSDK.shared.fetchFiats(orderType: .buy)
```

| Type | Fields |
|  --- | --- |
| `OrderType` | `.buy`, `.sell` |
| `Fiat` | `id`, `description?`, `symbol?`, `supportedPaymentMethods: [FiatPaymentMethod]?` |
| `FiatPaymentMethod` | `id`, `name?`, `minimum?`, `maximum?` |


### Crypto

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

```swift
let assets = try await BanxaPaymentSDK.shared.fetchCrypto(orderType: .buy)
```

| Type | Fields |
|  --- | --- |
| `Cryptocurrency` | `id`, `description?`, `blockchains: [CryptoBlockchain]?` |
| `CryptoBlockchain` | `id`, `description?`, `isDefaultBlockchain?`, `address?`, `network?`, `minimum?`, `unsupportedCountries: [String: [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.

### Payment methods

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

```swift
let methods = try await BanxaPaymentSDK.shared.fetchPaymentMethods(orderType: .buy)
let usdOnly = try await BanxaPaymentSDK.shared.fetchPaymentMethods(orderType: .buy, fiat: "USD")
```

| Type | Fields |
|  --- | --- |
| `PaymentMethod` | `id`, `name?`, `description?`, `supportedFiats: [String]?` |


### Quotes

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

```swift
let request = QuoteRequest(
    paymentMethodID: "debit-credit-card",
    crypto: "ETH",
    blockchain: "ETH",
    fiat: "USD",
    fiatAmount: "200"
)
let quotes = try await BanxaPaymentSDK.shared.fetchQuotes(orderType: .buy, request: request)
```

| Type | Fields |
|  --- | --- |
| `QuoteRequest` | `paymentMethodID`, `crypto`, `blockchain`, `fiat`, `fiatAmount?`, `cryptoAmount?`, `externalCustomerID?`, `ipAddress?`, `discountCode?` |
| `Quote` | `paymentMethodID?`, `cryptoAmount?`, `fiatAmount?`, `processingFee?`, `networkFee?`, `discount: QuoteDiscount?` |
| `QuoteDiscount` | `originalQuote: QuoteOriginalAmounts?`, `discountCode?` |
| `QuoteOriginalAmounts` | `originalCryptoAmount?`, `originalNetworkFee?`, `originalProcessingFee?`, `originalFiatAmount?` |


Provide either `fiatAmount` or `cryptoAmount`. If both are set, Banxa uses `cryptoAmount`. Banxa may return a single object or an array when discount codes apply, and `fetchQuotes` always returns `[Quote]`.

## Error handling

Failures are surfaced through `banxaDidFail(error:)` as `APIError`. Each case provides a human-readable `errorDescription`.

| Case | Meaning |
|  --- | --- |
| `.invalidURL` | The endpoint URL could not be built. |
| `.serverError(Int)` | Non-2xx HTTP response. |
| `.unauthorized` | `401` from Banxa. Check `apiKey`. |
| `.decodingFailed(String)` | The response payload failed to decode. |
| `.networkUnavailable` | No network connectivity. |
| `.missingCredentials([String])` | `apiKey` or `partnerID` was blank in `BanxaConfig`. |
| `.sdkNotConfigured` | `startPayment` was called before `configure(config:)`. |
| `.unknown(String)` | Any other unexpected error. |


Show user-facing messages only from validated error fields. Do not expose raw error strings that may include internal detail.

## URL scheme

Register a URL scheme in your `Info.plist` and use it for `redirectURL` on `CreateOrderRequest`. This covers 3D Secure returns and the checkout return.

## 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 sheet theming | Not exposed on iOS | Available on Android. See [Android SDK Reference](/products/hosted-checkout/docs/sdk-integration/android-sdk-reference) |


## Example

```swift
import SwiftUI
import BanxaPaymentSDK

@main
struct DemoApp: App {

    init() {
        let config = BanxaConfig(
            apiKey: ProcessInfo.processInfo.environment["BANXA_API_KEY"] ?? "",
            partnerID: "your-partner-id",
            environment: .sandbox
        )
        BanxaPaymentSDK.shared.configure(config: config)
    }

    var body: some Scene {
        WindowGroup { ContentView() }
    }
}

final class CheckoutCoordinator: NSObject, BanxaPaymentSDKDelegate {

    override init() {
        super.init()
        BanxaPaymentSDK.shared.delegate = self
    }

    func buy(from controller: UIViewController) {
        let request = CreateOrderRequest(
            crypto: "ETH",
            fiat: "EUR",
            fiatAmount: "40",
            walletAddress: "0x0000000000000000000000000000000000000000",
            email: "user@example.com",
            redirectURL: "your-app-scheme://banxa-return",
            paymentMethodID: "debit-credit-card"
        )
        BanxaPaymentSDK.shared.startPayment(request: request, controller: controller)
    }

    func banxaDidCompleteCheckout(_ result: BanxaCheckoutResult) {
        print("Payment complete:", result.paymentId ?? result.rawQuery ?? "-")
    }

    func banxaDidFail(error: Error) {
        print("Payment failed:", error.localizedDescription)
    }

    func banxaDidDismiss() {
        print("Customer dismissed checkout")
    }
}
```

## Payment methods and supported fiats

Availability varies by partner, region, and order type. Treat `fetchPaymentMethods` 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` |
| `apple-pay` | `AUD`, `EUR`, `GBP`, `USD` |
| `google-pay` | `AUD`, `EUR`, `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

- [iOS SDK Integration Guide](/products/hosted-checkout/docs/sdk-integration/ios-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.