Basic Integration
Accept credit card payments using the SDK's built-in CreditCardView.
Step 1: Create a Payment Request
Create a PaymentRequest with your API key and payment details.
import MoyasarSdk
func createPaymentRequest() -> PaymentRequest {
do {
return try PaymentRequest(
apiKey: "pk_test_YOUR_API_KEY",
amount: 1000, // 10.00 SAR (amount in smallest currency unit)
currency: "SAR",
description: "Order #12345",
metadata: [
"order_id": .stringValue("ios_order_3214124"),
"user_id": .integerValue(12345)
],
manual: false, // Auto-capture (set true to authorize only)
saveCard: false, // Set true to tokenize for recurring payments
givenID: UUID().uuidString, // Optional: for idempotency
// Note: The sum of all split amounts must equal the total payment amount (1000 = 800 + 200)
splits: [ // Optional: payment splitting for marketplace
PaymentSplit(
recipientId: "7d2d0797-a2be-40fe-bb1b-1fdec9824c95",
amount: 800
),
PaymentSplit(
recipientId: "327680bb-d790-4643-8e10-31455a1ab3a6",
amount: 200,
reference: "optional-reference-for-split-1fcfcbe9-ba75-4eed",
description: "Platform processing fee",
feeSource: true,
refundable: false
)
]
)
} catch {
fatalError("Invalid API key: \(error)")
}
}
PaymentRequest Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
apiKey | String | Yes | Your publishable API key (starts with pk_test_ or pk_live_) |
amount | Int | Yes | Amount in smallest currency unit (e.g., 10 SAR = 1000 Halalas) |
currency | String | Yes | Three-letter ISO currency code (e.g., "SAR") |
description | String | Yes | Payment description shown on the payment page |
metadata | [String: MetadataValue] | No | Custom key-value pairs for tracking |
manual | Bool | No | true = authorize only, false = authorize + capture (default: false) |
saveCard | Bool | No | true = generate token for recurring payments (default: false) |
givenID | String | No | Unique ID for idempotency (prevents duplicate payments) |
allowedNetworks | [PKPaymentNetwork] | No | Restrict card networks (default: all supported) |
payButtonType | ButtonType | No | Button text style (default: .pay) |
splits | [PaymentSplit] | No | Payment splitting for marketplaces (see below) |
PaymentSplit Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
recipientId | String | Yes | The recipient's ID (merchant or platform account) |
amount | Int | Yes | Amount in smallest currency unit to split |
reference | String | No | Custom reference for the split transaction |
description | String | No | Description of the split (e.g., "Platform fee") |
feeSource | Bool | No | true = this recipient pays the processing fees (default: false) |
refundable | Bool | No | true = this split is refundable (default: true) |
Important: The sum of all split amounts must equal the total payment amount. For example, if the payment amount is
10000(100.00 SAR), the splits must add up to exactly10000.
Step 2: Add the Credit Card View
- SwiftUI
- UIKit
import SwiftUI
import MoyasarSdk
struct ContentView: View {
var body: some View {
CreditCardView(
request: createPaymentRequest()
) { result in
handlePaymentResult(result)
}
}
func handlePaymentResult(_ result: PaymentResult) {
switch result {
case .completed(let payment):
handleCompletedPayment(payment)
case .failed(let error):
handlePaymentError(error)
case .canceled:
print("Payment canceled")
@unknown default:
break
}
}
}
import UIKit
import SwiftUI
import MoyasarSdk
class PaymentViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
setupCreditCardView()
}
func setupCreditCardView() {
let creditCardView = CreditCardView(
request: createPaymentRequest()
) { result in
self.handlePaymentResult(result)
}
let hostingController = UIHostingController(rootView: creditCardView)
hostingController.view.translatesAutoresizingMaskIntoConstraints = false
addChild(hostingController)
view.addSubview(hostingController.view)
hostingController.didMove(toParent: self)
NSLayoutConstraint.activate([
hostingController.view.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
hostingController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
hostingController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
hostingController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])
}
func handlePaymentResult(_ result: PaymentResult) {
switch result {
case .completed(let payment):
handleCompletedPayment(payment)
case .failed(let error):
handlePaymentError(error)
case .canceled:
print("Payment canceled")
@unknown default:
break
}
}
}
Step 3: Handle the Payment Result
func handleCompletedPayment(_ payment: ApiPayment) {
switch payment.status {
case .paid:
print("Payment successful: \(payment.id)")
// Navigate to success screen
case .failed:
print("Payment failed")
// Show error to user
case .authorized:
print("Payment authorized (not captured)")
// Capture later via API
default:
print("Payment status: \(payment.status)")
}
}
func handlePaymentError(_ error: MoyasarError) {
switch error {
case .apiError(let apiError):
print("API error: \(apiError.message ?? "Unknown")")
case .apiKeyNotSet:
print("API key not configured")
case .networkError:
print("Network connection failed")
case .webviewTimedOut:
print("3DS authentication timed out")
case .webviewUnexpectedError(_, let webError):
print("3DS error: \(webError.localizedDescription)")
default:
print("Unexpected error: \(error)")
}
}
PaymentResult Cases
| Case | Description |
|---|---|
.completed(ApiPayment) | Payment flow finished successfully |
.failed(MoyasarError) | Payment failed with an error |
.canceled | User canceled the payment |
.saveOnlyToken(ApiToken) | Token created when createSaveOnlyToken is true |
Handling 3DS Authentication Errors
If payment fails during 3DS authentication, the result will be .failed with a webview... error. The payment may still be paid on the server.
func handlePaymentError(_ error: MoyasarError) {
// Check for 3DS-related errors
switch error {
case .webviewNotConnectedToInternet(let payment),
.webviewTimedOut(let payment),
.webviewUnexpectedError(let payment, _):
// Fetch payment status from API to confirm
fetchPaymentStatus(payment.id)
default:
handlePaymentError(error)
}
}
Set Custom Language
The SDK follows the system language by default. Override it to force Arabic or English.
// Call in AppDelegate (UIKit) or App init (SwiftUI)
MoyasarLanguageManager.shared.setLanguage(.ar) // or .en
Next Steps
- Apple Pay Integration — Add wallet payments
- STC Pay Integration — Add STC Pay support
- Custom Credit Card UI — Build your own card form
- Testing Guide — Test with sandbox cards