# Use digital wallets with Issuing

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

Issuing allows users to add cards to digital wallets like Apple Pay and Google Pay.

You can’t test this feature in a sandbox, because digital wallet tokens are only available in live mode. To test using digital wallet tokens, you must be approved for live use cases and use real cards. Stripe supports the following provisioning 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 and websites allow users to add cards directly to their digital wallets.

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](https://docs.stripe.com/issuing/controls/token-management.md).

## Manual provisioning

Cardholders can add Stripe Issuing [virtual cards](https://docs.stripe.com/issuing/cards/virtual.md) and [physical cards](https://docs.stripe.com/issuing/cards/physical.md) 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 and CA

US-issued stablecoin programs currently follow the US enablement process.

Apple Pay wallets require approval from Apple. Check your [digital wallets settings](https://dashboard.stripe.com/settings/issuing/digital-wallets) to view the status of Apple Pay in your account. You might need to submit an application before using Apple Pay. After the application is submitted, approval can take 1-2 weeks.

Google Pay and Samsung Pay have no additional required steps.

### EU and UK

Digital wallet integrations require additional approval from the Stripe partnership team. Get in touch with your account representative or [contact Stripe](https://stripe.com/contact/embedded-finance) for more information.

Apple Pay wallets require additional approval. Check your [digital wallets settings](https://dashboard.stripe.com/settings/issuing/digital-wallets) to view the status of Apple Pay in your account. You might need to submit an application before using Apple Pay.

## Push provisioning

Push provisioning allows cardholders to add Stripe Issuing cards to their digital wallets directly from your app or website by selecting an “add to wallet” button.

Users must first complete manual provisioning steps to enable push provisioning in the US. In addition to manual provisioning approval, push provisioning requires an integration with each wallet platform. You can integrate directly with the wallet platform or use a Stripe SDK.

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

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

# Android

![A black UI button that says Add to Google Wallet. There is a Google Wallet logo image to the left of the text.](https://b.stripecdn.com/docs-statics-srv/assets/add_to_google_pay_black.2df6c169bbc605123ec73d37dc73a86e.png)

## Request access

You must get access to [manual provisioning](https://docs.stripe.com/issuing/cards/digital-wallets.md?platform=android#manual-provisioning) before you can request push provisioning.

> This guide reflects Google Wallet’s Unified Push Provisioning (UPP) flow. This flow lets cardholders provision cards directly to wearable devices from a mobile device. It also lets cardholders save card information to a Google Wallet account for use on other Google devices and applications, such as Google Chrome.

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:

1. [Set up a Google Issuer Console account](https://pay.google.com/business/console?business_type=financial_institution). Select **Financial Institution** as the business type.

2. In the Google Issuer Console dashboard, go to the **Push Provisioning API** tab and complete your business profile. If you don’t know the Visa BID or Mastercard CID, set it to `Unknown`. Google reviews your issuer details within 24 to 48 hours and emails you an NDA and call to action to complete.

3. Don’t exchange keys with Google. Instead, complete the [Unified Push Provisioning API Intake Request](https://support.google.com/googlepay/contact/upp_api_onboarding) and select **Aggregator/Program Manager linking** to link your managed issuer account to Stripe’s program manager account. Stripe’s Aggregator Merchant ID is `BCR2DN7TWDCZDZJC`.

   > Google allows each Issuer Console account to link to only one program manager. If you have multiple program managers, contact [support-issuing@stripe.com](mailto:support-issuing@stripe.com) for guidance.

4. Request access to [Google’s push provisioning documentation](https://developers.google.com/pay/issuers/apis/push-provisioning/android) and download the [private TapAndPay SDK](https://developers.google.com/pay/issuers/apis/push-provisioning/android/releases). The most recently tested version, and the minimum required version, is `18.8.0`.

5. Update your client app and server backend by following the guidance in the [following sections](https://docs.stripe.com/issuing/cards/digital-wallets.md#update-your-app).

6. Submit screenshots of your app’s user flow in the Google Issuer Console. Follow [Google’s brand guidelines](https://developers.google.com/pay/issuers/apis/push-provisioning/android/branding-guidelines).

7. Submit your app ID and fingerprint in the Google Issuer Console to gain access to Google’s Push Provisioning API. Before you complete this step, **Add to Google Wallet** returns an error. For more information about allowlisting your app, see [Google’s documentation](https://developers.google.com/pay/issuers/apis/push-provisioning/android/allowlist).

8. [Contact support-issuing@stripe.com](mailto:support-issuing@stripe.com) with your application name, application ID, card network, and card name.

9. Use the [Testing section](https://docs.stripe.com/issuing/cards/digital-wallets.md#testapp) to get final approval from Google before you go live.

## Update your app [Client-side]

To update your app:

1. Import Google’s [private TapAndPay SDK](https://developers.google.com/pay/issuers/apis/push-provisioning/android/setup). The minimum version required is version `18.8.0`.
2. Import Stripe’s Issuing Android Push Provisioning SDK.

```java
dependencies {
  [... your dependencies]
  implementation 'com.stripe:stripe-android-issuing-push-provisioning:1.3.0'
}
```

For more context, see the code snippets and references to the sample app at each step. For this step, see how the [sample app](https://github.com/stripe-samples/push-provisioning-samples/blob/main/client/android/app/build.gradle.kts#L118-L125) imports these SDKs.

- Prepare your backend to create ephemeral keys for your cards. [See section below](https://docs.stripe.com/issuing/cards/digital-wallets.md#update-your-backend).
- Create an `EphemeralKeyProvider` that extends `PushProvisioningEphemeralKeyProvider`. Because you pass the ephemeral key provider to another activity, it must also implement `Parcelable`. See [Parcelable](https://developer.android.com/reference/android/os/Parcelable). For more context, see how the [sample app](https://github.com/stripe-samples/push-provisioning-samples/blob/main/client/android/app/src/main/java/com/stripe/android/pushprovisioning/network/BackendPushProvisioningEphemeralKeyProvider.kt#L20-L43) defines its `EphemeralKeyProvider`.
- Implement the **Add to Google Wallet** button [according to Google’s specifications](https://developers.google.com/pay/issuers/apis/push-provisioning/android/branding-guidelines). Google provides a [Provision Button API](https://developers.google.com/pay/issuers/apis/push-provisioning/android/provision-button-api) for automatic localization of the button.

> As [recommended](https://developers.google.com/pay/issuers/apis/push-provisioning/android/faq#implementation_questions) by Google, don’t require your users to install the Google Wallet app, or check its existence programmatically. The app is only a frontend and you don’t need it for Google Wallet to work. Users can manage their cards from within their Google settings in the “Settings” app.

Google requires that the **Add to Google Wallet** button only displays when a card doesn’t already exist on all of the user’s devices (the mobile phone and wearables), and that users with cards pending verification complete the final guided activation process. Use Google’s [list of test cases](https://developers.google.com/pay/issuers/apis/push-provisioning/android/test-cases) to help you verify that your implementation is correct.

To determine whether to display the **Add to Google Wallet** button, call the Stripe SDK helper function `canAddCardToWallet`. For an example, see the [sample app](https://github.com/stripe-samples/push-provisioning-samples/blob/main/client/android/app/src/main/java/com/stripe/android/pushprovisioning/MainActivity.kt#L82-L93).

If you already have the card information, you can call the TapAndPay SDK method [hasEligibleTokenizationTarget](https://developers.google.com/pay/issuers/apis/push-provisioning/android/wallet-operations#expandable-1) directly instead. Starting in TapAndPay SDK version `18.8.0`, the returned task raises an error if the device owner has no connected wearables. In that case, use [isTokenized](https://developers.google.com/pay/issuers/apis/push-provisioning/android/reading-wallet#istokenized) to check only the current mobile device.

To check the status of your users’ cards, use [listTokens()](https://developers.google.com/pay/issuers/apis/push-provisioning/android/reading-wallet#listtokens) to retrieve a list of all of your cards already present on the device. Compare the value of `getFpanLastFour()` on each returned object to Stripe’s [last4](https://docs.stripe.com/api/issuing/cards/object.md#issuing_card_object-last4)) property of the [Issued Card object](https://docs.stripe.com/api/issuing/cards/object.md) for the card you want to add. Discard all non-matching objects from the response list.

- If the resulting list is empty, it means that the card you intend to add isn’t present on the device yet. You can proceed with displaying the button as described below.
- If the resulting list contains a `TokenInfo` object, check its [TokenState](https://developers.google.com/pay/issuers/apis/push-provisioning/android/enumerated-values#token_status) by invoking `getTokenState()`.
  - If the status is `TOKEN_STATE_NEEDS_IDENTITY_VERIFICATION`, your user has already tried to add the card to the device manually. Display the **Add to Google Wallet** button, and help them recover by wiring the `onActivityResult` listener to the `tokenize()` method as [described in Google’s documentation](https://developers.google.com/pay/issuers/apis/push-provisioning/android/wallet-operations#resolving_yellow_path).
  - If the status is anything else, the card is already present on the device.

> Provide your application ID to Stripe before you start internal testing. Setup can take more than one week, and an incomplete setup can cause inconsistent responses from these methods. The result of `listTokens()` includes only cards added after Stripe completes the setup.

When a user taps the button, launch Stripe’s `PushProvisioningActivity` using the `PushProvisioningActivityStarter`.

```java
new PushProvisioningActivityStarter(
  this, // The Activity or Fragment you are initiating the push provisioning from
  new PushProvisioningActivityStarter.Args(
    "Stripe Card", // The name that will appear on the push provisioning UI
    ephemeralKeyProvider, // Your instance of EphemeralKeyProvider
    false // If you want to enable logs or not
  )).startForResult();
```

If you support Bounce Provisioning, dynamically invoke `.setIsBounceProvisioned(isBounceProvisioned)` on `PushProvisioningActivityStarter.Args`. See [Google’s documentation](https://developers.google.com/pay/issuers/apis/push-provisioning/android/bounce_provisioning) for more information about how to support Bounce Provisioning within your app.

For more context, see how the [sample app](https://github.com/stripe-samples/push-provisioning-samples/blob/main/client/android/app/src/main/java/com/stripe/android/pushprovisioning/MainActivity.kt#L132-L146) launches `PushProvisioningActivity`.

This prepares the push provisioning and launches the UI to add the card to the wallet. Implement the callback in your `onActivityResult`.

```java
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
  if (requestCode == PushProvisioningActivityStarter.REQUEST_CODE) {
    if (resultCode == PushProvisioningActivity.RESULT_OK) {
      PushProvisioningActivityStarter.Result success = PushProvisioningActivityStarter.Result.fromIntent(data);
    } else if (resultCode == PushProvisioningActivity.RESULT_ERROR) {
      PushProvisioningActivityStarter.Error error = PushProvisioningActivityStarter.Error.fromIntent(data);
    }
  }
}
```

For more context, see how the [sample app](https://github.com/stripe-samples/push-provisioning-samples/blob/main/client/android/app/src/main/java/com/stripe/android/pushprovisioning/MainActivity.kt#L148-L188) implements `onActivityResult`.

If provisioning succeeds, you receive a `PushProvisioningActivityStarter.Result` that contains `cardTokenId`, which is Google’s ID for the card in the active wallet. You can use this ID with the other wallet functions. After provisioning succeeds, display a success message to the user. Google reviews this screen as part of the user flow review.

If the provisioning encountered an error, a `PushProvisioningActivityStarter.Error` will be returned with a `code` and a `message`. The `message` is a developer-friendly text explaining the error. The `code` can have the following values:

| Enum                                              | Meaning                                                                                            |
| ------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
| **USER\_CANCELED**                                | The user canceled the provisioning.                                                                |
| **CARD\_CANCELED**                                | The card has been canceled or is lost or stolen and can’t be provisioned.                          |
| **EPHEMERAL\_KEY\_ERROR**                         | There was an error retrieving the ephemeral key.                                                   |
| **TAP\_AND\_PAY\_UNAVAILABLE**                    | The TapAndPay library can’t be used, most likely because the app isn’t added to an allowlist.      |
| **NO\_STABLE\_HARDWARE\_ID**                      | This can happen in the development emulator. The app can’t retrieve the stable hardware ID.        |
| **NO\_ACTIVE\_WALLET\_FOUND**                     | No active wallet available. Emulators generally don’t have Google Pay.                             |
| **CARD\_DETAILS\_ERROR**                          | There was an error contacting Stripe’s servers to get the card details for push provisioning.      |
| **PUSH\_PROVISIONING\_ENCRYPTED\_PAYLOAD\_ERROR** | There was an error contacting Stripe’s servers to get the encrypted payload for push provisioning. |
| **UNKNOWN\_ERROR**                                | An unexpected error occurred. The `message` will have additional information.                      |

## Update your backend [Server-side]

Your push provisioning integration communicates with your backend to create a Stripe Ephemeral Key and return its JSON to your app. This key is a short-lived API credential that you can use to retrieve the encrypted card details for a single card object.

You must explicitly set an API version when creating the key. If you use a Stripe SDK, use the API version that the SDK provides. For a direct integration, return the version used to create the key with its `secret`, and use that same version for requests authenticated with the key.

#### curl

```bash
PINNED_VERSION="{{API_VERSION}}"
curl https://api.stripe.com/v1/ephemeral_keys \
  -u <<YOUR_SECRET_KEY>>: \
  -H "Stripe-Version: ${PINNED_VERSION}" \
  -d issuing_card="{{ISSUING_CARD_ID}}" | \
  jq --arg api_version "${PINNED_VERSION}" '. + {api_version: $api_version}'
```

```json
{
    "id": "ephkey_1G4V6eEEs6YsaMZ2P1diLWdj",
    "object": "ephemeral_key",
    "associated_objects": [
        {
            "id": "{{CARD_ID}}",
            "type": "issuing.card"
        }
    ],
    "created": 1586556828,
    "expires": 1586560428,
    "livemode": false,
    "secret": "ek_test_YWNjdF8xRmdlTjZFRHelWWxwWVo5LEtLWFk0amJ2N0JOa0htU1JzEZkd2RpYkpJdnM_00z2ftxCGG",
    "api_version": "{{API_VERSION}}"
}
```

For more context, see how the [sample backend](https://github.com/stripe-samples/push-provisioning-samples/blob/main/server/ruby/README.md) creates a [Stripe Ephemeral Key](https://github.com/stripe-samples/push-provisioning-samples/blob/main/server/ruby/server.rb#L68-L88).

## Testing

All testing must be done in live mode, with live Issuing cards, and on physical devices.

Submit videos through the Issuer Console that show successful completion of Google’s [test cases](https://developers.google.com/pay/issuers/apis/push-provisioning/android/test-cases). Before you go live, also complete [field testing](https://developers.google.com/pay/issuers/apis/push-provisioning/android/launch-process#field_testing). For more information, see [Google’s launch process](https://developers.google.com/pay/issuers/apis/push-provisioning/android/launch-process#app_review).

To build the sample app, follow the steps in the [readme](https://github.com/stripe-samples/push-provisioning-samples/blob/main/client/android/README.md). You don’t need to build the app to follow the instructions above.

