The xMoney iOS SDK provides a drop-in Payment Sheet, an embeddable Payment Element, and standalone Apple Pay. All surfaces use PaymentConfig, PaymentIntent, and PaymentResult.
Current release: 1.0.0.
- iOS 15 or later
- Swift 5.9 or later
- Xcode 15 or later
- A publishable xMoney key
- A backend that creates and signs orders
Store the xMoney private key on your backend. The app should receive only the publishable key, order payload, and checksum.
Add the package dependency:
.package(
url: "https://github.com/xMoney-Payments/xmoney-ios.git",
from: "1.0.0"
)Link XMoneyPaymentSheet for Payment Sheet. It includes Payment Element and Apple Pay. For a smaller embedded integration, link XMoneyPaymentElement and add XMoneyApplePay only when you need Apple Pay.
pod 'XMoneyPaymentSheet', '1.0.0'
# Or select individual surfaces:
# pod 'XMoneyPaymentSheet', :subspecs => ['PaymentElement']
# pod 'XMoneyPaymentSheet', :subspecs => ['ApplePay']CocoaPods exposes all subspecs through import XMoneyPaymentSheet.
Your backend creates and signs the order. Build an intent from the returned values:
let intent = PaymentIntent(
orderPayload: OrderPayload(payloadFromYourServer),
orderChecksum: OrderChecksum(checksumFromYourServer)
)See Create the order on your backend for the shared server responsibilities.
Payment Sheet owns the complete checkout UI and Pay button.
import XMoneyPaymentSheet
let configuration = PaymentConfig(
publicKey: "pk_test_...",
paymentMethods: .init(
applePay: .init(enabled: true)
),
card: .init(
savedCards: .init(enabled: true)
)
)
let sheet = PaymentSheet(configuration: configuration)
sheet.present(from: self, intent: intent) { result in
handlePaymentResult(result)
}Idle close, drag, or scrim dismissal returns .canceled without consuming the order. Once payment or 3DS starts, terminal results consume the signed order.
Payment Element places the payment form directly in your layout. It does not link Apple Pay automatically.
import XMoneyPaymentElement
import XMoneyApplePay
ApplePay.register()
let embedded = EmbeddedPayment(configuration: configuration) { result in
handlePaymentResult(result)
}
let element = PaymentElement(payment: embedded) { event in
if case .ready = event {
hideCheckoutLoader()
}
}
view.addSubview(element)
try await element.prepare(intent: intent)Call ApplePay.register() before prepare when the embedded configuration enables Apple Pay. Keep the element mounted while it prepares and while the order changes.
To use your own Pay button, hide the SDK button and call confirm() after the element reports .ready:
let configuration = PaymentConfig(
publicKey: "pk_test_...",
card: .init(
submitButton: .init(visible: false)
)
)
embedded.confirm()Gate the merchant button with embedded.isInteractionEnabled.
import XMoneyApplePay
let applePay = ApplePay(configuration: configuration) { result in
handlePaymentResult(result)
}
applePay.present(from: self, intent: intent)You can also attach present to ApplePayButton or ApplePayButtonView. A dismissal before wallet authorization returns .canceled and does not consume the intent.
- Enable Apple Pay in
paymentMethods.applePay. - Create a Merchant ID in the Apple Developer portal.
- In Xcode, add the Apple Pay capability to your app target and select the Merchant ID.
- Make sure the Merchant ID matches the
merchantIdconfigured for your xMoney site. - Test on a physical device with an eligible card in Wallet.
See Apple Pay for activation and integration options.
func handlePaymentResult(_ result: PaymentResult) {
switch result {
case .complete(let transaction):
confirmOrderOnBackend(transaction)
case .failed(let error):
showPaymentError(error.message)
case .canceled:
showCheckout()
}
}Use the result to update the app, then confirm final payment status on your backend before fulfillment.
When the amount, currency, or cart changes, request a new signed order and rebind the mounted element:
try await embedded.updateOrder(intent: nextIntent)Do not replace the element with a loader. Interaction is disabled until the new intent is ready. A complete, failed, or post-submit canceled result consumes the current intent; prepare a new one before another attempt.
PaymentConfig controls saved cards, card validation, field grouping, submit-button intent, locale, light/dark style, colors, and radii.
let configuration = PaymentConfig(
publicKey: "pk_test_...",
card: .init(
savedCards: .init(enabled: true, optInVisible: true),
validationMode: .onTouched,
inputs: .init(grouping: .condensed)
),
options: .init(
locale: "en-US",
style: .automatic
)
)Supported UI languages are English (en), Greek (el), Romanian (ro), Bulgarian (bg), Hungarian (hu), and Polish (pl). Region tags such as pl-PL are supported.
For cardholder name verification, provide CardHolderVerification in the card configuration and return true to continue:
card: .init(
cardHolderVerification: CardHolderVerification(
name: CardHolderName(firstName: "John", lastName: "Doe"),
onCardHolderVerification: { result in
result.status == .matched
}
)
)The site must have cardholder name verification enabled.
- Review the native SDK shared model.
- Use test cards in the test environment.
- Explore the complete iOS SDK samples.