How to Generate a Google Wallet membership card using Node.js

How to Generate a Google Wallet membership card using Node.js

How to Create a Membership Card for Google Wallet Using Node.js

Google Wallet (formerly known as Google Pay Passes) allows users to store and manage various passes, such as loyalty cards, event tickets, and membership cards. Creating a membership card for Google Wallet can enhance user engagement and provide a seamless experience. In this guide, we'll walk you through the process of generating Google Wallet Passes using Node.js.

Table of Contents

  1. Prerequisites
  2. Step 1: Set Up Your Google Cloud Project
  3. Step 2: Install Required Libraries
  4. Step 3: Create the Membership Card Class
  5. Step 4: Create the Membership Card Object
  6. Step 5: Serve the Membership Object
  7. Step 6: Test Your Pass Generation
  8. Additional Notes
  9. Conclusion

Prerequisites

Before you begin, ensure you have the following:

  • Google Cloud Account: Required to create a project and access the Google Wallet API.
  • Node.js and npm Installed: Ensure you have Node.js (v12 or later) and npm installed on your machine.
  • Basic Knowledge of Node.js and Express: Familiarity with setting up a basic Node.js server.
  • Service Account with Proper Permissions: To authenticate and interact with Google Wallet API.

Step 1: Set Up Your Google Cloud Project

To interact with the Google Wallet API, you need to set up a project in Google Cloud and configure the necessary services.

  1. Create or Select a Google Cloud Project:
    • Go to the Google Cloud Console.
    • Click on the project dropdown and select New Project or choose an existing one.
  2. Enable the Google Wallet API:
    • Navigate to APIs & Services > Library.
    • Search for "Google Wallet API".
    • Click Enable to activate the API for your project.
  3. Create a Service Account:
    • Go to IAM & Admin > Service Accounts.
    • Click Create Service Account.
    • Provide a Service Account Name and Description.
    • Assign the Wallet Object Creator role to the service account.
    • After creation, click on the service account and navigate to the Keys tab.
    • Click Add Key > Create New Key, choose JSON, and download the credentials file. Save it securely as service-account.json.

Security Tip: Store your service account credentials securely and avoid committing them to version control systems.


Step 2: Install Required Libraries

Initialize your Node.js project and install the necessary dependencies.


# Create and navigate to your project directory
mkdir google-wallet-pass
cd google-wallet-pass

# Initialize a new Node.js project
npm init -y

# Install required packages
npm install express google-auth-library jsonwebtoken axios dotenv

Note: We've added the dotenv package to manage environment variables securely.


Step 3: Create the Membership Card Class

Google Wallet membership cards are based on a Class template. First, you need to define this class using the Wallet API.

  1. Project Structure:

    
    google-wallet-pass/
    ├── service-account.json
    ├── pass-model/
    │   └── images/
    │       ├── logo.png
    ├── .env
    ├── class.js
    ├── object.js
    ├── server.js
    └── package.json
    
    
  2. Configure Environment Variables:

    Create a .env file to store sensitive information.

    
    GOOGLE_APPLICATION_CREDENTIALS=./service-account.json
    WALLET_API_BASE_URL=https://walletobjects.googleapis.com/walletobjects/v1
    PORT=3000
    
    
  3. Create class.js:

    // class.js
    require('dotenv').config();
    const { GoogleAuth } = require('google-auth-library');
    const axios = require('axios');
    const fs = require('fs');
    const path = require('path');
    
    // Initialize Google Auth
    const auth = new GoogleAuth({
    	keyFile: process.env.GOOGLE_APPLICATION_CREDENTIALS,
    	scopes: ['https://www.googleapis.com/auth/wallet_object.issuer'],
    });
    
    // Define the Membership Class
    const membershipClass = {
    	id: 'issuerId.membershipClassId', // Replace with your issuer ID and unique class ID
    	issuerName: 'Your Company Name',
    	programName: 'Loyalty Membership',
    	programLogo: {
    		sourceUri: {
    			uri: 'https://your-domain.com/path-to-logo.png', // URL to your program logo
    		},
    	},
    	textModulesData: [
    		{
    			header: 'Membership Details',
    			body: 'Welcome to our membership program. Enjoy exclusive benefits and rewards!',
    		},
    	],
    	linksModuleData: {
    		uris: [
    			{
    				uri: 'https://your-website.com',
    				description: 'Visit our website for more information',
    			},
    		],
    	},
    	reviewStatus: 'underReview', // Set to 'active' once approved by Google
    };
    
    // Function to create Membership Class
    async function createMembershipClass() {
    	try {
    		const client = await auth.getClient();
    		const accessToken = await client.getAccessToken();
    
    		const response = await axios.post(
    			`${process.env.WALLET_API_BASE_URL}/loyaltyClass`,
    			membershipClass,
    			{
    				headers: {
    					Authorization: `Bearer ${accessToken}`,
    					'Content-Type': 'application/json',
    				},
    			},
    		);
    
    		console.log('Membership class created successfully:', response.data);
    	} catch (error) {
    		console.error(
    			'Error creating membership class:',
    			error.response ? error.response.data : error.message,
    		);
    	}
    }
    
    // Execute the function
    createMembershipClass();
    

    Important: Replace "issuerId.membershipClassId" with your actual issuer ID and a unique class ID.

  4. Run class.js to Create the Class:

    
    node class.js
    
    

    After successful execution, Google will review your class. Once approved, you can set reviewStatus to active to make it available for creating objects.


Step 4: Create the Membership Card Object

Once the class is approved, you can create membership card Objects for individual users. These objects contain specific user information and are linked to the class.

  1. Create object.js:

    // object.js
    require('dotenv').config();
    const { GoogleAuth } = require('google-auth-library');
    const jwt = require('jsonwebtoken');
    const fs = require('fs');
    const path = require('path');
    
    // Initialize Google Auth
    const auth = new GoogleAuth({
    	keyFile: process.env.GOOGLE_APPLICATION_CREDENTIALS,
    	scopes: ['https://www.googleapis.com/auth/wallet_object.issuer'],
    });
    
    // Define the Membership Object
    const membershipObject = {
    	id: 'issuerId.membershipObjectId', // Replace with your issuer ID and unique object ID
    	classId: 'issuerId.membershipClassId', // Replace with your class ID
    	state: 'active',
    	accountId: '123456789', // Unique identifier for the user
    	accountName: 'John Doe',
    	barcode: {
    		type: 'qrCode',
    		value: '123456789',
    	},
    	textModulesData: [
    		{
    			header: 'Membership Info',
    			body: 'Thank you for being a loyal member!',
    		},
    	],
    	infoModuleData: {
    		labelValueRows: [
    			{
    				columns: [
    					{
    						label: 'Points',
    						value: '100',
    					},
    				],
    			},
    		],
    	},
    };
    
    // Function to create Membership Object
    async function createMembershipObject() {
    	try {
    		const client = await auth.getClient();
    		const accessToken = await client.getAccessToken();
    
    		const response = await axios.post(
    			`${process.env.WALLET_API_BASE_URL}/loyaltyObject`,
    			membershipObject,
    			{
    				headers: {
    					Authorization: `Bearer ${accessToken}`,
    					'Content-Type': 'application/json',
    				},
    			},
    		);
    
    		console.log('Membership object created successfully:', response.data);
    	} catch (error) {
    		console.error(
    			'Error creating membership object:',
    			error.response ? error.response.data : error.message,
    		);
    	}
    }
    
    // Execute the function
    createMembershipObject();
    

    Important: Replace "issuerId.membershipObjectId" with your actual issuer ID and a unique object ID. Ensure that classId matches the ID of the class you created earlier.

  2. Run object.js to Create the Object:

    
    node object.js
    
    

    This will create a membership object linked to your class. You can generate a Save URL for users to add this pass to their Google Wallet.


Step 5: Serve the Membership Object

You can use Express to serve the membership card creation via a URL. This allows users to add their membership card to Google Wallet seamlessly.

  1. Create server.js:

    // server.js
    require('dotenv').config();
    const express = require('express');
    const { GoogleAuth } = require('google-auth-library');
    const jwt = require('jsonwebtoken');
    const axios = require('axios');
    const path = require('path');
    
    const app = express();
    
    // Initialize Google Auth
    const auth = new GoogleAuth({
    	keyFile: process.env.GOOGLE_APPLICATION_CREDENTIALS,
    	scopes: ['https://www.googleapis.com/auth/wallet_object.issuer'],
    });
    
    // Function to create Membership Object and generate Save URL
    async function generateSaveUrl(userData) {
    	// Define the Membership Object based on user data
    	const membershipObject = {
    		id: `issuerId.${userData.userId}`, // Unique object ID
    		classId: 'issuerId.membershipClassId', // Your class ID
    		state: 'active',
    		accountId: userData.userId,
    		accountName: userData.name,
    		barcode: {
    			type: 'qrCode',
    			value: userData.membershipId,
    		},
    		textModulesData: [
    			{
    				header: 'Membership Info',
    				body: 'Thank you for being a loyal member!',
    			},
    		],
    		infoModuleData: {
    			labelValueRows: [
    				{
    					columns: [
    						{
    							label: 'Points',
    							value: `${userData.points}`,
    						},
    					],
    				},
    			],
    		},
    	};
    
    	try {
    		const client = await auth.getClient();
    		const accessToken = await client.getAccessToken();
    
    		// Create the membership object
    		await axios.post(
    			`${process.env.WALLET_API_BASE_URL}/loyaltyObject`,
    			membershipObject,
    			{
    				headers: {
    					Authorization: `Bearer ${accessToken}`,
    					'Content-Type': 'application/json',
    				},
    			},
    		);
    
    		// Generate JWT for Save to Wallet
    		const serviceAccount = require(
    			path.resolve(process.env.GOOGLE_APPLICATION_CREDENTIALS),
    		);
    		const privateKey = serviceAccount.private_key;
    		const issuerId = serviceAccount.client_email;
    
    		const tokenPayload = {
    			iss: issuerId,
    			aud: 'google',
    			origins: ['https://your-domain.com'],
    			typ: 'savetowallet',
    			payload: {
    				loyaltyObjects: [membershipObject],
    			},
    		};
    
    		const token = jwt.sign(tokenPayload, privateKey, { algorithm: 'RS256' });
    
    		const saveUrl = `https://pay.google.com/gp/v/save/${token}`;
    		return saveUrl;
    	} catch (error) {
    		console.error(
    			'Error generating Save URL:',
    			error.response ? error.response.data : error.message,
    		);
    		throw new Error('Failed to generate Save URL');
    	}
    }
    
    // Route to add membership to Google Wallet
    app.get('/add-to-wallet', async (req, res) => {
    	// Example user data. In a real application, retrieve this from your database.
    	const userData = {
    		userId: 'uniqueUserId123',
    		name: 'Jane Smith',
    		membershipId: 'MEM123456',
    		points: 250,
    	};
    
    	try {
    		const saveUrl = await generateSaveUrl(userData);
    		res.redirect(saveUrl); // Redirect the user to Google Wallet to save the pass
    	} catch (error) {
    		res.status(500).send('Error generating Google Wallet pass.');
    	}
    });
    
    // Start the server
    const PORT = process.env.PORT || 3000;
    app.listen(PORT, () => {
    	console.log(`Server is running on port ${PORT}`);
    });
    

    Note: Replace 'https://your-domain.com' with your actual domain. Ensure that userData is fetched dynamically based on your application's logic.

  2. Run the Server:

    
    node server.js
    
    
  3. Access the Pass Generation Endpoint:

    Open your browser and navigate to:

    
    http://localhost:3000/add-to-wallet
    
    

    This should redirect you to Google Wallet's interface to save the pass.


Step 6: Test Your Pass Generation

  1. Start the Server:

    Ensure your server is running.

    
    node server.js
    
    
  2. Access the Pass Generation Endpoint:

    Open your browser or use a tool like Postman to navigate to:

    
    http://localhost:3000/add-to-wallet
    
    

    This should redirect you to Google Wallet's interface, prompting you to add the membership card.

  3. Verify in Google Wallet:

    • On your mobile device, ensure you're signed in to the same Google account.
    • Follow the prompts to add the pass to your Google Wallet.

Additional Notes

Pass Customization

  • Dynamic Data: Integrate a database to dynamically populate pass fields based on user data.
  • Localization: Support multiple languages by adding localization files.
  • Images: Enhance your pass with additional images like thumbnails, strip images, and background images. Ensure they meet Google's design guidelines.

Security Considerations

  • Protect Service Account Credentials: Ensure your service-account.json is stored securely and not exposed publicly.
  • HTTPS: Serve your application over HTTPS to secure data transmission.
  • Validation: Implement validation to ensure only authorized users can generate passes.

Error Handling

  • Implement comprehensive error handling to catch and respond to potential issues during pass generation.
  • Log errors securely for debugging purposes without exposing sensitive information to users.

Deployment

  • Environment Variables: Use environment variables to manage configurations securely in different environments (development, staging, production).
  • Scalability: Consider deploying your application on scalable platforms like Google App Engine, AWS, Heroku, or Vercel to handle increased traffic.

Review Process

  • After creating your class, Google will review it. Ensure that all information complies with Google's policies and guidelines.
  • Once approved, update the reviewStatus to active to make the class available for creating objects.

Conclusion

Creating a membership card for Google Wallet using Node.js involves setting up a Google Cloud project, defining a membership class, creating membership objects, and serving them to users. By following this guide, you can integrate Google Wallet into your application, providing users with a convenient and modern way to access their membership information.

For more advanced features, consider exploring Google's Wallet Objects API and integrating additional functionalities like push updates and loyalty points management.

Happy coding!

Vivek Thumar

Software Engineer

Vivek is a software engineer with a passion for building innovative solutions. He enjoys working on challenging problems and creating software that makes a positive impact.