Save passes to Google Pay

All Pass verticals have common use cases. For example, all loyalty cards, gift cards, offers, event tickets, boarding passes for flights, and transit passes can be added to the Google Pay App in multiple ways. Select one of the following methods to learn more:


From an Android app

You can use the following methods to add the Save to Google Pay button to your Android app:

Use the following steps to save your Pass to Google Pay from your app:

  1. Complete the steps in Add the Save to Google Pay button to your email or SMS.
  2. Use an ACTION_VIEW intent to open the deep link from the Save to Google Pay button.

    Make sure that the button that triggers the intent uses the Brand guidelines.

The following is an example flow summary:

  1. At some time before a Pass is saved, a class is created on the backend with the REST API.
  2. When the end user asks to saves a pass, your server backend sends a JWT to your Android client app that represents an object.
  3. Your Android client app includes a Save to Google Pay button that follows our brand guidelines. When clicked, it opens an ACTION_VIEW intent to a URI that includes the JWT in its path. Here's an example:
    https://pay.google.com/gp/v/save/{jwt_generated}
    

Use the JWT POST request method

The JWT POST request method is an alternative method to create flight or event ticket classes and objects for Android apps. It's used when it's difficult to implement the backend work required to create and insert a class before an object is saved. This method is most useful for event tickets and boarding passes, which are Passes that can have many classes created over time. Its flow is summarized as follows:

  1. When the end user checks in to their flight, or redeems an event ticket, your server backend renders a JWT to your Android client app that includes both the class and object.
  2. Your Android client app includes a Save to Google button that follows our brand guidelines. When you click the button, the following happens:
    1. A POST request sends the JWT to a Google endpoint through HTTPS.
    2. A URI from the resulting HTTP response body is sent in return, which should then be used to open an ACTION_VIEW intent.

The JWT POST request method also requires an API key. This is appended as a query parameter to the REST API call.

Class creation

A new class is only created on our backend when presented with a class.id that hasn't been saved in the past. Therefore, while you might potentially pass the class details to Google through the JWT multiple times, the backend recognizes that the class is already saved, and it doesn't create new ones every time a boarding pass is saved.

Class updates

After the first boarding pass, the object is saved along with the class. You can use the class.id as expected with our REST API to perform ADDMESSAGE, GET, LIST, PATCH, and UPDATE operations as expected.

To change class details, you must use the Class Update API. If you create a class with class.id=XYZ and some other class details, and you attempt to create a class later with class.id=XYZ but with different class details, we still maintain the original class and won't apply any changes.

JWT format

The format for the JWT you send is described in detail by our reference documentation about Google Pay API for Passes JWT. For this payload, you pass one entry for objects, which represents the object you want to create, and one entry for classes, which contains the class that you created.

HTTP request

You can use the INSERT method to insert classes and objects specified in a JWT. The API Key must be set as a query parameter.

JWT INSERT method

Given a JWT, the INSERT method inserts the classes and objects specified in a JWT. If successful, it returns a 200 HTTP response.

HTTP request
POST https://walletobjects.googleapis.com/walletobjects/v1/jwt/

Authorization

This request requires no authorization. However, the JWT must be signed with RSA-SHA256. The signing key is the OAuth service account-generated key.

Request body

In the request body, supply data with the following structure:

{ “jwt” : string }

Response body

When successful, this method returns a response body with the following structure:

{
    "saveUri": string,
    "resources": {
      "eventTicketClasses": [ eventTicketClass resource, ... ],
      "eventTicketObjects": [ eventTicketObject resource, ... ],
      "flightClasses": [ flightClass resource, ... ],
      "flightObjects": [ flightObject resource, ... ],
      "giftCardClasses": [ giftCardClass resource, ... ],
      "giftCardObjects": [ giftCardObject resource, ... ],
      "loyaltyClasses": [ loyaltyClass resource, ... ],
      "loyaltyObjects": [ loyaltyObject resource, ... ],
      "offerClasses": [ offerClass resource, ... ],
      "offerObjects": [ offerObject resource, ... ],
      "transitClasses": [ transitClass resource, ... ],
      "transitObjects": [ transitObject resource, ... ]
    }
}

A saveUri is a URI that, when opened, allows the end user to save the objects identified in the JWT to their Google account. This URI is only valid a week after it's returned.

See the JWT endpoint reference for more details.

Flow diagrams

See Typical API flows for flow diagrams.

Use the Android SDK

The Android API facilitates saving Pass in Google Pay. By integrating the Save to Google Pay button in your app, you make it easy for your customers to save their Pass to Google Pay.

The following steps outline how to add the Save to Google Pay button for the Loyalty Pass.

1. Add the Save to Google Pay button to your UI

The first step is to add the Save to Google Pay button to your app. Google Pay provides an Android SDK button for you to integrate into your app. The button assets are available in the Brand guidelines.

This toolkit contains vector images of the buttons.

To incorporate a button in your application, copy over the button image from the toolkit into the res folder of your application and add the following code to your Android layout file. Note that each button requires its unique contentDescription string and minWidth value in addition to the correct value for src.

<ImageButton
             android:layout_width="match_parent"
             android:layout_height="48dp"
             android:minWidth="200dp"
             android:clickable="true"
             android:src="@drawable/s2ap" />

The layout_height for the button is 48 dp and minWidth must be 200 dp.

2. Create a loyalty class

A class can be created from the Google Pay API for Passes Merchant Center. From the Classes page in the Merchant Center, select Create Class to create the loyaltyclass. Input fields with a red outline are required, while the remaining are optional. For any fields with a URL, make sure the link is publicly accessible. The created class will be referenced when creating the valuable object.

3. Create a loyalty object

The next step is to create the loyalty object. Following is an example of creating a loyalty object using the builder pattern:

// Define Points
LoyaltyPoints points = LoyaltyPoints.newBuilder()
    .setLabel("Points")
    .setType("points")
    .setBalance(LoyaltyPointsBalance.newBuilder().setString("500").build()).build();

// Define Text Module Data
List textModulesData = new ArrayList();
TextModuleData textModuleData = new TextModuleData("Jane's Baconrista Rewards", "Save more at your local Mountain View store Jane.  You get 1 bacon fat latte for every 5 coffees purchased.  Also just for you, 10% off all pastries in the Mountain View store.");
textModulesData.add(textModuleData);

// Define Links Module Data
List uris = new ArrayList();
UriData uri1 = new UriData("http://www.baconrista.com/myaccount?id=1234567890","My Baconrista Account");
uris.add(uri1);

List imageUris = new ArrayList();
UriData uri2 = new UriData("http://examplesite/images/exampleimage2.jpg", "Image Description");
imageUris.add(uri2);

// Define Info Module
List row0cols = new ArrayList();
LabelValue row0col0 = new LabelValue("Next Reward in","2 coffees");
LabelValue row0col1 = new LabelValue("Member Since", "01/15/2013");
row0cols.add(row0col0);
row0cols.add(row0col1);

List row1cols = new ArrayList();
LabelValue row1col0 = new LabelValue("Local Store", "Mountain View");
row1cols.add(row1col0);

List rows = new ArrayList();
LabelValueRow row0 = LabelValueRow.newBuilder().addColumns(row0cols).build();
LabelValueRow row1 = LabelValueRow.newBuilder().addColumns(row1cols).build();

rows.add(row0);
rows.add(row1);

// Define general messages
List messages = new ArrayList();
WalletObjectMessage message =  WalletObjectMessage.newBuilder()
    .setHeader("Hi Jane!")
    .setBody("Thanks for joining our program. Show this message to " +
        "our barista for your first free coffee on us!")
    .build();
messages.add(message);

// Define Geolocations

LatLng location = new LatLng(37.422601, -122.085286);

List locations = new ArrayList();
locations.add(location);

LoyaltyWalletObject wob = LoyaltyWalletObject
    .newBuilder()
    .setClassId("2967745143867465930.LoyaltyClass")
    .setId("2967745143867465930.LoyaltyObject")
    .setState(WalletObjectsConstants.State.ACTIVE)
    .setAccountId("1234567890")
    .setAccountName("Jane Doe")
    .setIssuerName("Baconrista")
    .setProgramName("Baconrista Rewards")
    .setBarcodeType("qrCode")
    .setBarcodeValue("28343E3")
    .setBarcodeAlternateText("12345")
    .setLoyaltyPoints(points)
    .addTextModulesData(textModulesData)
    .addLinksModuleDataUris(uris)
    .addInfoModuleDataLabelValueRows(rows)
    .addImageModuleDataMainImageUris(imageUris)
    .addMessages(messages)
    .addLocations(locations)
    .build();

This object is the first parameter taken by the createWalletObject call described in the next section.

4. Initialize the Request to save the loyalty object

The class walletObjectsClient serves as the entry point for Wallet objects functionality.

The following code snippet illustrates how an app can instantiate a client for saving an object to Google Pay:

CreateWalletObjectsRequest request = new CreateWalletObjectsRequest(wob);
Wallet.WalletOptions walletOptions = new Wallet.WalletOptions.Builder()
        .setTheme(WalletConstants.THEME_LIGHT)
        .setEnvironment(WalletConstants.ENVIRONMENT_PRODUCTION)
        .build();

walletObjectsClient = Wallet.getWalletObjectsClient(this, walletOptions);
Task task = walletObjectsClient.createWalletObjects(request);
AutoResolveHelper.resolveTask(task, this, SAVE_TO_ANDROID);

You can also use the GoogleApiClient to initialize a request:

Wallet.WalletObjects.createWalletObjects(googleApiClient, request, SAVE_TO_ANDROID);

5. Handle onActivityResult

Define onActivityResult to react to the success, cancellation, or failure of the operation as shown:

public void onActivityResult(int requestCode, int resultCode, Intent data){
  EditText textBox = (EditText) findViewById(R.id.s2wResponse);

  switch(requestCode){
    case SAVE_TO_ANDROID:
      switch (resultCode) {
        case Activity.RESULT_OK:
          textBox.setText("saved");
          break;
        case Activity.RESULT_CANCELED:
          textBox.setText("canceled");
          break;
        default:
          int errorCode =
              data.getIntExtra(
                  WalletConstants.EXTRA_ERROR_CODE, -1);
          textBox.setText("failed error code: " + errorCode);
          break;
      }