Skip to main content

Apple Pay

Apple Pay is self-submitting: the PKPaymentButton it renders is the Pay button. The tap opens PassKit's sheet, the authorization selects the method as primary and runs /validate.

Setup​

ProductPurseCheckoutApplePay (brings PassKit)
InstallPluginRegistry.shared.install(ApplePayModule(configuration:)), once, before you build a checkout
EntitlementApple Pay (In-App Payments) enabled in Signing & Capabilities, listing the same merchant identifier
DashboardApple Pay activated on the entity with a gateway (Adyen, Ingenico/Worldline, or another partner). Country, currency, capabilities and accepted networks are configured there and reach the app through /init
KeysNone in the app. A payment processing certificate must exist for the merchant identifier with that PSP

The merchant identifier is the one thing no server can supply: it is bound to your app's entitlement, so it comes from your code.

PluginRegistry.shared.install(ApplePayModule(configuration: ApplePayConfiguration(
merchantIdentifier: "merchant.com.example.store", // must match the entitlement exactly
merchantName: "Example Store" // the sheet's total line, when /init names nobody
)))

Everything else about the sheet comes from /init: the SDK shapes the request per PSP variant (Adyen, Ingenico/Worldline, or the default), and falls back to Cartes Bancaires, Mastercard and Visa when the response lists no networks.

Render​

Render the element as soon as the method is listed, and prepare() it: that is the POST /init that configures the sheet, and the button cannot present without it. Never call setPrimary for it, and never place a Pay button of yours next to it: submit() is a no-op for a self-submitting element.

PaymentElementView(element)
.frame(height: 48) // the branded button is the submit
.task { await element.prepare() }

element.isReady turns true once /init answered. hasUI is true, selfSubmitting is true.

Outcomes​

OutcomeWhen
completed(ValidationResult)The sheet was authorized and /validate answered without a redirect
returnedFromRedirect(url:)A further step followed and the shopper came back. Confirm the payment status on your backend
canceledThe shopper dismissed the sheet without authorizing. Nothing was charged; leave them able to try again or pick another method
failed(PurseError)/init failed, the sheet could not present, or the token could not be read

/init failing, the sheet failing to present and an unreadable token are also reported as plugin events (initFailed, clientError): the method moves into PARTNER_UI_FATAL_ERROR and stays unavailable for the session (Method states).

A failure from prepare() means the button was never usable: report it where the shopper already is rather than on a payment-result screen, and leave the other methods selectable.

When the device cannot pay​

Two different degradations:

SituationWhat happens
ApplePayModule installed with no configurationThe method stays listed. Its element has hasUI false; submitting reports failed with Apple Pay needs a merchant id: install ApplePayModule(configuration:)
PKPaymentAuthorizationController.canMakePayments() is falseWhen the checkout is created, the plugin refuses the device: the method moves into PLUGIN_INCOMPATIBLE, which is filtered, and disappears from paymentMethods. Apple requires the button be hidden on such a device. An element built before that check lands has hasUI false and submit does nothing: no button, no outcome

An element without UI never reports readiness, so element.isReady also stays false. Gate on hasUI or isReady before you reserve room for the button, so an express row does not render an empty box.

Two sheets, one session​

A second submit() while one is in flight returns the in-flight task rather than starting another payment, and a second /validate for one session is refused by the API. After a successful payment the session is spent.

Testing

Apple Pay has no sandbox flag in this SDK: nothing maps a PurseEnvironment to an Apple Pay environment. Use a sandbox tester account on a real device. The simulator cannot produce a usable payment token.

Troubleshooting​

SymptomCause
The method is not listedcanMakePayments() is false on this device (PLUGIN_INCOMPATIBLE), or the session does not offer applepay
The method is listed but the button never appearsThe module was installed without a configuration
failed, message lists the entitlement, the certificate and the requestPassKit refused to present and does not say why. Work down that list: the merchant id must be in the In-App Payments entitlement, a processing certificate must exist for it with this PSP, and the request's country, currency and networks must be usable on the device
failed with PARTNER_UI_ERROR, message Apple Pay /init returned no plugin_result.logsApple Pay is offered but not configured on the gateway. Check the dashboard
failed with PARTNER_UI_ERROR, message Apple Pay /init did not return a country code (or currency)The gateway's /init answer is incomplete. PKPaymentRequest refuses to present without them, so the SDK fails here where the cause is still known
failed, message call prepare() before present()The button was tapped before prepare() completed. Start it when the element is created
The method is listed but has no UI and submitting reports METHOD_NOT_IMPLEMENTEDApplePayModule was never installed. See Payment methods