XPay Swift SDK
XPay Payment Kit for Swift is an embedded payment system that allows you to collect payments directly from users within your iOS Swift applications. This package is highly customizable, enabling you to tailor the appearance and functionalities of the payment form to align seamlessly with your app's style and theme.
Features
Seamless Payment Integration
Easily integrate payment functionalities into your IOS app without redirecting users to external applications or pages.
Embedded Authentication
Perform OTP authentication within your app, ensuring a smooth and secure user experience.
Custom Styling
Style the payment form according to your app's theme with customizable labels, placeholders, and more.
Event Handling
Utilize built-in events such as onBinDiscount and onReady to manage changes and validate inputs dynamically.
Getting started
To incorporate the XPay embedded payment system into your IOS application, start by adding the following package dependency to your app:
// For production,, use latest released version
https://github.com/XStakCommerce/XPay-Swift-SDK
// For staging, please change from version to branch type using the branch name stage.E2E Integration Sample Repo
E2E Integration Sample Repo using Swift & StoryBoard
Usage
To use the XPay SDK in your app, follow these steps:
Import the Package
import XPayPaymentKitInitialize the SDK Controller
Create an instance of XPayController:
XPayController for each payment method. This ensures proper configuration and isolation between different payment flows.// Initialize separate controllers for each payment method
let cardController = XPayController()
let jazzCashController = XPayController()
let easypaisaController = XPayController()Initialize the SDK KeysConfiguration
Create an instance of KeysConfiguration with the necessary credentials available on the XPay dashboard:
KeysConfiguration instance across all payment methods (e.g., Card, JazzCash, Easypaisa). No need to create separate key configurations for each one.let keysConfiguration = KeysConfiguration(accountId: "your_account_id", publicKey: "your_public_key", hmacKey: "your_hmac_key")Embed the Payment Form
Use the respective XPay form components in your SwiftUI view. Each payment method has its own view. Reuse the same keysConfiguration across all, but make sure each form uses its own controller instance.
var body: some View {
VStack(spacing: 20) {
// Card Payment Form
XPayPaymentForm(keysConfiguration: keysConfiguration, controller: cardController)
// JazzCash Payment Form
XPayJazzCashPaymentForm(keysConfiguration: keysConfiguration, controller: jazzCashController)
// Easypaisa Payment Form
XPayEasyPaisaPaymentForm(keysConfiguration: keysConfiguration, controller: easypaisaController)
}
}Enabling Additional Card Types (AMEX, PayPak)
By default, the XPayPaymentForm supports Visa and Mastercard. If you want to allow additional card types such as AMEX or PayPak, you can specify them in the allowedCards property.
import XPaySDK
let paymentForm = XPayPaymentForm(
keysConfiguration: keysConfig,
customStyle: customStyleConfiguration,
onBinDiscount: { data in
print("Card: \(data)")
},
onReady: { ready in
isReady = ready
},
controller: cardPaymentController,
// Enable AMEX and PayPak in addition to Visa and Mastercard (default)
allowedCards: [.AMEX, .PAYPAK]
)
Custom Styling
Customize the payment form UI with your app seamlessly. The XPay payment form allows you to modify form style and appearance, making it adaptable to various design requirements.
Initializing and Applying Custom Styles
To customize the appearance of the payment forms, define shared style properties and pass a method-specific or combined inputConfiguration.
Shared Style Configuration (Used Across All Methods)
let inputStyle = InputStyle(height: 25, textColor: .black, textSize: 17, borderColor: .gray, borderRadius: 5, borderWidth: 1)
let inputLabelStyle = InputLabelStyle(fontSize: 17, textColor: .gray)
let onFocusInputStyle = OnFocusInputStyle(textColor: .black, textSize: 17, borderColor: .blue, borderWidth: 1)
let invalidStyle = InvalidStyle(borderColor: .red, borderWidth: 1, textColor: .red, textSize: 14)
let errorMessageStyle = ErrorMessageStyle(textColor: .red, textSize: 14)Input Configurations
// Card
let cardInputConfig = InputConfiguration(
cardNumber: InputField(label: "Card Number", placeholder: "Enter card number"),
expiry: InputField(label: "Expiry Date", placeholder: "MM/DD"),
cvc: InputField(label: "CVC1", placeholder: "cvc")
)
// JazzCash
let jazzCashInputConfig = InputConfiguration(
phoneNumber: InputField(label: "Phone Number", placeholder: "Enter phone number"),
cnic: InputField(label: "CNIC", placeholder: "cnic number")
)
// Easypaisa
let easypaisaInputConfig = InputConfiguration(
phoneNumber: InputField(label: "Phone Number", placeholder: "Enter phone number")
)
// Optional: Combined config (if preferred)
let combinedInputConfig = InputConfiguration(
cardNumber: ..., expiry: ..., cvc: ..., phoneNumber: ..., cnic: ...
)Apply Styles (Change inputConfig per method or use combined)
let customStyle = CustomStyleConfiguration(
inputConfiguration: cardInputConfig, // or jazzCashInputConfig / easypaisaInputConfig / combinedInputConfig
inputStyle: inputStyle,
inputLabelStyle: inputLabelStyle,
onFocusInputStyle: onFocusInputStyle,
invalidStyle: invalidStyle,
errorMessageStyle: errorMessageStyle
)Usage in SwiftUI View
After configuring your styles, apply them to the Payment forms to enhance the user interface:
var body: some View {
VStack(spacing: 20) {
XPayPaymentForm(keysConfiguration: keysConfiguration, customStyle: customStyle, controller: cardController)
XPayJazzCashPaymentForm(keysConfiguration: keysConfiguration, customStyle: customStyle, controller: jazzCashController)
XPayEasyPaisaPaymentForm(keysConfiguration: keysConfiguration, customStyle: customStyle, controller: easypaisaController)
}
}Element Events
Handle element-specific events to enhance the user experience:
onReady Event
This event triggers when all form fields are valid and the form is ready for submission.
var body: some View {
VStack(spacing: 20) {
// Card Payment Form
XPayPaymentForm(
keysConfiguration: keysConfiguration,
customStyle: customStyle,
onReady: { isReady in
self.isReady = isReady
},
controller: cardController
)
// JazzCash Payment Form
XPayJazzCashPaymentForm(
keysConfiguration: keysConfiguration,
customStyle: customStyle,
onReady: { isReady in
self.isReady = isReady
},
controller: jazzCashController
)
// Easypaisa Payment Form
XPayEasyPaisaPaymentForm(
keysConfiguration: keysConfiguration,
customStyle: customStyle,
onReady: { isReady in
self.isReady = isReady
},
controller: easypaisaController
)
}
}onBinDiscount
Receive data related to the card's BIN as the user inputs their card number, which can be used for implementing discounts or promotional offers.
var body: some View {
VStack {
XPayPaymentForm(keysConfiguration: keysConfiguration, onBinDiscount: {data in
print("bin details : \(data)")
} controller: cardController)
}
}Confirming Payment
You should perform a few steps to proceed with the payment confirmation when all form fields are valid and the onReady event has returned true. First, ensure you have initiated a server-side API call to create a payment intent. This create intent API is responsible for generating the clientSecret.
Server-Side Payment Intent Creation
Before invoking the payment confirmation on the client side, your backend should call the create intent API to obtain:
clientSecret: A secret key used to initiate the payment process securely.
Confirming the Payment
Once you have the necessary keys from your backend, use the XPayController initialized earlier to call the confirmPayment method. Here’s how you can implement this in your IOS app:
The method signature remains the same for all payment methods — only the controller changes depending on the selected method.
func confirmCardPayment() {
cardController.confirmPayment(
customerName: "Customer Name",
clientSecret: "client_secret_from_intent_api",
paymentResponse: { data in
let errorValue = data["error"] as? Bool ?? false
let message = data["message"] as? String ?? "payment error"
let paymentStatus = data["status"] as? String ?? "Failed"
}
)
}
func confirmJazzCashPayment() {
jazzCashController.confirmPayment(
customerName: "Customer Name",
clientSecret: "client_secret_from_intent_api",
paymentResponse: { data in
let errorValue = data["error"] as? Bool ?? false
let message = data["message"] as? String ?? "payment error"
let paymentStatus = data["status"] as? String ?? "Failed"
}
)
}
func confirmEasypaisaPayment() {
easypaisaController.confirmPayment(
customerName: "Customer Name",
clientSecret: "client_secret_from_intent_api",
paymentResponse: { data in
let errorValue = data["error"] as? Bool ?? false
let message = data["message"] as? String ?? "payment error"
let paymentStatus = data["status"] as? String ?? "Failed"
}
)
}ℹ️ Replace "client_secret_from_intent_api" with the actual secret received from your backend.
Confirm Payment Response
The response from the confirmPayment method call will be returned as a Swift dictionary containing three keys:
error: A boolean that indicates whether the payment was unsuccessful. If true, it means the payment failed.message: A string containing a message from the server. This message provides details about the payment outcome or error information.status: A string containing the status of payment.
Clear Method
The clear() method is used to reset the payment form fields. This is useful when you want to clear the input, for example, after a successful payment or when the user taps a "Reset" button.
Each payment method’s controller can call the same clear() function.
// For Card
cardController.clear()
// For JazzCash
jazzCashController.clear()
// For Easypaisa
easypaisaController.clear()