Apple Pay

Allow customers to securely make payments using Apple Pay on their iPhone, iPad, and Apple Watch.

Stripe users can accept Apple Pay in iOS applications in iOS 9 and above, and on the web in Safari starting with iOS 10 or macOS Sierra. There are no additional fees to process Apple Pay payments, and the pricing is the same as other card transactions.

Apple Pay is compatible with most Stripe products and features (e.g., subscriptions), allowing you to use it in place of a traditional payment form whenever possible. Use it to accept payments for physical or digital goods, donations, subscriptions, and more (note that Apple Pay cannot be used instead of in-app purchases).

Apple Pay is available to cardholders at participating banks in supported countries. Refer to Apple’s participating banks documentation to learn which banks and countries are supported.

Using Stripe and Apple Pay vs. in-app purchases

Apple Pay doesn’t replace Apple’s In-App Purchase API. You can use any of Stripe’s supported payment methods and Apple Pay in your iOS app to sell physical goods (e.g., groceries and clothing) or for services your business provides (e.g., club memberships and hotel reservations). These payments are processed through Stripe and you only need to pay Stripe’s processing fee.

Apple’s developer terms require their In-App Purchase API be used for digital “content, functionality, or services,” such as premium content for your app or subscriptions for digital content. Payments made using the In-App Purchase API are processed by Apple and subject to their transaction fees.

Accept Apple Pay in your iOS app

Stripe’s iOS SDK makes it easy to accept both Apple Pay and regular credit card payments. Before you start, you’ll need to be enrolled in the Apple Developer Program and set up Stripe on your server and in your app. Next, follow these steps:

  1. Register for an Apple Merchant ID
  2. Create a new Apple Pay certificate
  3. Integrate with Xcode
  4. Check if Apple Pay is supported
  5. Create the payment request
  6. Present the payment sheet
  7. Submit the payment to Stripe

Step 1: Register for an Apple Merchant ID

First, you’ll need to obtain an Apple Merchant ID. Register a new identifier on the Apple Developer website.

Fill out the form with a description and identifier. Your description is for your own records and can be modified in the future (we recommend just using the name of your app). We recommend using merchant.com.{{your_app_name}} as the identifier.

Step 2: Create a new Apple Pay certificate

Next, create a certificate for your app to encrypt payment data.

Head to the Apple Pay Settings page in the Dashboard. Choose Add new application and follow the guide there.

Step 3: Integrate with Xcode

Finally, add the Apple Pay capability to your app. In Xcode, open your project settings, choose the Signing & Capabilities tab, and add the Apple Pay capability. You may be prompted to log in to your developer account at this point. Enable the checkbox next to the merchant ID you created earlier, and your app is ready to accept Apple Pay.

Xcode capabilities pane

Enable the Apple Pay capability in Xcode

Step 4: Check if Apple Pay is supported

Before displaying Apple Pay as a payment option in your app, determine if the user’s device supports Apple Pay and they have a card added to their wallet.

import Stripe import PassKit class CheckoutViewController: UIViewController, STPApplePayContextDelegate { let applePayButton: PKPaymentButton = PKPaymentButton(paymentButtonType: .plain, paymentButtonStyle: .black) override func viewDidLoad() { super.viewDidLoad() // Only offer Apple Pay if the customer can pay with it applePayButton.isHidden = Stripe.deviceSupportsApplePay() applePayButton.addTarget(self, action: #selector(handleApplePayButtonTapped), for: .touchUpInside) } // ...continued in next step }
#import <Stripe/Stripe.h> #import <PassKit/PassKit.h> @interface CheckoutViewController () <STPApplePayContextDelegate> @property (nonatomic) PKPaymentButton *applePayButton; @end @implementation CheckoutViewController - (void)viewDidLoad { [super viewDidLoad]; // Only offer Apple Pay if the customer can pay with it self.applePayButton.hidden = [Stripe deviceSupportsApplePay]; [self.applePayButton addTarget:self action:@selector(handleApplePayButtonTapped) forControlEvents:UIControlEventTouchUpInside]; }

Step 5: Create the payment request

When the user taps the Apple Pay button, call Stripe paymentRequestWithMerchantIdentifier:country:currency: to create a PKPaymentRequest.

Next, configure the PKPaymentRequest to display your business name and the total. You can also collect information like billing details or shipping information.

See Apple’s documentation for full guidance on how to customize the payment request.

func handleApplePayButtonTapped() { let merchantIdentifier = "merchant.com.your_app_name" let paymentRequest = Stripe.paymentRequest(withMerchantIdentifier: merchantIdentifier, country: "US", currency: "USD") // Configure the line items on the payment request paymentRequest.paymentSummaryItems = [ // The final line should represent your company; // it'll be prepended with the word "Pay" (i.e. "Pay iHats, Inc $50") PKPaymentSummaryItem(label: "iHats, Inc", amount: 50.00), ] // ...continued in next step }
- (void)handleApplePayButtonTapped { NSString *merchantIdentifier = @"com.merchant.your_application"; PKPaymentRequest *paymentRequest = [Stripe paymentRequestWithMerchantIdentifier:merchantIdentifier country:@"US" currency:@"USD"]; paymentRequest.paymentSummaryItems = @[ // The final line should represent your company; // it'll be prepended with the word "Pay" (i.e. "Pay iHats, Inc $50") [PKPaymentSummaryItem summaryItemWithLabel:@"iHats, Inc" amount:[NSDecimalNumber decimalNumberWithString:@"50.00"]], ]; // ...continued in next step }

Step 6: Present the payment sheet

Next, create an STPApplePayContext instance with the PKPaymentRequest and use it to present the Apple Pay sheet.

func handleApplePayButtonTapped() { // ...continued from previous step // Initialize an STPApplePayContext instance if let applePayContext = STPApplePayContext(paymentRequest: paymentRequest, delegate: self) { // Present Apple Pay payment sheet applePayContext.presentApplePay(on: self) } else { // There is a problem with your Apple Pay configuration } }
- (void)handleApplePayButtonTapped { // ...continued from previous step // Initialize an STPApplePayContext instance STPApplePayContext *applePayContext = [[STPApplePayContext alloc] initWithPaymentRequest:paymentRequest delegate:self]; if (applePayContext) { // Present Apple Pay payment sheet [applePayContext presentApplePayOnViewController:self completion:nil]; } else { // There is a problem with your Apple Pay configuration } }

Step 7: Submit the payment to Stripe

Server-side

On your server, make an endpoint that creates a PaymentIntent with an amount and currency. Always decide how much to charge on the server side, a trusted environment, as opposed to the client. This prevents malicious customers from being able to choose their own prices.

curl https://api.stripe.com/v1/payment_intents \ -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \ -d amount=1099 \ -d currency=usd
# Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' intent = Stripe::PaymentIntent.create({ amount: 1099, currency: 'usd', }) client_secret = payment_intent['client_secret'] # Pass the client secret to the client
# Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' intent = stripe.PaymentIntent.create( amount=1099, currency='usd', ) client_secret = intent.client_secret # Pass the client secret to the client
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys \Stripe\Stripe::setApiKey('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); $intent = \Stripe\PaymentIntent::create([ 'amount' => 1099, 'currency' => 'usd', ]); $client_secret = $intent->client_secret; // Pass the client secret to the client
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.apiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; PaymentIntentCreateParams params = PaymentIntentCreateParams.builder() .setAmount(1099L) .setCurrency("usd") .build(); PaymentIntent intent = PaymentIntent.create(params); String clientSecret = intent.getClientSecret(); // Pass the client secret to the client
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys const stripe = require('stripe')('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); const paymentIntent = await stripe.paymentIntents.create({ amount: 1099, currency: 'usd', }); const clientSecret = paymentIntent.client_secret // Pass the client secret to the client
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys stripe.Key = "sk_test_4eC39HqLyjWDarjtT1zdp7dc" params := &stripe.PaymentIntentParams{ Amount: stripe.Int64(1099), Currency: stripe.String(string(stripe.CurrencyUSD)), } pi, _ := paymentintent.New(params) // Pass the client secret to the client
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys StripeConfiguration.ApiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; var options = new PaymentIntentCreateOptions { Amount = 1099, Currency = "usd", }; var service = new PaymentIntentService(); var paymentIntent = service.Create(options); // Pass the client secret to the client

Client-side

Implement applePayContext:didCreatePaymentMethod:completion: to call the completion block with the PaymentIntent client secret retrieved from the endpoint above.

After you call the completion block, STPApplePayContext completes the payment, dismisses the Apple Pay sheet, and calls applePayContext:didCompleteWithStatus:error: with the status of the payment. Implement this method to show a receipt to your customer.

extension CheckoutViewController { func applePayContext(_ context: STPApplePayContext, didCreatePaymentMethod paymentMethod: STPPaymentMethod, paymentInformation: PKPayment, completion: @escaping STPIntentClientSecretCompletionBlock) { let clientSecret = ... // Retrieve the PaymentIntent client secret from your backend (see Server-side step above) // Call the completion block with the client secret or an error completion(clientSecret, error); } func applePayContext(_ context: STPApplePayContext, didCompleteWith status: STPPaymentStatus, error: Error?) { switch status { case .success: // Payment succeeded, show a receipt view break case .error: // Payment failed, show the error break case .userCancellation: // User cancelled the payment break @unknown default: fatalError() } } }
#pragma mark - STPApplePayContextDelegate - (void)applePayContext:(STPApplePayContext *)context didCreatePaymentMethod:(STPPaymentMethod *)paymentMethod paymentInformation:(PKPayment *)paymentInformation completion:(STPIntentClientSecretCompletionBlock)completion { NSString *clientSecret = ... // Call your backend to create a PaymentIntent (see Server-side step above) and get its client secret // Call the completion block with the client secret or an error completion(clientSecret, error); } - (void)applePayContext:(STPApplePayContext *)context didCompleteWithStatus:(STPPaymentStatus)status error:(NSError *)error { switch (status) { case STPPaymentStatusSuccess: // Payment succeeded, show a receipt view break; case STPPaymentStatusError: // Payment failed, show the error break; case STPPaymentStatusUserCancellation: // User cancelled the payment break; } }

Finally, handle post-payment events to do things like sending an order confirmation email to your customer, logging the sale in a database, or starting a shipping workflow.

Implement applePayContext:didCreatePaymentMethod:completion: to send paymentMethod.stripeId to your server and create and confirm the PaymentIntent. Next, call the completion block with the PaymentIntent client secret returned from your server.

After you call the completion block, STPApplePayContext completes the payment, dismisses the Apple Pay sheet, and calls applePayContext:didCompleteWithStatus:error: with the status of the payment. Implement this method to show a receipt to your customer.

extension CheckoutViewController { func applePayContext(_ context: STPApplePayContext, didCreatePaymentMethod paymentMethod: STPPaymentMethod, paymentInformation: PKPayment, completion: @escaping STPIntentClientSecretCompletionBlock) { let clientSecret = ... // Call your backend to create and confirm a PaymentIntent and get its client secret // Call the completion block with the client secret or an error completion(clientSecret, error); } func applePayContext(_ context: STPApplePayContext, didCompleteWith status: STPPaymentStatus, error: Error?) { switch status { case .success: // Payment succeeded, show a receipt view break case .error: // Payment failed, show the error break case .userCancellation: // User cancelled the payment break @unknown default: fatalError() } } }
#pragma mark - STPApplePayContextDelegate - (void)applePayContext:(STPApplePayContext *)context didCreatePaymentMethod:(STPPaymentMethod *)paymentMethod paymentInformation:(PKPayment *)paymentInformation completion:(STPIntentClientSecretCompletionBlock)completion { NSString *clientSecret = ... // Call your backend to create and confirm a PaymentIntent and get its client secret // Call the completion block with the client secret or an error completion(clientSecret, error); } - (void)applePayContext:(STPApplePayContext *)context didCompleteWithStatus:(STPPaymentStatus)status error:(NSError *)error { switch (status) { case STPPaymentStatusSuccess: // Payment succeeded, show a receipt view break; case STPPaymentStatusError: // Payment failed, show the error break; case STPPaymentStatusUserCancellation: // User cancelled the payment break; } }

Troubleshooting

If you’re seeing errors from the Stripe API when attempting to create tokens, you most likely have a problem with your Apple Pay Certificate. You’ll need to generate a new certificate and upload it to Stripe, as described above. Make sure you use a CSR obtained from your Dashboard and not one you generated yourself. Xcode often incorrectly caches old certificates, so in addition to generating a new certificate, we recommend creating a new Apple Merchant ID as well.

If you receive the error “You haven’t added your Apple merchant account to Stripe,” it’s likely your app is sending data encrypted with a previous (non-Stripe) CSR/Certificate. Make sure any certs generated by non-Stripe CSRs are revoked under your Apple Merchant ID. If this doesn’t resolve the issue, delete the merchant ID in your Apple account and recreate it. Then, create a new certificate based on the same (Stripe-provided) CSR that was previously used. You don’t need to re-upload this new certificate to Stripe. When finished, toggle the Apple Pay Credentials off and on in your app to make sure they refresh properly.

Accept Apple Pay on the web

You can start accepting Apple Pay payments on the web using Checkout or Elements. No additional configuration is required to use Apple Pay in Checkout. For Elements, refer to our Payment Request Button documentation to learn how to add Apple Pay to your site.

Use of Apple Pay on the Web is subject to the Apple Pay on the Web terms of service.

Recurring payments

You can use Apple Pay tokens to create one-off payments or subscriptions. For repeat purchases that aren’t related to a subscription, we recommend that you create single-use tokens. Your customer must authenticate with the Apple Pay payment sheet each time—attempting to reuse payment information for a non-subscription payment can result in it being declined.

Testing Apple Pay

Stripe test card information can’t be saved to Wallet in iOS. Instead, Stripe recognizes when you’re using your test API keys and returns a successful test card token for you to use. This allows you to make test payments using a live card without it being charged.

You’re now ready to implement Apple Pay. If you’d like to read more about Apple Pay and its other configuration options, we recommend the NSHipster article on Apple Pay and the Apple Pay Within Apps presentation from WWDC 2015.

See also

Was this page helpful?
Questions? Contact us.
Developer tutorials on YouTube.
You can unsubscribe at any time. Read our privacy policy.