Sign in
An image of the Stripe logo
Create account
Sign in
Home
Payments
Business operations
Financial services
Developer tools
All products
Home
Payments
Business operations
Home
Payments
Business operations
Financial services
Developer tools
Support
Overview
Overview
Global Issuing
Getting started
Create cards
Cards
Virtual cards
Physical cards
Testing physical cards
Replacement cards
Digital wallets
Support
Controls
Spending controls
Real-time authorizations
Fraud protection
3D Secure
Funding
Balance
Connect
Purchases
Authorizations
Transactions
Disputes
Testing
Merchant categories
Additional information
Marketing guidance (Europe/UK)
Product and marketing compliance guidance (US)
Issuing
·
HomeFinancial servicesIssuing cards

Use digital wallets with Issuing

Learn how to use Issuing to add cards to digital wallets.

Add to wallet manually

Users can add Stripe Issuing virtual cards and physical cards to their Apple Pay, Google Pay, and Samsung Pay wallets by opening the wallet app on their phone and entering their card details.

Stripe sends a 6-digit verification code to the phone_number or email of the cardholder associated with the card.

A “card not supported” error displays if neither field is set on the cardholder.

Apple Pay wallets require additional approval. Check your digital wallets settings to view the status of Apple Pay in your account. You may be required to submit an application before using Apple Pay.

Add to wallet with an app

Request Access

Push provisioning requires a special entitlement from Apple called com.apple.developer.payment-pass-provisioning. You can request it by emailing support-issuing@stripe.com. In your email, include your:

  • App name—Your app’s name.
  • Developer team ID—Found in your Apple Developer account settings under membership (for example, 2A23JCNA5E).
  • ADAM ID—Your app’s unique numeric ID. Found in App Store Connect, or in the App Store link to your app (for example, https://apps.apple.com/app/id123456789).
  • Bundle ID—Your app’s bundle identifier, also found in App Store Connect (for example, com.example.yourapp).

After we approve and apply your request, your app appears on the details page of a provisioned card in the Wallet app, and the PKSecureElementPass object is available in your app by calling PKPassLibrary().passes(). You might need to remove and re-provision the card for the change to take effect.

Check eligibility
Client-side

Make sure you’ve integrated the latest version of the Stripe iOS SDK with your app.

Determine if the device is eligible to use push provisioning.

  1. Check that the value of wallets[apple_pay][eligible] in the issued card is true.
  2. Call PKPassLibrary().canAddSecureElementPass(primaryAccountIdentifier:) with the wallets[primary_account_identifier] from your card, and check that the result is true. If the primary_account_identifier is empty, pass an empty string to canAddSecureElementPass().

Retrieve these values on your backend, then pass them to your app for the eligibility check.

You must check the server-side wallets[apple_pay][eligible] flag and the result of canAddSecureElementPass() before showing the PKAddPassButton. If you show an Add to Apple Wallet button without checking these values, App Review might reject your app.

import Stripe class MyViewController: UIViewController { @IBOutlet weak var addPassButton: PKAddPassButton! // ... func handleEligibilityResponse(eligible: Bool, primaryAccountIdentifier: String?) { if eligible && PKPassLibrary().canAddSecureElementPass(primaryAccountIdentifier: primaryAccountIdentifier ?? "") { addPassButton.isHidden = false } else { addPassButton.isHidden = true } } }

Provision a card
Client-side

When the user taps the PKAddPassButton, create and present a PKAddPaymentPassViewController, which contains Apple’s UI for the push provisioning flow.

PKAddPaymentPassViewController can use the primaryAccountIdentifier from the previous step to determine if a card has already been provisioned on a specific device. For example, if the card has already been added to an iPhone, Apple’s UI offers to add it to a paired Apple Watch.

import Stripe class MyViewController: UIViewController { // ... func beginPushProvisioning() { let config = STPPushProvisioningContext.requestConfiguration( withName: "Jenny Rosen", // the cardholder's name description: "RocketRides Card", // optional; a description of your card last4: "4242", // optional; the last 4 digits of the card brand: .visa, // optional; the brand of the card primaryAccountIdentifier: self.primaryAccountIdentifier // the primary_account_identifier value from the previous step ) let controller = PKAddPaymentPassViewController(requestConfiguration: config, delegate: self) self.present(controller!, animated: true, completion: nil) } }

The PKAddPaymentPassViewController’s initializer takes a delegate that you need to implement – typically this can just be the view controller from which you’re presenting it. We provide a class called STPPushProvisioningContext that is designed to help you implement these methods.

class MyViewController: UIViewController { var pushProvisioningContext: STPPushProvisioningContext? = nil // ... } extension MyViewController: PKAddPaymentPassViewControllerDelegate { func addPaymentPassViewController(_ controller: PKAddPaymentPassViewController, generateRequestWithCertificateChain certificates: [Data], nonce: Data, nonceSignature: Data, completionHandler handler: @escaping (PKAddPaymentPassRequest) -> Void) { self.pushProvisioningContext = STPPushProvisioningContext(keyProvider: self) // STPPushProvisioningContext implements this delegate method for you, by retrieving encrypted card details from the Stripe API. self.pushProvisioningContext?.addPaymentPassViewController(controller, generateRequestWithCertificateChain: certificates, nonce: nonce, nonceSignature: nonceSignature, completionHandler: handler); } func addPaymentPassViewController(_ controller: PKAddPaymentPassViewController, didFinishAdding pass: PKPaymentPass?, error: Error?) { // Depending on if `error` is present, show a success or failure screen. self.dismiss(animated: true, completion: nil) } }

Last, you’ll notice STPPushProvisioningContext’s initializer expects a keyProvider. This should be an instance of a class that implements the STPIssuingCardEphemeralKeyProvider protocol.

This protocol defines a single required method, createIssuingCardKeyWithAPIVersion:completion. To implement this method, make an API call to your backend. Your backend creates an Ephemeral Key object using the Stripe API, and returns it to your app. Your app then calls the provided completion handler with your backend’s API response.

extension MyViewController: STPIssuingCardEphemeralKeyProvider { func createIssuingCardKey(withAPIVersion apiVersion: String, completion: @escaping STPJSONResponseCompletionBlock) { // This example uses Alamofire for brevity, but you can make the request however you want AF.request("https://myapi.com/ephemeral_keys", method: .post, parameters: ["api_version": apiVersion]) .responseJSON { response in switch response.result { case .success: if let data = response.data { do { let obj = try JSONSerialization.jsonObject(with: data, options: []) as! [AnyHashable: Any] completion(obj, nil) } catch { completion(nil, error) } case .failure(let error): completion(nil, error) } } }

Update your backend
Server-side

The push provisioning implementation exposes methods that expect you to communicate with your own backend to create a Stripe Ephemeral Key and return it to your app. This key is a short-lived API credential that can be used to retrieve the encrypted card details for a single instance of a card object.

To ensure that the object returned by the Stripe API is compatible with the version of iOS/Android SDK you are using, the Stripe SDK will tell you what API version it prefers. You must explicitly pass this API version to our API when creating the key.

Terminal
curl https://api.stripe.com/v1/ephemeral_keys \ -u
sk_test_4eC39HqLyjWDarjtT1zdp7dc
: \ -d "issuing_card"="{{ISSUING_CARD_ID}}" \ -H "Stripe-Version: {{API_VERSION}}"
{ "id": "ephkey_1G4V6eEEs6YsaMZ2P1diLWdj", "object": "ephemeral_key", "associated_objects": [ { "id": "ic_1GWQp6EESaYspYZ9uSEZOcq9", "type": "issuing.card" } ], "created": 1586556828, "expires": 1586560428, "livemode": false, "secret": "ek_test_YWNjdF8xRmdlTjZFRHelWWxwWVo5LEtLWFk0amJ2N0JOa0htU1JzEZkd2RpYkpJdnM_00z2ftxCGG" }

Testing

The com.apple.developer.payment-pass-provisioning entitlement only works with distribution provisioning profiles, meaning even after you obtain it, the only way to test the end-to-end push provisioning flow is by distributing your app with TestFlight or the App Store.

To make testing easier, we provide a mock version of PKAddPaymentPassViewController called STPFakeAddPaymentPassViewController that can be used interchangeably during testing.

import Stripe class MyViewController: UIViewController { // ... func beginPushProvisioning() { let config = STPPushProvisioningContext.requestConfiguration( withName: "Jenny Rosen", // the cardholder's name description: "RocketRides Card", // optional; a description of your card last4: "4242", // optional; the last 4 digits of the card brand: .visa // optional; the brand of the card ) let controller = STPFakeAddPaymentPassViewController(requestConfiguration: config, delegate: self) self.present(controller!, animated: true, completion: nil) } }
Was this page helpful?
Questions? Contact us.
View developer tutorials on YouTube.
Check out our product changelog.
Powered by Markdoc
You can unsubscribe at any time. Read our privacy policy.
On this page
Add to wallet manually
Add to wallet with an app
Request Access
Check eligibility
Provision a card
Update your backend
Testing
Stripe Shell
Test mode
▗▄ ▄▟█ █▀▀ ▗▟████▙▖ ██████ ███▗▟█ ███ ███▗▟██▙▖ ▗▟█████▙▖ ███▖ ▀▀ ███ ███▀▀▀ ███ ███▀ ███ ███ ███ ▝▜████▙▖ ███ ███ ███ ███ ███ █████████ ▄▄ ▝███ ███ ▄ ███ ███ ███▄ ███ ███ ▄▄ ▝▜████▛▘ ▝▜███▛ ███ ███ ███▝▜██▛▘ ▝▜█████▛▘ ███ ▀▘
Welcome to the Stripe Shell! Stripe Shell is a browser-based shell with the Stripe CLI pre-installed. Login to Stripe docs and press Control + Backtick on your keyboard to start managing your Stripe resources in test mode. - View supported commands: - Find webhook events: - Listen for webhook events: - Call Stripe APIs: stripe [api resource] [operation] (e.g. )
The Stripe Shell is best experienced on desktop.
$