Stay organized with collections
Save and categorize content based on your preferences.
Once you've created a pass and encoded it in a JWT, you are ready to issue it in your Android app. To do this, you will need to check that the Google Wallet API is available on the user's device, present them with an 'Add to Google Wallet' button, then save the pass to their Google Wallet once they tap the button.
Prerequisites
Before you try to issue a pass, be sure you have completed the following:
Before saving the new object, ensure that the Google Wallet API is
available on the target device by calling thegetPayApiAvailabilityStatus method in the PayClient class.
Start by adding a member variable to the
activity where you will show the button and instantiate it when the activity is
created:
If you are using other design patterns consider placing domain specific business logic appropriately. For example, if you are using the MVVM pattern,
place UI related business logic in your Activity or Fragment (eg.: UI elements,
activity result), and operational logic in your view model (eg.: client
instantiation, network call triggers).
Next, use the PayClient to check whether the API is available:
Finally, call the method you just defined in your application when you need to determine the availability of the API.
Handle when the API is unavailable
Some reasons why the API may be unavailable include the Android or Google
Play services versions being out of date, or that Google Wallet is
unavailable in the user's country.
If the API is not available
consider hiding the button and falling back to a different integration (e.g.
using a JWT link). Note that the user may become eligible to use the API in the future.
3. Add the 'Add to Google Wallet' button
Google Wallet provides a familiar button that you can use to trigger the
Add to Google Wallet flow in your application. Vector assets for the button are
available in the
Button guidelines.
You can import vector assets in Android Studio under File > New > Vector Asset. Select "Local file" in the wizard, add a name (eg.:
add_to_google_wallet_button.xml) and locate the file in your local drive to import it.
Now, you can use the imported drawable to add the button to your user interface:
The button has a layout_height of 48 dp and must be at least 200 dp wide.
4. Add a pass to a user's Google Wallet
The LoyaltyObject can be added by passing an unsigned JWT to the savePasses method.
You can start the add operation as a result of clicking the Google Wallet
button.
The savePasses method triggers the save flow and invokes the
onActivityResult method after the save flow has completed. The implementation of onActivityResult should be similar to the following:
[[["Easy to understand","easyToUnderstand","thumb-up"],["Solved my problem","solvedMyProblem","thumb-up"],["Other","otherUp","thumb-up"]],[["Missing the information I need","missingTheInformationINeed","thumb-down"],["Too complicated / too many steps","tooComplicatedTooManySteps","thumb-down"],["Out of date","outOfDate","thumb-down"],["Samples / code issue","samplesCodeIssue","thumb-down"],["Other","otherDown","thumb-down"]],["Last updated 2025-08-14 UTC."],[[["\u003cp\u003eTo issue passes in your Android app, you need to integrate the Google Wallet API, check for its availability on the user's device, and provide an 'Add to Google Wallet' button to initiate the saving process.\u003c/p\u003e\n"],["\u003cp\u003ePasses are added to Google Wallet by using the \u003ccode\u003esavePasses\u003c/code\u003e method with an unsigned JWT or \u003ccode\u003esavePassesJwt\u003c/code\u003e with a signed JWT (if integrating for both web and Android), triggering an 'Add to Google Wallet' flow.\u003c/p\u003e\n"],["\u003cp\u003eYou must install the Google Wallet Android SDK, check for API availability using the \u003ccode\u003ePayClient\u003c/code\u003e, and design a user interface incorporating the 'Add to Google Wallet' button to facilitate pass saving.\u003c/p\u003e\n"],["\u003cp\u003eEnsure you've completed onboarding, created the necessary passes class and object, and encoded them in a JWT before attempting to issue a pass to a user's Google Wallet.\u003c/p\u003e\n"],["\u003cp\u003eHandle the result of the pass saving operation in the \u003ccode\u003eonActivityResult\u003c/code\u003e method, addressing successful saves, cancellations, and potential errors reported by the API.\u003c/p\u003e\n"]]],["To issue a pass in an Android app, first, ensure the Google Wallet API is available using `getPayApiAvailabilityStatus`. If available, show the 'Add to Google Wallet' button, obtained from the provided vector assets, and add it to the user interface. Upon button tap, use the `savePasses` method, passing a previously created JWT, to save the pass to the user's wallet. Handle the result in `onActivityResult`, checking for success, cancellation, or errors.\n"],null,["Once you've created a pass and encoded it in a JWT, you are ready to issue it in your Android app. To do this, you will need to check that the Google Wallet API is available on the user's device, present them with an 'Add to Google Wallet' button, then save the pass to their Google Wallet once they tap the button.\n\nPrerequisites\n\nBefore you try to issue a pass, be sure you have completed the following:\n\n- Completed all of the steps in the [Onboarding guide](../getting-started/onboarding-guide).\n- Create at least one [Passes Class](../use-cases/create#creating_a_passes_class).\n- Create at least one [Passes Object](../use-cases/create#creating_a_passes_object).\n- [Encoded](../use-cases/jwt) your Passes Class and Passes Object in a JWT.\n\n| **Demo Mode / \\[TEST ONLY\\] passes**\n|\n| When you are still in [Demo Mode](../resources/terminology#demo-mode), all the passes that you create will have an additional text \"\\[TEST ONLY\\]\" in the title. This is to differentiate demo passes from live passes. Once you are granted [publishing access](../test-and-go-live/request-publishing-access), these demo mode passes will no longer have the additional text when the user reopens the wallet app on a connected device.\n\n1. Install the Google Wallet Android SDK \nTo use the Google Wallet Android SDK, add `com.google.android.gms:play-services-pay` to the `dependencies` section of your app-level `build.gradle` file: \n\n```\n implementation \"com.google.android.gms:play-services-pay:16.5.0\"\n```\n\n2. Check for Google Wallet API availability \nBefore saving the new object, ensure that the Google Wallet API is\navailable on the target device by calling the`getPayApiAvailabilityStatus` method in the `PayClient` class.\n\nStart by adding a member variable to the\nactivity where you will show the button and instantiate it when the activity is\ncreated: \n\nKotlin \n\n import com.google.android.gms.pay.PayClient\n\n private lateinit var walletClient: PayClient\n\n override fun onCreate(savedInstanceState: Bundle?) {\n super.onCreate(savedInstanceState)\n\n walletClient = Pay.getClient(this)\n\n // Additional logic in your onCreate method\n }\n\nJava \n\n import com.google.android.gms.pay.PayClient;\n\n private final PayClient walletClient;\n\n @Override\n protected void onCreate(Bundle savedInstanceState) {\n super.onCreate(savedInstanceState);\n\n walletClient = Pay.getClient(application);\n\n // Additional logic in your onCreate method\n }\n\nIf you are using other design patterns consider placing domain specific business logic appropriately. For example, if you are using the MVVM pattern,\nplace UI related business logic in your Activity or Fragment (eg.: UI elements,\nactivity result), and operational logic in your view model (eg.: client\ninstantiation, network call triggers).\n\nNext, use the `PayClient` to check whether the API is available: \n\nKotlin \n\n import com.google.android.gms.pay.PayApiAvailabilityStatus\n\n private fun fetchCanUseGoogleWalletApi() {\n walletClient\n .getPayApiAvailabilityStatus(PayClient.RequestType.SAVE_PASSES)\n .addOnSuccessListener { status -\u003e\n if (status == PayApiAvailabilityStatus.AVAILABLE) {\n // The API is available, show the button in your UI\n } else {\n // The user or device is not eligible for using the Pay API\n }\n }\n .addOnFailureListener {\n // Hide the button and optionally show an error message\n }\n }\n\nJava \n\n import com.google.android.gms.pay.PayApiAvailabilityStatus;\n\n private void fetchCanAddPassesToGoogleWallet() {\n walletClient\n .getPayApiAvailabilityStatus(PayClient.RequestType.SAVE_PASSES)\n .addOnSuccessListener(status -\u003e {\n if (status == PayApiAvailabilityStatus.AVAILABLE) {\n // The API is available, show the button in your UI\n } else {\n // The user or device is not eligible for using the Pay API\n };\n })\n .addOnFailureListener(exception -\u003e {\n // Google Play Services is too old, or API availability not verified\n // Hide the button and optionally show an error message\n });\n }\n\nFinally, call the method you just defined in your application when you need to determine the availability of the API.\n\nHandle when the API is unavailable\n\nSome reasons why the API may be unavailable include the Android or Google\nPlay services versions being out of date, or that Google Wallet is\nunavailable in the user's country.\n\nIf the API is not available\nconsider hiding the button and falling back to a different integration (e.g.\n[using a JWT link](/wallet/retail/loyalty-cards/web)). Note that the user may become eligible to use the API in the future.\n\n3. Add the 'Add to Google Wallet' button \nGoogle Wallet provides a familiar button that you can use to trigger the\nAdd to Google Wallet flow in your application. Vector assets for the button are\navailable in the\n[Button guidelines](/wallet/retail/loyalty-cards/resources/brand-guidelines).\n| **Tip:** Make sure to only include graphics for the configurations supported.\n\nYou can import vector assets in Android Studio under `File \u003e New \u003e Vector Asset`. Select \"Local file\" in the wizard, add a name (eg.:\n`add_to_google_wallet_button.xml`) and locate the file in your local drive to import it.\n- \n- \n\nNow, you can use the imported drawable to add the button to your user interface: \n\n```xml\n \u003cImageButton\n android:id=\"@+id/addToGoogleWalletButton\"\n android:layout_width=\"match_parent\"\n android:layout_height=\"48dp\"\n android:minWidth=\"200dp\"\n android:clickable=\"true\"\n android:src=\"@drawable/add_to_google_wallet_button\" /\u003e\n```\n\nThe button has a `layout_height` of 48 dp and must be at least 200 dp wide.\n\n4. Add a pass to a user's Google Wallet \nThe `LoyaltyObject` can be added by passing an unsigned JWT to the `savePasses` method.\nYou can start the add operation as a result of clicking the Google Wallet\nbutton.\n**Note:** If you are integrating for both Android and web, you can reuse the signed JWT that is required for the web integration, calling `savePassesJwt` instead of ` savePasses`. \n\nKotlin \n\n import android.os.Bundle\n import android.view.View\n import com.google.android.gms.samples.wallet.databinding.ActivityCheckoutBinding\n\n private val addToGoogleWalletRequestCode = 1000\n\n private lateinit var layout: ActivityCheckoutBinding\n private lateinit var addToGoogleWalletButton: View\n\n override fun onCreate(savedInstanceState: Bundle?) {\n super.onCreate(savedInstanceState)\n\n // Use view binding to access the UI elements\n layout = ActivityCheckoutBinding.inflate(layoutInflater)\n setContentView(layout.root)\n\n addToGoogleWalletButton = layout.addToGoogleWalletButton\n addToGoogleWalletButton.setOnClickListener {\n walletClient.savePasses(newObjectJson, this, addToGoogleWalletRequestCode)\n }\n\n // Additional logic in your onCreate method\n }\n\nJava \n\n import android.os.Bundle;\n import android.view.View;\n import com.google.android.gms.samples.wallet.databinding.ActivityCheckoutBinding;\n\n private static final int ADD_TO_GOOGLE_WALLET_REQUEST_CODE = 999;\n\n private ActivityCheckoutBinding layout:\n private View addToGoogleWalletButton;\n\n @Override\n protected void onCreate(Bundle savedInstanceState) {\n super.onCreate(savedInstanceState);\n\n // Use view binding to access the UI elements\n layout = ActivityCheckoutBinding.inflate(getLayoutInflater());\n setContentView(layout.getRoot());\n\n addToGoogleWalletButton = layout.addToGoogleWalletButton;\n addToGoogleWalletButton.setOnClickListener(v -\u003e {\n walletClient.savePasses(newObjectJson, this, ADD_TO_GOOGLE_WALLET_REQUEST_CODE);\n });\n\n // Additional logic in your onCreate method\n }\n\nResult handling\n\nThe `savePasses` method triggers the save flow and invokes the\n` onActivityResult` method after the save flow has completed. The implementation of `onActivityResult` should be similar to the following: \n\nKotlin \n\n import android.content.Intent\n\n override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {\n super.onActivityResult(requestCode, resultCode, data)\n\n if (requestCode == addToGoogleWalletRequestCode) {\n when (resultCode) {\n RESULT_OK -\u003e {\n // Pass saved successfully\n }\n\n RESULT_CANCELED -\u003e {\n // Save operation canceled\n }\n\n PayClient.SavePassesResult.SAVE_ERROR -\u003e data?.let { intentData -\u003e\n val errorMessage = intentData.getStringExtra(PayClient.EXTRA_API_ERROR_MESSAGE)\n // Handle error\n }\n\n else -\u003e {\n // Handle unexpected (non-API) exception\n }\n }\n }\n }\n\nJava \n\n import android.content.Intent;\n\n @Override\n protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {\n super.onActivityResult(requestCode, resultCode, data);\n\n if (requestCode == ADD_TO_GOOGLE_WALLET_REQUEST_CODE) {\n switch (resultCode) {\n case RESULT_OK: {\n // Pass saved successfully\n break;\n }\n\n case RESULT_CANCELED: {\n // Save operation canceled\n break;\n }\n\n case PayClient.SavePassesResult.SAVE_ERROR: {\n if (data != null) {\n String apiErrorMessage = data.getStringExtra(PayClient.EXTRA_API_ERROR_MESSAGE);\n // Handle error\n }\n break;\n }\n\n default: {\n // Handle unexpected (non-API) exception\n }\n }\n }\n }\n\nWhen the pass is successfully added, the `resultCode` contains the value of ` Activity.RESULT_OK`."]]