{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-products/hosted-checkout/sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":["admonition"]},"type":"markdown"},"seo":{"title":"iOS SDK Integration Guide","description":"Official Banxa API documentation – on-ramp and off-ramp transfers with identity verification and compliance.","llmstxt":{"title":"Banxa Developer Documentation","description":"Integrate crypto-fiat exchange with Banxa's licensed infrastructure: payments, KYC, compliance, and settlement handled. 150+ countries, 45 global licences.","details":{"content":"Two integration products: **Banxa Native API** for partners who manage their own KYC and want full UX control (headless, HMAC server-to-server, no Banxa-hosted screens); **Banxa Hosted Checkout** for partners who want Banxa to handle KYC and payments (three paths: Referral URL, API, or React Native SDK). Both use the same sandbox and production environments at `https://api.banxa-sandbox.com` and `https://api.banxa.com`.\n\n## Constraints\n\n- **Authentication**: HMAC credentials must be stored server-side only, never expose in frontend, mobile, or client-side code. HMAC is required for all Native API calls and for KYC sharing in Hosted Checkout; `x-api-key` is used for all other Hosted Checkout endpoints.\n- **`externalCustomerId`**: Required on every buy and sell order. Use a stable opaque identifier, never PII.\n- **`identityReference`**: Must remain constant for the same user across all requests. Must not contain PII. If you attempt to create an identity for an email that already exists, you will receive a 422 / code 81, so retrieve the existing record rather than retrying creation. Use `GET /eapi/v0/identities/{identityReference}?email=user@example.com` to look up the real `identityReference` linked to an email.\n- **`quoteId`**: Only supported by `POST /eapi/v0/ramps` (bank transfer). The React Native SDK and Embedded Payment Button do not accept a `quoteId`, so use indicative pricing (`GET /eapi/v0/price`) for SDK and Embedded Payment Button flows.\n- **Quotes**: Indicative prices are not rate-locked, so refresh close to order creation to minimise rate drift. Locked quotes (`GET /eapi/v0/quote`) expire after approximately 3 minutes and are only valid for bank transfer ramp creation.\n- **Eligibility gate**: Never create a ramp or invoke the SDK when `paymentReady` is `false`. Always check eligibility and satisfy all requirements before payment execution.\n- **Webhooks**: Verify all inbound webhook signatures with HMAC-SHA256 before processing. Return HTTP 200 immediately and process asynchronously.\n- **Product selection**: Banxa Native is for partners who manage their own KYC. Banxa Hosted Checkout is for partners who do not do KYC. These are separate products with separate flows: do not mix endpoints across products.\n- **SDK scope**: The React Native SDK has no `banxa.customerIdentity` module. Identity and KYC are handled through the Native API only. `primerCallbacks` and `primerSettings` are Native context only and must not be referenced in Hosted Checkout integrations.\n- **Payment method naming**: Never use \"eAPI\" or \"EAPI\" as a product name. The correct name is \"Banxa Native API\". The URL path prefix `/eapi/` is correct and should not be changed.\n"}}},"dynamicMarkdocComponents":[],"compilationErrors":[],"ast":{"$$mdtype":"Tag","name":"article","attributes":{},"children":[{"$$mdtype":"Tag","name":"Heading","attributes":{"level":1,"id":"ios-sdk-integration-guide","__idx":0},"children":["iOS SDK Integration Guide"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This guide walks through a complete Banxa Hosted Checkout integration in a native iOS app using the Banxa iOS SDK. By the end you will have a working buy flow: configure the SDK once, start a payment with a single call, and confirm the final order status from your backend."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The iOS SDK is headless. There is no Banxa view controller to embed and no WebView for you to manage. You supply an order request and a host view controller, and the SDK presents checkout, handles the payment, and reports the outcome on a delegate."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["For the full API surface, see the ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/products/hosted-checkout/docs/sdk-integration/ios-sdk-reference"},"children":["iOS SDK Reference"]},"."]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"before-you-start","__idx":1},"children":["Before you start"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"prerequisites","__idx":2},"children":["Prerequisites"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["A native iOS app on iOS 13.1 or above, built with Xcode 16 and Swift 6.0 or above."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Your Banxa partner reference and API key. Use sandbox for development, production after approval."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["A configured webhook endpoint. Optional but recommended for order status tracking."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"install-the-sdk","__idx":3},"children":["Install the SDK"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Add the package in Xcode through ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["File, Add Package Dependencies"]},", or declare it in ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Package.swift"]},":"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"dependencies: [\n    .package(url: \"https://github.com/BanxaOfficial/ios-payment-sdk\", from: \"1.0.0\")\n]\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Then add ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["BanxaPaymentSDK"]}," to your target:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":".target(\n    name: \"YourApp\",\n    dependencies: [\n        .product(name: \"BanxaPaymentSDK\", package: \"ios-payment-sdk\")\n    ]\n)\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"step-1-configure-the-sdk","__idx":4},"children":["Step 1: Configure the SDK"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Configure once at app launch and set your delegate. Calling any SDK method before ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["configure(config:)"]}," fails with ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["APIError.sdkNotConfigured"]},"."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"import BanxaPaymentSDK\n\nlet config = BanxaConfig(\n    apiKey: \"YOUR_API_KEY\",\n    partnerID: \"your-partner-id\",\n    environment: .sandbox            // .sandbox or .production\n)\n\nBanxaPaymentSDK.shared.configure(config: config)\nBanxaPaymentSDK.shared.delegate = self\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Field"},"children":["Field"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Description"},"children":["Description"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["apiKey"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Your v2 API key from the merchant dashboard."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["partnerID"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Your partner identifier."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["environment"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":[".sandbox"]}," or ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":[".production"]},". Credentials are not interchangeable."]}]}]}]}]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"step-2-get-a-quote","__idx":5},"children":["Step 2: Get a quote"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Fetch live pricing before you show an amount to the customer. Call this close to when the price is displayed, because crypto rates move quickly and quotes are indicative."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"let request = QuoteRequest(\n    paymentMethodID: \"debit-credit-card\",\n    crypto: \"ETH\",\n    blockchain: \"ETH\",\n    fiat: \"USD\",\n    fiatAmount: \"200\"\n)\n\nlet quotes = try await BanxaPaymentSDK.shared.fetchQuotes(orderType: .buy, request: request)\n\nprint(\"Receive:\", quotes[0].cryptoAmount ?? \"-\")\nprint(\"Processing fee:\", quotes[0].processingFee ?? \"-\")\nprint(\"Network fee:\", quotes[0].networkFee ?? \"-\")\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Provide either ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["fiatAmount"]}," or ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["cryptoAmount"]},". If both are set, Banxa uses ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["cryptoAmount"]},". Quotes carry no quote id, so there is nothing to pass into the payment call."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["fetchQuotes"]}," always returns an array, because Banxa returns multiple entries when discount codes apply."]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"step-3-start-the-payment","__idx":6},"children":["Step 3: Start the payment"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Build a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CreateOrderRequest"]}," and call ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["startPayment(request:controller:)"]}," when the customer confirms. Pass the view controller that should host the checkout presentation."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"let request = CreateOrderRequest(\n    crypto: \"ETH\",\n    fiat: \"EUR\",\n    fiatAmount: \"40\",\n    walletAddress: \"0x0000000000000000000000000000000000000000\",\n    email: \"user@example.com\",\n    redirectURL: \"your-app-scheme://banxa-return\",\n    paymentMethodID: \"debit-credit-card\"\n)\n\nBanxaPaymentSDK.shared.startPayment(request: request, controller: self)\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"required-fields","__idx":7},"children":["Required fields"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Field"},"children":["Field"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Notes"},"children":["Notes"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["crypto"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["fiat"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["fiatAmount"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["The order amounts and assets."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["paymentMethodID"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["The payment method to use. Declared as an optional in the Swift signature, but Banxa requires a value: omitting it fails at payment execution, not at compile time."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["walletAddress"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["The customer's receiving wallet address."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["email"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["The customer's email address."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["redirectURL"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Where the customer returns after checkout. Use a scheme you register in ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Info.plist"]},"."]}]}]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Pass ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["externalCustomerID"]}," as well. It is your stable per-customer identifier, and Banxa uses it to recognise returning customers so they do not repeat KYC."]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"warning","name":"Do not create orders in advance"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["startPayment"]}," creates the order and presents checkout in a single call, which keeps the order inside the one-minute window in which Banxa checkout must be loaded. Call it at the moment the customer confirms. There is no supported pattern for creating an order early and presenting it later."]}]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"warning","name":"A missing memo can permanently lose funds"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["XRP, XLM, EOS, and ATOM require a memo or tag. Pass it as ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["walletAddressTag"]}," on ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CreateOrderRequest"]},"."]}]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"step-4-handle-the-outcome","__idx":8},"children":["Step 4: Handle the outcome"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Conform to ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["BanxaPaymentSDKDelegate"]},". There are three methods, each with a default no-op implementation, so implement only what you need. All callbacks are delivered on the main actor."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"import BanxaPaymentSDK\n\nextension CheckoutViewController: BanxaPaymentSDKDelegate {\n\n    func banxaDidCompleteCheckout(_ result: BanxaCheckoutResult) {\n        // Payment succeeded. Confirm the authoritative state from your backend.\n        showProcessingState()\n    }\n\n    func banxaDidFail(error: Error) {\n        // API, validation, network, decoding, or checkout failure.\n        showRetry(message: error.localizedDescription)\n    }\n\n    func banxaDidDismiss() {\n        // The customer closed checkout without completing.\n        returnToAmountEntry()\n    }\n}\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["banxaDidCompleteCheckout"]}," is a UI signal, not the authoritative order state. Do not credit the customer on it."]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"step-5-confirm-order-status","__idx":9},"children":["Step 5: Confirm order status"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The SDK does not expose order lookup. Confirm the final state from your backend using the Banxa API."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Only terminal statuses are final. Do not credit the customer until the order reaches ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["complete"]},". For the full list, see ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/products/hosted-checkout/docs/transaction-lifecycle/order-statuses"},"children":["Order Statuses"]},", and for lookup see ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/products/hosted-checkout/docs/transaction-lifecycle/order-lookup"},"children":["Order Lookup"]},"."]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"step-6-handle-webhooks","__idx":10},"children":["Step 6: Handle webhooks"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Webhooks fire on every order status change and are the reliable mechanism for order tracking. Configure your webhook URL in the merchant dashboard."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The typical pattern:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Delegate success callback: optimistic UI update, \"your order is processing\"."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Webhook to your backend: authoritative order state."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Backend pushes the update to the app, or the app re-fetches on resume."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["See ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/products/hosted-checkout/docs/transaction-lifecycle/webhooks"},"children":["Webhooks"]}," for payload structure and signature verification. Webhook signatures are verified with your HMAC secret, not the v2 ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["x-api-key"]},"."]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"error-handling","__idx":11},"children":["Error handling"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Banxa-originated failures reach ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["banxaDidFail(error:)"]}," as ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["APIError"]},". The cases you will meet most often during integration:"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Case"},"children":["Case"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Cause"},"children":["Cause"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":[".sdkNotConfigured"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["startPayment"]}," was called before ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["configure(config:)"]},"."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":[".missingCredentials([String])"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["apiKey"]}," or ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["partnerID"]}," was blank."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":[".unauthorized"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["401"]}," from Banxa. Check the key matches the environment."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":[".checkoutFailed(String?)"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Checkout reached the failure URL. The payload is the raw query string."]}]}]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Show user-facing messages only from validated error fields. Do not expose raw error strings that may include internal detail. See ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/products/hosted-checkout/docs/reference/error-codes"},"children":["Error Codes"]},"."]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"kyc-camera-access","__idx":12},"children":["KYC camera access"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Banxa runs KYC inside the checkout the SDK presents. Add ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["NSCameraUsageDescription"]}," to your ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Info.plist"]},", and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["NSMicrophoneUsageDescription"]}," if your flow includes liveness capture. Without these keys, document capture fails silently and the customer cannot complete verification."]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"testing","__idx":13},"children":["Testing"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Use sandbox for all development:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"let config = BanxaConfig(\n    apiKey: \"YOUR_SANDBOX_API_KEY\",\n    partnerID: \"your-partner-id\",\n    environment: .sandbox\n)\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Apple Pay cannot be tested on the iOS simulator. The simulator reaches the payment sheet and then fails at payment. Test on a real device with at least one card added to Wallet."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["For test credentials, see ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/products/hosted-checkout/docs/testing/sandbox-test-data"},"children":["Sandbox Test Data"]},"."]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"native-payment-sheet","__idx":14},"children":["Native payment sheet"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The SDK presents a native payment sheet for card, Apple Pay, and Google Pay when the customer is cleared for it, and falls back to Banxa checkout when they are not. Driving that behaviour explicitly, including reading the eligibility result and acting on outstanding requirements, is a Banxa Native capability for partners who verify their own users and run their own KYC. See ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"https://banxa-enterprise.redocly.app/enterprise-api/v0-beta"},"children":["Banxa Native"]},", or talk to Banxa about whether it is relevant to your integration."]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"next-steps","__idx":15},"children":["Next steps"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/products/hosted-checkout/docs/sdk-integration/ios-sdk-reference"},"children":["iOS SDK Reference"]},": full method, model, and error reference."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/products/hosted-checkout/docs/transaction-lifecycle/webhooks"},"children":["Webhooks"]},": configure webhook notifications."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/products/hosted-checkout/docs/transaction-lifecycle/order-statuses"},"children":["Order Statuses"]},": full status reference."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/products/hosted-checkout/docs/testing/sandbox-test-data"},"children":["Sandbox Test Data"]},": credentials and test values."]}]}]},"headings":[{"value":"iOS SDK Integration Guide","id":"ios-sdk-integration-guide","depth":1},{"value":"Before you start","id":"before-you-start","depth":2},{"value":"Prerequisites","id":"prerequisites","depth":3},{"value":"Install the SDK","id":"install-the-sdk","depth":3},{"value":"Step 1: Configure the SDK","id":"step-1-configure-the-sdk","depth":2},{"value":"Step 2: Get a quote","id":"step-2-get-a-quote","depth":2},{"value":"Step 3: Start the payment","id":"step-3-start-the-payment","depth":2},{"value":"Required fields","id":"required-fields","depth":3},{"value":"Step 4: Handle the outcome","id":"step-4-handle-the-outcome","depth":2},{"value":"Step 5: Confirm order status","id":"step-5-confirm-order-status","depth":2},{"value":"Step 6: Handle webhooks","id":"step-6-handle-webhooks","depth":2},{"value":"Error handling","id":"error-handling","depth":2},{"value":"KYC camera access","id":"kyc-camera-access","depth":2},{"value":"Testing","id":"testing","depth":2},{"value":"Native payment sheet","id":"native-payment-sheet","depth":2},{"value":"Next steps","id":"next-steps","depth":2}],"frontmatter":{"title":"iOS SDK Integration Guide | Banxa Docs","description":"End-to-end iOS integration for Banxa Hosted Checkout with the Banxa iOS SDK: install, configure, start a payment, handle delegate callbacks, and confirm order status.","seo":{"title":"iOS SDK Integration Guide"}},"lastModified":"2026-08-12T00:56:59.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/products/hosted-checkout/docs/sdk-integration/ios-sdk-guide","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}