Skip to content

Installation

Install the iOS SDK library and start using components in your project.

Before you start

Make sure you have Xcode 14.0 or later, iOS 14.0 or later as your deployment target, and Swift 5.9+.

Step 1: Install the iOS SDK library

To install using Swift Package Manager:

  1. Open your Xcode project.
  2. Go to File > Add Package Dependencies....
  3. Enter the repository URL: https://github.com/PXP-IO/ios-components-sdk.git.
  4. Select a version rule (e.g., Up to Next Major Version).
  5. Click Add Package.
  6. Select the PXPCheckoutSDK library and add it to your app target.
import PXPCheckoutSDK

The Paze button component is included in PXPCheckoutSDK. You don't need a separate Paze dependency.

Step 2: Get your API credentials

To initialise the SDK, you'll need to send authenticated requests to the PXP API.

To get your credentials:

  1. In the Unity Portal, go to Merchant setup > Merchant groups.
  2. Select a merchant group.
  3. Click the Inbound calls tab.
  4. Copy the Client ID in the top-right corner.
  5. Click New token.
  6. Choose a number of days before token expiry. For example, 30.
  7. Click Save to confirm. Your token is now created.
  8. Copy the token ID and token value. Make sure to keep these confidential to protect the integrity of your authentication process.

As best practice, we recommend regularly generating and implementing new tokens.

Step 3: Get the session data

Now that you have your credentials, you're ready to send an API request to the sessions endpoint. This allows you to retrieve the transaction session data from the back-end, so you can supply it when you initialise the SDK.

Our platform uses HMAC (Hash-based Message Authentication Code) with SHA256 for authentication to ensure secure communication and data integrity. This method involves creating a signature by hashing your request data with a secret key, which must then be included in the HTTP headers of your API request.

To create the HMAC signature, you need to prepare a string that includes four parts:

  • A timestamp, in Unix format. For example, 1754701373.
  • A unique request ID, in GUID format. For example, ce244054-b372-42c2-9102-f0d976db69f6.
  • The request path, which is api/v1/sessions.
  • The request body. For example:
    {
       "merchant": "MERCHANT-1",
       "site": "SITE-1",
       "sessionTimeout": 120,
       "merchantTransactionId": "0ce72cfd-014d-4256-a006-a56601b2ffc4",
       "amounts": {
         "currencyCode": "EUR",
         "transactionValue": 20
       },
       "transactionMethod": {
         "intent": {
           "card": "authorisation",
           "paypal": "authorisation"
         }
       }
    }
ParameterDescription
merchant
string (≤ 20 characters)
required
Your unique merchant identifier, as assigned by PXP. You can find it in the Unity Portal, by going to Merchant setup > Merchants and checking the Merchant ID column or by clicking on a merchant and checking the General information section.
site
string (≤ 20 characters)
required
Your unique site identifier, as assigned by PXP. You can find it in the Unity Portal, by going to Merchant setup > Sites and checking the Site ID column or by clicking on a site and checking the General information section.
merchantTransactionId
string (≤ 50 characters)
required
A unique identifier of your choice that represents this transaction.
sessionTimeout
number
required
The duration of the session, in minutes.
amounts
object
required
Details about the transaction amount.
amounts.currencyCode
string (3 characters)
required
The currency code associated with the transaction, in ISO 4217 format. See Supported payment currencies.
amounts.transactionValue
number
required
The transaction amount. The numbers after the decimal will be zero padded if they are less than the expected currencyCode exponent. For example, GBP 1.1 = GBP 1.10, EUR 1 = EUR 1.00, or BHD 1.3 = 1.300. The transaction will be rejected if numbers after the decimal are greater than the expected currencyCode exponent (e.g., GBP 1.234), or if a decimal is supplied when the currencyCode of the exponent does not require it (e.g., JPY 1.0).
transactionMethod
object
required
Details about the transaction method and intent.
transactionMethod.intent
object
required
The payment intent for each payment method type.
transactionMethod.intent.card
string
The intent for card or Apple Pay transactions.

Possible values:
  • authorisation
  • purchase
  • verification
transactionMethod.intent.paypal
string
The intent for PayPal transactions.

Possible values:
  • authorisation
  • purchase
  • payout

For PayPal payouts, use "payout" as the intent value. Payout transactions have different requirements than payment transactions. See PayPal Payouts for more details.

For Paze, enable the service in the Unity Portal and include clientId and merchantCategoryCode in the session response. Use USD as currencyCode when testing Paze. See Paze onboarding.

Put these four parts together following this format: "{timestamp}{requestId}{requestPath}{requestBody}". The result should look something like this:

1754701373ce244054-b372-42c2-9102-f0d976db69f6api/v1/sessions{
  "merchant": "MERCHANT-1",
  "site": "SITE-1",
  "sessionTimeout": 120,
  "merchantTransactionId": "0ce72cfd-014d-4256-a006-a56601b2ffc4",
  "amounts": {
    "currencyCode": "EUR",
    "transactionValue": 20
  },
  "transactionMethod": {
    "intent": {
      "card": "authorisation",
      "paypal": "authorisation"
    }
  }
}

Use your token ID to encrypt this data structure by SHA256. You can find your token ID in the Unity Portal. Here's an example of an hmacSignature after you've encrypted the data:

1DE2DFC390D7CD746A972140F26846AFA81CF85F5A0BAABA95DBC95301795EA6

You can now put together your Authorization header. It follows this format: PXP-UST1 {tokenId}:{timestamp}:{hmacSignature}. For example:

"PXP-UST1 9aac6071-38d0-4545-9d2f-15b936af6d7f:1754701373:1DE2DFC390D7CD746A972140F26846AFA81CF85F5A0BAABA95DBC95301795EA6"

Lastly, send your request to the Sessions API. You'll need to add a request ID of your choice and include your client ID, which you can find in the Unity Portal.

Here's a full example of what your request might look like:

curl -i -X POST \
  'https://api-services.pxp.io/api/v1/sessions' \
  -H 'Authorization: "PXP-UST1 9aac6071-38d0-4545-9d2f-15b936af6d7f:1754701373:1DE2DFC390D7CD746A972140F26846AFA81CF85F5A0BAABA95DBC95301795EA6"' \
  -H 'X-Request-Id: "550e8400-e29b-41d4-a716-446655440000"' \
  -H 'X-Client-Id: "f47ac10b-58cc-4372-a567-0e02b2c3d479"' \
  -H 'Content-Type: application/json' \
  -d '{
  "merchant": "MERCHANT-1",
  "site": "SITE-1",
  "sessionTimeout": 120,
  "merchantTransactionId": "0ce72cfd-014d-4256-a006-a56601b2ffc4",
  "amounts": {
    "currencyCode": "EUR",
    "transactionValue": 20
  },
  "transactionMethod": {
    "intent": {
      "card": "authorisation",
      "paypal": "authorisation"
    }
  }
}'

If your request is successful, you'll receive a 200 response containing the session data.

{
  "sessionId": "c5f0799b-0839-43ce-abc5-5b462a98f250",
  "hmacKey": "904bc42395d4af634e2fd48ee8c2c7f52955a1da97a3aa3d82957ff12980a7bb",
  "encryptionKey": "20d175a669ad3f8c195c9c283fc86155",
  "sessionExpiry": "2025-05-19T13:39:20.3843454Z",
  "allowedFundingTypes": {
    "cards": [
      "Visa",
      "Diners",
      "Mastercard",
      "AmericanExpress"
    ],
    "wallets": {
      "paypal": {
        "allowedFundingOptions": [
          "paylater", 
          "paypal"
        ],
        "merchantId": "ST9US6Q5XW2KN"
      },
      "applepay": {
        "merchantId": "merchant.com.yourcompany.store"
      },
      "paze": {
        "clientId": "your-paze-client-id",
        "merchantCategoryCode": "5812"
      }
    }
  },
  "restrictions": {
    "card": {
      "ownerTypes": ["Consumer"],
      "fundingSources": ["Credit", "Debit"]
    }
  }
}
ParameterDescription
sessionId
string (UUID)
The unique identifier for the newly-created session.
hmacKey
string
The HMAC key generated for securing session communications.
encryptionKey
string
A key used for encrypting sensitive session data during communication.
sessionExpiry
string
The timestamp indicating when the session will expire, in ISO 8601 format.
allowedFundingTypes
object
Details about the funding types allowed for this session.

Possible values:
  • cards
  • wallets
allowedFundingTypes.cards
array of strings or null
The list of supported card schemes.
allowedFundingTypes.wallets
object or null
Details about the supported digital wallets.
allowedFundingTypes.wallets.paypal
object or null
PayPal wallet configuration.
allowedFundingTypes.wallets.paypal.allowedFundingOptions
array of strings
The list of PayPal funding options available. Possible values: paypal, paylater, credit.
allowedFundingTypes.wallets.paypal.merchantId
string
The PayPal merchant ID associated with this session.
allowedFundingTypes.wallets.applepay
object or null
Apple Pay wallet configuration.
allowedFundingTypes.wallets.applepay.merchantId
string
The Apple Pay merchant ID to be used for this session.
restrictions
object (optional)
Card restrictions such as ownerTypes and fundingSources. Pass through to SessionData when returned by your backend.

Step 4: Configure your iOS project

Depending on which payment methods you plan to support, you'll need to configure your Xcode project accordingly.

Add required capabilities

  1. In Xcode, select your project target.
  2. Go to the Signing & Capabilities tab.
  3. Click + Capability and add:
    • Apple Pay: Required for Apple Pay functionality.

Configure your merchant ID

In the Apple Pay capability section, add your merchant ID:

  1. Click the + button under Merchant IDs.
  2. Enter your merchant ID (e.g., merchant.com.yourcompany.store). Ensure it matches exactly with your Apple Developer Console configuration.

Update Info.plist

Add the following entries to your Info.plist:

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <false/>
    <key>NSAllowsArbitraryLoadsInWebContent</key>
    <false/>
</dict>

Step 5: Initialise the SDK and create components

To initialise the SDK, you need to pass the session data from Step 3 back to your iOS application, along with details about the environment, owner ID and type, merchant shopper ID, and transaction data.

Once the SDK is initialised, you can create payment components for your desired payment methods.

import UIKit
import PXPCheckoutSDK

class ViewController: UIViewController {
    
    private var pxpCheckout: PxpCheckout?
    private var applePayComponent: ApplePayButtonComponent?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        Task {
            await initialiseTheSDK()
        }
    }
    
    private func initialiseTheSDK() async {
        do {
            // 1. Get the session data from the back-end
            let sessionData = try await getSessionDataFromBackend()
            
            // 2. Create checkout configuration
            let config = CheckoutConfig(
                environment: .test,
                session: sessionData,
                transactionData: TransactionData(
                    amount: Decimal(25.00),
                    currency: "USD",
                    entryType: .ecom,
                    intent: TransactionIntentData(
                        card: .authorisation,
                        paypal: nil
                    ),
                    merchantTransactionId: UUID().uuidString,
                    merchantTransactionDate: { Date() }
                ),
                merchantShopperId: "Shopper_01",
                ownerType: "merchantGroup",
                ownerId: "Unity",
                kountDisabled: false // OPTIONAL: Set to true to disable Kount fraud detection
            )
            
            // 3. Initialise the SDK
            let pxpCheckoutSdk = try PxpCheckout.initialize(config: config)
            self.pxpCheckout = pxpCheckoutSdk
            
            setupApplePayComponent()
            
        } catch {
            showError("Failed to initialise SDK: \(error.localizedDescription)")
        }
    }
    
    private func setupApplePayComponent() {
        guard let pxpCheckout = pxpCheckout else { return }
        
        // Create Apple Pay component configuration
        let config = ApplePayButtonComponentConfig()
        config.countryCode = "US"
        config.currencyCode = "USD"
        config.supportedNetworks = [.visa, .masterCard, .amex, .discover]
        config.merchantCapabilities = [.threeDSecure]
        config.buttonType = .buy
        config.buttonStyle = .black
        config.requiredBillingContactFields = [.postalAddress, .name, .emailAddress]
        config.requiredShippingContactFields = [.postalAddress, .name, .phoneNumber]
        
        // Required: Set the total payment amount
        config.totalPaymentItem = ApplePayPaymentSummaryItem(
            amount: Decimal(25.00),
            type: .final,
            label: "Your Store Name"
        )
        
        // Set up callbacks on config
        config.onPreAuthorisation = { [weak self] async in
            self?.handlePreAuthorisation()
        }
        
        config.onPostAuthorisation = { [weak self] submitResult, applePayResult in
            self?.handlePostAuthorisation(submitResult: submitResult, applePayResult: applePayResult)
        }
        
        config.onError = { [weak self] error in
            self?.showError("Apple Pay error: \(error.errorMessage)")
        }
        
        config.onCancel = { [weak self] error in
            print("Apple Pay cancelled: \(error.errorMessage)")
        }
        
        // Create the component
        do {
            let component = try pxpCheckout.create(.applePayButton, componentConfig: config)
            applePayComponent = component as? ApplePayButtonComponent
            
            // Use buildContent() in SwiftUI to render
            // applePayComponent?.buildContent()
        } catch {
            showError("Failed to create Apple Pay component: \(error.localizedDescription)")
        }
    }
    
    private func handlePreAuthorisation() -> ApplePayTransactionInitData? {
        return ApplePayTransactionInitData(
            riskScreeningData: RiskScreeningData(
                performRiskScreening: true,
                userIp: "192.168.1.100",
                account: RiskScreeningAccount(
                    id: "user_12345678",
                    creationDateTime: ISO8601DateFormatter().date(from: "2024-01-15T10:30:00Z")
                ),
                items: [
                    RiskScreeningItem(
                        price: Decimal(25.00),
                        quantity: 1,
                        category: "General"
                    )
                ],
                fulfillments: [
                    RiskScreeningFulfillment(
                        type: .shipped,
                        recipientPerson: RiskScreeningRecipientPerson(
                            phoneNumber: "+1234567890"
                        )
                    )
                ]
            )
        )
    }
    
    private func handlePostAuthorisation(submitResult: BaseSubmitResult, applePayResult: ApplePayResult) {
        if let merchantResult = submitResult as? MerchantSubmitResult {
            print("Payment success: \(merchantResult.systemTransactionId)")
            // Handle successful payment
        } else if let failedResult = submitResult as? FailedSubmitResult {
            showError("Payment failed: \(failedResult.errorReason ?? "")")
        }
    }
    
    private func getSessionDataFromBackend() async throws -> SessionData {
        // Implement your backend session request here
        // This should match the curl request shown above
        fatalError("Implement session data retrieval from your backend")
    }
    
    private func showError(_ message: String) {
        DispatchQueue.main.async {
            let alert = UIAlertController(title: "Error", message: message, preferredStyle: .alert)
            alert.addAction(UIAlertAction(title: "OK", style: .default))
            self.present(alert, animated: true)
        }
    }
}
ParameterDescription
environment
Environment
required
The environment type.

Possible values:
  • .test
  • .live
session
SessionData
required
Details about the checkout session.
transactionData
TransactionData
required
Details about the transaction.
transactionData.amount
Decimal
required
The transaction amount (e.g., Decimal(25.00)).
transactionData.currency
String
required
The currency code associated with the transaction, in ISO 4217 format (e.g., "USD", "EUR", "GBP").
transactionData.entryType
EntryType
required
The entry type.

Possible values:
  • .ecom
  • .moto
transactionData.intent
TransactionIntentData
required
The transaction intent data containing separate intents for different payment methods. Both parameters are optional - you can specify only the payment method you need.

Use TransactionIntentData(card: CardIntentType?, paypal: PayPalIntentType?).

Card intent values:
  • .authorisation - Pre-authorise funds for later capture
  • .estimatedAuthorisation - Pre-auth with estimated amount
  • .purchase - Standard immediate payment
  • .payout - Send funds to cardholder
  • .verification - Verify card without charging

PayPal intent values:
  • .authorisation - Pre-authorise funds for later capture
  • .purchase - Standard immediate payment
  • .payout - Send funds to PayPal account holder (requires paypalConfig)

Example for payout-only: TransactionIntentData(card: nil, paypal: .payout).

For Paze, set the card intent (.authorisation or .purchase), currency to "USD", and entryType to .ecom. See Paze.

Learn more about intents.
transactionData.merchantTransactionId
string
required
A unique identifier for this transaction.
transactionData.merchantTransactionDate
() -> Date
required
A closure that returns the date and time of the transaction. Use { Date() } for current date.
transactionData.cardAcceptorName
String?
Card acceptor name for the transaction.
transactionData.recurring
RecurringType?
Recurring payment configuration. Use RecurringType(frequencyInDays: Int?, frequencyExpiration: String?) to specify recurring payment details.
transactionData.linkId
String?
Transaction link ID for linking related transactions.
merchantShopperId
string
required
A unique identifier for this shopper.
ownerType
String?
The type of owner as a string.

Possible values:
  • "merchantGroup"
  • "merchant"
  • "site"
ownerId
string
required
The identifier of the owner related to the ownerType.
onGetShippingAddress
(() async -> ShippingAddress?)?
An async callback function to dynamically fetch the shipping address. The SDK will call this when it needs the shipping address.

Example:
swift{% br / %}onGetShippingAddress: {{% br / %} return await fetchShippingAddressFromBackend(){% br / %}}{% br / %}
The ShippingAddress structure contains:
  • address: The first line of the shipping address (String)
  • addressLine2: The second line of the shipping address (String?)
  • city: The city of the shipping address (String)
  • postalCode: The postal or ZIP code (String)
  • countryCode: The 2-character country code in ISO-3166-1 alpha-2 format (String)
localisation
Localisation?
Custom UI text overrides for localization.
locale
String?
Locale for language/region (e.g., "en-US", "es-ES", "el-GR").
paypalConfig
PayPalConfig?
PayPal-specific configuration. Required for PayPal payout transactions. Learn more.
restrictions
Restrictions?
Optional card restrictions for owner types (corporate or consumer) and funding sources (credit, debit, or prepaid). When both session and config restrictions are provided, they're merged as a union.
kountDisabled
Bool
Disable Kount fraud detection. Default: false (fraud detection enabled).
onGetShopper
(() async -> TransactionShopper?)?
An async callback function to dynamically fetch shopper information.
analyticsEvent
((BaseAnalyticsEvent) -> Void)?
Handler for analytics events.

PayPal payout configuration

For PayPal payout integrations, you must configure paypalConfig with payout-specific settings. This is required when using .payout intent for PayPal transactions.

Basic PayPal payout setup

let config = CheckoutConfig(
    environment: .test,
    session: sessionData,
    transactionData: TransactionData(
        amount: Decimal(100.00),
        currency: "USD",
        entryType: .ecom,
        intent: TransactionIntentData(
            card: nil,
            paypal: .payout  // Must use .payout intent
        ),
        merchantTransactionId: UUID().uuidString,
        merchantTransactionDate: { Date() }
    ),
    merchantShopperId: "customer-123",
    ownerId: "merchant-id",
    kountDisabled: false, // OPTIONAL: Set to true to disable Kount fraud detection
    paypalConfig: PayPalConfig(
        payout: PayPalPayoutConfig(
            paypalWallet: PayPalWallet(
                email: "recipient@example.com",
                payerId: "PAYERID123",  // Max 13 alphanumeric characters
                proceedPayoutWithSdk: false  // false = automatic payout
            )
        )
    )
)

PayPal payout with approval callback

Set proceedPayoutWithSdk: true on PayPalWallet or VenmoWallet to gate whether the payout submission component runs its approval callback before processing. Configure onPrePayoutSubmit on the payout submission component — not on CheckoutConfig:

let config = CheckoutConfig(
    environment: .test,
    session: sessionData,
    transactionData: TransactionData(
        amount: Decimal(100.00),
        currency: "USD",
        entryType: .ecom,
        intent: TransactionIntentData(
            card: nil,
            paypal: .payout
        ),
        merchantTransactionId: UUID().uuidString,
        merchantTransactionDate: { Date() }
    ),
    merchantShopperId: "customer-123",
    ownerId: "merchant-id",
    kountDisabled: false, // OPTIONAL: Set to true to disable Kount fraud detection
    paypalConfig: PayPalConfig(
        payout: PayPalPayoutConfig(
            paypalWallet: PayPalWallet(
                email: "recipient@example.com",
                payerId: "PAYERID123",
                proceedPayoutWithSdk: true
            )
        )
    )
)

let pxpCheckout = try PxpCheckout.initialize(config: config)

let payoutConfig = PayoutSubmissionComponentConfig()
payoutConfig.onPrePayoutSubmit = { async in
    // Return approval result before payout proceeds
    PrePayoutSubmitResult(approved: true)
}

let payoutComponent = try pxpCheckout.create(
    .payoutSubmission,
    componentConfig: payoutConfig
)

Venmo payout configuration

let config = CheckoutConfig(
    environment: .test,
    session: sessionData,
    transactionData: TransactionData(
        amount: Decimal(50.00),
        currency: "USD",
        entryType: .ecom,
        intent: TransactionIntentData(
            card: nil,
            paypal: .payout
        ),
        merchantTransactionId: UUID().uuidString,
        merchantTransactionDate: { Date() }
    ),
    merchantShopperId: "customer-123",
    ownerId: "merchant-id",
    kountDisabled: false, // OPTIONAL: Set to true to disable Kount fraud detection
    paypalConfig: PayPalConfig(
        payout: PayPalPayoutConfig(
            venmoWallet: VenmoWallet(
                recipientType: .email,  // or .phone, .userHandle
                receiver: "user@example.com",  // or phone number, or @username
                proceedPayoutWithSdk: false
            )
        )
    )
)

PayPal payout key points

  • PayerId validation: Must be max 13 characters, alphanumeric only.
  • Intent requirement: Must set paypal: .payout in TransactionIntentData.
  • proceedPayoutWithSdk flag:
    • false (default): SDK proceeds automatically with payout using provided Payer ID.
    • true: configure onPrePayoutSubmit on the payout submission component, not on CheckoutConfig.
  • Email vs PayerId: Provide either email or payerId (or both) for PayPal wallet identification.

For a complete guide on implementing PayPal payouts, see PayPal payouts.

What's next?

You've successfully installed the SDK and created your first payment component! Here are some recommended next steps:

  • For Apple Pay: Learn more about Apple Pay.
  • For PayPal: Learn more about PayPal button component documentation.
  • For Paze: Learn more about Paze for portal setup, URL callback scheme, and component integration.
  • Testing: Use the test environment to validate your integration before going live.
  • Webhooks: Subscribe to webhooks in the Unity Portal for real-time payment notifications. Learn more about webhooks.