1. Before you begin
The Google Wallet API allows you to engage with users through various predefined types of passes: loyalty card, offer, gift card, event ticket, transit ticket, and boarding pass, all of which come with use-case specific fields and features. We recognize however that these might not fit every use case, and that is why we created a generic pass type. As the name suggests, the generic pass type should be used when your use case does not fit into any of the other specialized types. Here are some example use cases for the generic pass type:
- Parking passes
- Library membership cards
- Stored value vouchers
- Gym membership cards
- Insurance cards
- Reservations of various kinds
You can use generic passes for any use case that can be presented to the user in the form of a card with up to three rows of information, with an optional barcode and optional details section, so long as it is within our Acceptable Use Policy.
The Google Wallet API allows you to create:
- Pass classes. Think of classes as templates with common information that all your passes belonging to a program or event share. All pass objects belong to a class.
- Pass objects serve a concrete purpose associated with your activity as a business and your users (eg.: entry ticket for user A, loyalty card for user B). Each of these items are associated with a previously defined class, and inherit common properties from it.
This codelab will provide you with a pre-defined class, and guide you through creating a pass object, and adding the "Add to Google Wallet" button to your web app, which will allow your users to save the pass to their Google Wallet.
For more information on the Google Wallet API, or adding an "Add to Google Wallet" button to an Android application, please visit the Google Wallet developer documentation.
Prerequisites
- Basic knowledge of HTML and JavaScript
What You'll Learn
- How to create pass objects using the Wallet API
- How to create a JWT for the pass object, and embed it within a "Add to Google Wallet" button in a web app
What you'll need
- Google Account with access to Google Cloud Console
- Node.js 10 or later installed
git
installed (recommended)gcloud
command-line tool installed
2. Get set up
Create your cloud project
Sign in to Cloud Console and create a new project or reuse an existing one. (If you don't already have a Gmail or Workspace account, you must create one.)
Remember the project ID, a unique name across all Google Cloud projects. It will be referred to next.
Get a service account key
The Google Wallet APIs use service accounts for authentication. In this step, we will create a service account and download its service account key file. We will use the gcloud
command-line tool, so make sure to install it, if you haven't before.
Open up your terminal, and define a PROJECT_ID
variable. For example if your project ID was my-cloud-project
:
export PROJECT_ID=my-cloud-project
Run the following command to create a service account:
gcloud iam service-accounts create wallet-codelab --project=$PROJECT_ID
Run the following command, which will create and download a service account key file:
gcloud iam service-accounts keys create ./key.json --iam-account=wallet-codelab@$PROJECT_ID.iam.gserviceaccount.com --project=$PROJECT_ID
Note the path to the key.json
file in the current directory (the following command will display it), as we will reference the path to the service account key file in the next steps:
echo $(pwd)/key.json
Enable the Wallet API
Enable the Wallet API using the following command:
gcloud services enable walletobjects.googleapis.com --project=$PROJECT_ID
Create a temporary issuer account
To create passes for your user, you first need to create an issuer account, enable the Wallet API, and then create a class, all of which can be done via the Google Pay Business Console. However, access to this is only granted once the approval process is complete, so for this codelab we will create both a temporary issuer account, and a pass class for you.
- Take note of the issuer ID and class ID, which you will need in the upcoming steps.
This is how the newly created class looks:
{
"id": "999999.d1fa-4cca1...",
"classTemplateInfo": {
"cardTemplateOverride": {
"cardRowTemplateInfos": [
{
"twoItems": {
"startItem": {
"firstValue": {
"fields": [
{
"fieldPath": "object.textModulesData['points']"
}
]
}
},
"endItem": {
"firstValue": {
"fields": [
{
"fieldPath": "object.textModulesData['contacts']"
}
]
}
}
}
}
]
},
"detailsTemplateOverride": {
"detailsItemInfos": [
{
"item": {
"firstValue": {
"fields": [
{
"fieldPath": "class.imageModulesData['event_banner']"
}
]
}
}
},
{
"item": {
"firstValue": {
"fields": [
{
"fieldPath": "class.textModulesData['game_overview']"
}
]
}
}
},
{
"item": {
"firstValue": {
"fields": [
{
"fieldPath": "class.linksModuleData.uris['official_site']"
}
]
}
}
}
]
}
},
"imageModulesData": [
{
"mainImage": {
"sourceUri": {
"uri": "https://storage.googleapis.com/wallet-lab-tools-codelab-artifacts-public/google-io-2021-card.png"
},
"contentDescription": {
"defaultValue": {
"language": "en",
"value": "Google I/O 2022 Banner"
}
}
},
"id": "event_banner'"
}
],
"textModulesData": [
{
"header": "Gather points meeting new people at Google I/O",
"body": "Join the game and accumulate points in this badge by meeting other attendees in the event.",
"id": "game_overview"
}
],
"linksModuleData": {
"uris": [
{
"uri": "https://io.google/2022/",
"description": "Official I/O '22 Site",
"id": "official_site"
}
]
}
}
Get the source code
Clone the repository with the following command:
git clone -b start git@github.com:google-pay/wallet-web-codelab.git
cd wallet-web-codelab
Install project dependencies
The sample app consists of a simple Node.js app. Install the dependencies with the following command:
npm install .
You should now be able to run the Node.js app with the following command:
node app.js
And see it running in your browser:
3. Create a pass object
Open up the file app.js
in your favorite text editor. You'll see the Node.js app contains an empty createPassAndToken
function which is called when the email address form is submitted. When the form is submitted, it writes the response from the createPassAndToken
function out to the web page. Right now it simply returns the text "Form submitted!". We'll modify the createPassAndToken
function to use the email address submitted as the ID to create a unique pass object, and then create a JWT which we will use to build the URL that the user can visit, to save the pass to their Google Wallet.
First, let's define some variables. Edit the following lines at the top of the file, using the values defined earlier - the path where your service account key JSON file was saved to, and the issuer and class IDs given when your temporary issuer account was created:
const serviceAccountFile = '/path/to/key.json';
const issuerId = '';
const classId = '';
Next, replace the createPassAndToken
function with the following code, which creates an authenticated HTTP client and calls the Google Wallet API to create a pass object, using the user's email address as the object's ID:
async function createPassAndToken(req, res) {
const credentials = require(serviceAccountFile);
const httpClient = new GoogleAuth({
credentials: credentials,
scopes: 'https://www.googleapis.com/auth/wallet_object.issuer'
});
const objectUrl = 'https://walletobjects.googleapis.com/walletobjects/v1/genericObject/';
const objectPayload = require('./generic-pass.json');
objectPayload.id = `${issuerId}.${req.body.email.replace(/[^\w.-]/g, '_')}-${classId}`;
objectPayload.classId = `${issuerId}.${classId}`;
let objectResponse;
try {
objectResponse = await httpClient.request({url: objectUrl + objectPayload.id, method: 'GET'});
console.log('existing object', objectPayload.id);
} catch (err) {
if (err.response && err.response.status === 404) {
objectResponse = await httpClient.request({url: objectUrl, method: 'POST', data: objectPayload});
console.log('new object', objectPayload.id);
} else {
console.error(err);
throw err;
}
}
res.send("Form submitted!");
}
The HTTP client first tries to retrieve the existing object if it has already been created, and if it hasn't, it creates it. Enter your email address into the form a few times, and note the different outputs in your terminal.
Pass JSON
Notice the line const objectPayload = require('./generic-pass.json');
. This contains the JSON representation of the pass object. Open the file generic-pass.json
and try editing some values to customize the pass, before creating it again with a new email address.
4. Create a JWT for saving to Google Wallet
We're almost done. Lastly, we will create a signed JWT which we will use to create the URL for the "Add to Google Wallet" button, which we then send back to the web page. When the user clicks the button, their pass will be saved to their Google Wallet.
At the end of the createPassAndToken
function, replace the last line res.send("Form submitted!");
with the following code, which creates a JWT and sends the button HTML back to the web page:
const claims = {
iss: credentials.client_email, // `client_email` in service account file.
aud: 'google',
origins: ['http://localhost:3000'],
typ: 'savetowallet',
payload: {
genericObjects: [{id: objectPayload.id}],
},
};
const token = jwt.sign(claims, credentials.private_key, {algorithm: 'RS256'});
const saveUrl = `https://pay.google.com/gp/v/save/${token}`;
res.send(`<a href="${saveUrl}"><img src="button.png"></a>`);
5. Congratulations
Congratulations, you have integrated the Google Wallet API on Android successfully!
Sign up for an issuer account
When you are ready to issue your own passes in production, go to the Google Pay & Wallet Console to request access to the Google Wallet API. Check out the documentation to learn more.