CtrlK
BlogDocsLog inGet started
Tessl Logo

thiennc-tesoglobal/ios-skills

Community-maintained Agent Skills for complete Swift and Apple-platform app delivery.

72

Quality

90%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Medium

Suggest reviewing before use

Overview
Quality
Evals
Security
Files

SKILL.mdskills/passkit/

name:
passkit
description:
Integrate Apple Pay and Wallet passes with PassKit. Use for payment buttons and requests, authorization, merchant and shipping fields, pass creation or updates, Add to Wallet flows, and eligible physical-goods, service, donation, or recurring-payment checkout.

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 PKPaymentRequest supports 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

  1. Enable the Apple Pay capability in Xcode and configure a Merchant ID (merchant.com.example).
  2. 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 paymentSummaryItems MUST 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 PKPaymentRequest can 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 PayWithApplePayButton or PKPaymentButton used
  • 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

skills

passkit

.mcp.json

README.md

tile.json