PassKit
Accept Apple Pay payments for physical goods, real-world services, donations, and recurring subscriptions, and manage Wallet passes. Targets Swift 6.3 / iOS 26+.
Constraint: A single
PKPaymentRequestsupports at most one optional advanced request type (recurring, automatic reload, deferred, Apple Pay Later, or multi-token). Use separate requests if a transaction requires multiple modes.
Contents
- Setup & Availability
- Apple Pay Button
- Creating a Payment Request
- Authorizing Payments
- Wallet Passes
- Common Mistakes
- Review Checklist
- References
Setup & Availability
- Enable the Apple Pay capability in Xcode and configure a Merchant ID (
merchant.com.example). - Verify payment readiness before rendering checkout controls:
import PassKit
func isApplePayAvailable() -> Bool {
guard PKPaymentAuthorizationController.canMakePayments() else { return false }
return PKPaymentAuthorizationController.canMakePayments(
usingNetworks: [.visa, .masterCard, .amex],
capabilities: .threeDSecure
)
}
If canMakePayments(usingNetworks:capabilities:) returns true, Apple HIG requires Apple Pay to be presented as a primary payment method.
Apple Pay Button
Always use Apple-provided button views. Never draw custom Apple Pay logos:
// SwiftUI
import SwiftUI
import PassKit
PayWithApplePayButton(.buy) {
startPayment()
}
.payWithApplePayButtonStyle(.black)
.frame(height: 48)
// UIKit
let button = PKPaymentButton(paymentButtonType: .buy, paymentButtonStyle: .black)
button.addTarget(self, action: #selector(startPayment), for: .touchUpInside)
Creating a Payment Request
Construct a PKPaymentRequest with required merchant details and summary items. The final summary item represents the total charged and must use the merchant or company name:
func makePaymentRequest() -> PKPaymentRequest {
let request = PKPaymentRequest()
request.merchantIdentifier = "merchant.com.example.app"
request.countryCode = "US"
request.currencyCode = "USD"
request.supportedNetworks = [.visa, .masterCard, .amex]
request.merchantCapabilities = .threeDSecure
request.paymentSummaryItems = [
PKPaymentSummaryItem(label: "Coffee Beans", amount: NSDecimalNumber(string: "18.00")),
PKPaymentSummaryItem(label: "Shipping", amount: NSDecimalNumber(string: "4.50")),
PKPaymentSummaryItem(label: "Roasters Co.", amount: NSDecimalNumber(string: "22.50")) // Merchant total
]
return request
}
Authorizing Payments
Present the payment sheet with PKPaymentAuthorizationController and process token data on your payment processor:
final class CheckoutCoordinator: NSObject, PKPaymentAuthorizationControllerDelegate {
func paymentAuthorizationController(
_ controller: PKPaymentAuthorizationController,
didAuthorizePayment payment: PKPayment,
handler completion: @escaping (PKPaymentAuthorizationResult) -> Void
) {
// Send payment.token.paymentData to payment gateway (e.g. Stripe, Adyen)
Task {
do {
try await PaymentGateway.charge(token: payment.token)
completion(PKPaymentAuthorizationResult(status: .success, errors: nil))
} catch {
completion(PKPaymentAuthorizationResult(status: .failure, errors: [error]))
}
}
}
func paymentAuthorizationControllerDidFinish(_ controller: PKPaymentAuthorizationController) {
controller.dismiss()
}
}
Wallet Passes
Add passes (.pkpass) to Apple Wallet:
let pass = try PKPass(data: passData)
if PKPassLibrary().containsPass(pass) {
// Pass already exists in user's Wallet
} else {
let addController = PKAddPassesViewController(pass: pass)!
present(addController, animated: true)
}
Common Mistakes
- Incorrect final summary item: The last item in
paymentSummaryItemsMUST be the grand total and its label MUST be the business name. - Custom Apple Pay buttons: Drawing custom text or logos violates App Store guidelines and HIG.
- Mixing multiple advanced payment modes: A single
PKPaymentRequestcan specify only one advanced mode (e.g. recurring or deferred). - Hardcoding currency or country: Use ISO 4217 currency codes and ISO 3166 country codes matching your merchant account.
- Dismissing sheet without completion call: Always invoke the authorization
completion(...)handler before dismissing the payment controller.
Review Checklist
- Apple Pay capability and merchant identifier configured in Xcode
-
canMakePayments(usingNetworks:capabilities:)checked before rendering button - Official
PayWithApplePayButtonorPKPaymentButtonused - Final payment summary item matches grand total and displays merchant name
- Payment token dispatched securely to processor backend
- Authorization result completion handler called in all code paths
References
- Extended patterns (recurring/deferred payments, coupon codes, pass updates): references/wallet-passes.md
- PassKit framework
- PKPaymentRequest
- PKPaymentAuthorizationController
- PKPaymentButton
- PayWithApplePayButton
- AddPassToWalletButton
- PKPass
- PKAddPassesViewController
- PKPassLibrary
- PKPaymentNetwork
- Apple Pay HIG