Skip to content
Create account
or
Sign in
The Stripe Docs logo
/
Ask AI
Create account
Sign in
Get started
Payments
Revenue
Platforms and marketplaces
Money management
Developer tools
Overview
Start an integration
Products
Global Payouts
Capital
Issuing cards
    Overview
    How Issuing works
    Global availability
    Manage fraud
    Cards
    Choose your card type
    Virtual cards
    Physical cards
    Manage cards
    Digital wallets
    Replacement cards
    Card programs
    Program management
    Processor-only Issuing
    Customize your card program
    Add funds to your card program
    Credit Consumer Issuing
    Controls
    Spending controls
    Advanced fraud tools
    3DS
    Fraud challenges
    Real-time authorizations
    PIN management
    Issuing Elements
    Token Management
    Funding
    Balance
    Postfund your integration with Stripe
    Postfund your integration with Dynamic Reserves
    Purchases
    Authorizations
    Transactions
    Disputes
    Testing
    Merchant categories
    ATM Usage
    Issuing with Connect
    Set up an Issuing and Connect integration
    Update terms of service acceptance
    Connect funding
    Connected accounts, cardholders, and cards
    Embed card management UI
    Credit
    Overview
    Set up connected accounts
    Manage credit terms
    Report other credit decisions and manage AANs
    Report required regulatory data for credit decisions
    Manage account obligations
    Test credit integration
    Additional information
    Choose a cardholder type
    Customer support for Issuing and Treasury
    Issuing watchlist
    Marketing guidance (Europe/UK)
    Product and marketing compliance guidance (US)
Treasury
Manage money
HomeMoney managementIssuing cards

Use digital wallets with Issuing

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

Copy page

Issuing allows users to add cards to digital wallets like Apple Pay and Google Pay. Stripe supports the addition of cards through two methods:

  1. Manual Provisioning: cardholders enter their card details into a phone’s wallet application to add it to their digital wallets.
  2. Push Provisioning: mobile applications allow users to add cards to their digital wallets straight from the app.

When a card is added to a digital wallet, a tokenized representation of that card is created. Network tokens are managed separately from cards. For more information about network tokens and how they work, see Token Management.

Manual Provisioning

Cardholders can add Stripe Issuing virtual cards and physical cards to their Apple Pay, Google Pay, and Samsung Pay wallets through manual provisioning.

To do so, cardholders open the wallet app on their phone and enter their card details. Stripe then 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 when the card was provisioned.

No code is required to implement manual provisioning, but the process to set it up can vary depending on the digital wallet provider and the country you’re based in:

US

Apple Pay wallets require approval from Apple. Check your digital wallets settings to view the status of Apple Pay in your account. You might need to submit an application before using Apple Pay.

Google Pay and Samsung Pay have no additional required steps.

EU/UK

Digital wallet integrations require additional approval from the Stripe partnership team. Get in touch with your account representative or contact Stripe for more information.

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

Push Provisioning

With push provisioning, cardholders can add their Stripe Issuing cards to their digital wallets using your app, by pressing an “add to wallet” button like the ones shown below.

Users must first complete manual provisioning steps to enable push provisioning in the US. In addition to manual provisioning approval, push provisioning requires you to integrate with the Stripe SDK.

This requires both approval processes through Stripe and code integration with the Stripe SDK for each platform you wish to support push provisioning on. Platform approvals cascade down to all of their connected accounts.

Samsung Pay push provisioning isn’t supported with our SDKs.

A black UI button that says Add to Apple Wallet. There is an Apple Wallet logo image to the left of the text. It is a grey wallet with blue, yellow, green, and red cards stacked slightly offset.
A black UI button that says Add to Google Wallet. There is a Google Wallet logo image to the left of the text.

Request Access

Requesting access for iOS

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:

  • Card network—Visa or MasterCard.
  • Card name—This is the name of the card displayed in the wallet.
  • App name—Your app’s name.
  • Developer team ID—Found in your Apple Developer account settings under membership.
  • 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).

Requesting access for Android

Stripe provides an SDK wrapper around a private Google library for push provisioning. To distribute your app on the Google Pay Store with push provisioning you need to request access to this library:

  • Request access to Google Pay
  • Download Google’s TapAndPay private SDK (current compatible version is 17.1.2)
  • Request access to the push provisioning API for your app. You will need to provide your application ID to be added to Google’s allowlist. Details on this process are available in Google’s documentation.
  • Provide the same application ID, your app name, card network, and card name to support-issuing@stripe.com.

Setup your app
Client-side

The React Native SDK is open source and fully documented. Internally, it uses the native iOS and Android SDKs. To install Stripe’s React Native SDK, run one of the following commands in your project’s directory (depending on which package manager you use):

Command Line
yarn add @stripe/stripe-react-native

Next, install some other necessary dependencies:

  • For iOS, navigate to the ios directory and run pod install to ensure that you also install the required native dependencies.
  • For Android, there are no more dependencies to install.

Stripe initialization

To initialize Stripe in your React Native app, either wrap your payment screen with the StripeProvider component, or use the initStripe initialization method. Only the API publishable key in publishableKey is required. The following example shows how to initialize Stripe using the StripeProvider component.

import { StripeProvider } from '@stripe/stripe-react-native'; function App() { const [publishableKey, setPublishableKey] = useState(''); const fetchPublishableKey = async () => { const key = await fetchKey(); // fetch key from your server here setPublishableKey(key); }; useEffect(() => { fetchPublishableKey(); }, []); return ( <StripeProvider publishableKey={publishableKey} merchantIdentifier="merchant.identifier" // required for Apple Pay urlScheme="your-url-scheme" // required for 3D Secure and bank redirects > // Your app code here </StripeProvider> ); }

Note

Use your API test keys while you test and develop, and your live mode keys when you publish your app.

Android-specific setup

To enable push provisioning on Android, after you receive access to the TapAndPay SDK (see above), you need to include it in your native Android project.

Then, you need to import Stripe’s native Android push provisioning library by adding the following to your android/app/build.gradle file:

build.gradle
Groovy
dependencies { // ... implementation 'com.stripe:stripe-android-issuing-push-provisioning:1.1.0' }

iOS-specific setup

To enable push provisioning on iOS, after Stripe confirms the entitlement has been granted, you need to add the capability to your provisioning profile on app store connect.

Then, you need to add the new entitlement to your ios/app.config.js file:

app.config.js
"entitlements": { "com.apple.developer.payment-pass-provisioning": true }

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 a JSON of it to your app. This key is a short-lived API credential that you can use to retrieve the encrypted card details for a single instance of a card object.

To make sure that the object returned by the Stripe API is compatible with the version of the SDK you’re using, you must explicitly pass the API version exported by the React Native SDK to our API when creating the key.

Command Line
curl
curl https://api.stripe.com/v1/ephemeral_keys \ -u
sk_test_BQokikJOvBiI2HlWgH4olfQ2
:
\ -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" }

You should also create an endpoint to retrieve issuing card details that you must pass to the <AddToWalletButton /> component:

Command Line
cURL
curl https://api.stripe.com/v1/issuing/cards/ISSUING_CARD_ID \ -u "
sk_test_BQokikJOvBiI2HlWgH4olfQ2
:"

Update your app
Client-side

First, determine if the device is eligible to use push provisioning by checking that the value of wallets.apple_pay.eligible in the issued card (retrieved from the second endpoint you created above in step 3) is true. If it is, save the card details to use later in our component, and proceed. If wallets.apple_pay.eligible is false, don’t show the <AddToWalletButton /> on iOS, or App Review might reject your app. The same applies to wallets.google_pay.eligible for Android.

import React, {useEffect, useState} from 'react'; import {Constants} from '@stripe/stripe-react-native'; import {View} from 'react-native'; export default function MyScreen() { const [key, setKey] = useState(null); const [card, setCard] = useState(null); useEffect(() => { fetchEphemeralKey(); fetchIssuingCard(); }, []); const fetchIssuingCard = async () => { const response = await fetch(`${API_URL}/issuing-card`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ ISSUING_CARD_ID: '{{ISSUING_CARD_ID}}', }), }); const card = await response.json(); if (!card.wallets.apple_pay.eligible) { // Do not show <AddToWalletButton /> component on iOS. See card.wallets.apple_pay.ineligible_reason for details } else if (!card.wallets.google_pay.eligible) { // Do not show <AddToWalletButton /> component on Android. See card.wallets.google_pay.ineligible_reason for details } else { setCard(card); } }; const fetchEphemeralKey = async () => { // See above }; return <View />; }

Next, fetch your ephemeral key from the first endpoint you created in Step 3 above, and save it.

import React, {useEffect, useState} from 'react'; import {Constants} from '@stripe/stripe-react-native'; import {View} from 'react-native'; export default function MyScreen() { const [key, setKey] = useState(null); useEffect(() => { fetchEphemeralKey(); }, []); const fetchEphemeralKey = async () => { const response = await fetch(`${API_URL}/ephemeral-key`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ ISSUING_CARD_ID: '{{ISSUING_CARD_ID}}', API_VERSION: Constants.API_VERSIONS.ISSUING, }), }); const myKey = await response.json(); setKey(myKey); }; return <View />; }

You don’t need any more server communication. Next, you must determine if the card can be added to the wallet. You can check for this with the canAddCardToWallet method, which returns an object containing a boolean field canAddCard. If canAddCard is false, don’t render the AddToWalletButton, otherwise your app might be rejected by Apple.

On Android, the card might be in the wallet already, but stuck in a bad state. You can add logic to handle this case by checking for a token in the details object returned from canAddCardToWallet. If that response is non-null, and the token.status is "TOKEN_STATE_NEEDS_IDENTITY_VERIFICATION", pass that token into <AddToWalletButton />'s props.

import React, {useEffect, useState} from 'react'; import {Constants, canAddCardToWallet, GooglePayCardToken} from '@stripe/stripe-react-native'; import {View} from 'react-native'; export default function MyScreen() { const [key, setKey] = useState(null); const [card, setCard] = useState(null); const [showAddToWalletButton, setShowAddToWalletButton] = useState(false); const [androidCardToken, setAndroidCardToken] = useState(null); useEffect(() => { fetchEphemeralKey(); fetchIssuingCard(); }, []); const checkIfCanAddCard = async () => { const { canAddCard, details, error } = await canAddCardToWallet({ primaryAccountIdentifier: card?.wallets?.primary_account_identifier, cardLastFour: card.last4, hasPairedAppleWatch: // Pass a boolean indicating whether or not the device has a paired Apple Watch. iOS only. }); if (error) { Alert.alert(error.code, error.message); } else { setShowAddToWalletButton(canAddCard); if (details?.token?.status === 'TOKEN_STATE_NEEDS_IDENTITY_VERIFICATION') { setAndroidCardToken(details.token); } } }; const fetchIssuingCard = async () => { // See above await checkIfCanAddCard(); }; const fetchEphemeralKey = async () => { // See above }; return <View />; }

Now we have all the information we need to show the button:

import React, {useEffect, useState} from 'react'; import { Constants, canAddCardToWallet, AddToWalletButton, GooglePayCardToken, } from '@stripe/stripe-react-native'; import {View, Image, Alert, StyleSheet} from 'react-native'; import AddToGooglePayPNG from '../assets/Add-to-Google-Pay-Button-dark-no-shadow.png'; export default function MyScreen() { const [key, setKey] = useState(null); const [card, setCard] = useState(null); const [showAddToWalletButton, setShowAddToWalletButton] = useState(false); const [androidCardToken, setAndroidCardToken] = useState<null | GooglePayCardToken>(null); useEffect(() => { fetchEphemeralKey(); fetchIssuingCard(); }, []); const canAddCard = async () => { // See above }; const fetchIssuingCard = async () => { // See above }; const fetchEphemeralKey = async () => { // See above }; return ( <View> {showAddToWalletButton && ( <AddToWalletButton token={androidCardToken} androidAssetSource={Image.resolveAssetSource(AddToGooglePayPNG)} testEnv={true} style={styles.payButton} iOSButtonStyle="onLightBackground" cardDetails={{ name: card?.cardholder?.name, primaryAccountIdentifier: card?.wallets?.primary_account_identifier, // This can be null, but should still always be passed. Failing to pass the primaryAccountIdentifier can result in a failure to provision the card. lastFour: card?.last4, description: 'Added by Stripe', }} ephemeralKey={key} onComplete={({error}) => { Alert.alert( error ? error.code : 'Success', error ? error.message : 'Card was successfully added to the wallet.', ); }} /> )} </View> ); } const styles = StyleSheet.create({ payButton: { // You may add custom styles to your button, but make sure it complies // with the relevant platform guidelines: // iOS : https://developer.apple.com/wallet/add-to-apple-wallet-guidelines/ // Android : https://developers.google.com/pay/issuers/apis/push-provisioning/android/branding-guidelines }, });

When a user taps the button, it launches the UI to add the card to the wallet. Implement the callback in your onComplete prop. If the error field is non-null, an error occurred and the card wasn’t added to the wallet. If the error is null, then the card was successfully provisioned.

Button style

On iOS, the button style is determined by the iOSButtonStyle prop. Set this prop to:

  • onLightBackground when you show the button on top of a light or white background.
  • onDarkBackground when you show the button on top of a dark or black background.

On Android, you must pass in the actual image asset to the androidAssetSource prop. You can download all the possible asset options directly from Google. Follow Google’s branding guidelines when implementing your button.

To pass your chosen PNG to the AddToWalletButton component, add it to your project, import it like you would any other asset, and then resolve the source with Image.resolveAssetSource:

import {Image} from 'react-native'; import AddToGooglePayPNG from '../assets/Add-to-Google-Pay-Button-dark-no-shadow.png'; ... <AddToWalletButton ... androidAssetSource={Image.resolveAssetSource(AddToGooglePayPNG)} ... />

Testing

iOS

On iOS, you can test push provisioning in development, on simulators, and with test cards as long as you pass testEnv={true} to the AddToWalletButton component. Be aware that if the testEnv prop is set to true, cards won’t actually be added to the device’s wallet. In testing environments, you don’t need the com.apple.developer.payment-pass-provisioning entitlement.

Android

On Android, the testEnv prop has no effect. All testing must be done in live mode, with live issuing cards, and on physical devices.

Make sure to provide your application ID to Stripe before starting internal testing.

Was this page helpful?
YesNo
Need help? Contact Support.
Join our early access program.
Check out our changelog.
Questions? Contact Sales.
LLM? Read llms.txt.
Powered by Markdoc