Google Wallet Integration for Loyalty Cards in Mobile Apps
Google Wallet API works differently from PassKit. There's no file archive — a card is created via REST API, and a JWT token containing the object is sent to the device. For loyalty cards, use the LoyaltyClass + LoyaltyObject. Skipping the LoyaltyClass creation is impossible: Google will reject an object without a class.
Setup: Google Pay & Wallet Console
Before coding, three steps in console.wallet.google.com:
- Create an issuer account (Issuer Account)
- Create a
LoyaltyClass— a card template with logo, colors, fields - Get service account credentials for server calls
issuerId is a numeric issuer identifier, e.g., 3388000000022142. classId is formed as {issuerId}.{classPostfix}, e.g., 3388000000022142.loyalty_2024.
Creating LoyaltyClass via API
from google.oauth2 import service_account
from googleapiclient.discovery import build
credentials = service_account.Credentials.from_service_account_file(
'service_account.json',
scopes=['https://www.googleapis.com/auth/wallet_object.issuer']
)
service = build('walletobjects', 'v1', credentials=credentials)
loyalty_class = {
"id": "3388000000022142.loyalty_2024",
"issuerName": "YourShop",
"reviewStatus": "UNDER_REVIEW",
"programName": "YourShop Loyalty Program",
"programLogo": {
"sourceUri": { "uri": "https://yourshop.com/logo.png" },
"contentDescription": { "defaultValue": { "language": "en", "value": "YourShop Logo" } }
},
"hexBackgroundColor": "#1E5AC8",
"countryCode": "US",
"localizedIssuerName": {
"defaultValue": { "language": "en", "value": "YourShop" }
}
}
service.loyaltyclass().insert(body=loyalty_class).execute()
reviewStatus: "UNDER_REVIEW" is the required initial state. Google manually reviews the class (usually 1–3 days). Until approved, cards can only be added in test mode.
Creating LoyaltyObject and JWT
Each user gets a separate LoyaltyObject:
import jwt
import time
loyalty_object = {
"id": f"3388000000022142.user_{user_id}",
"classId": "3388000000022142.loyalty_2024",
"state": "ACTIVE",
"loyaltyPoints": {
"label": "Points",
"balance": { "int": user_points }
},
"barcode": {
"type": "QR_CODE",
"value": f"USER-{user_id}",
"alternateText": f"USER-{user_id}"
},
"textModulesData": [
{
"header": "Level",
"body": user_tier,
"id": "tier"
}
]
}
# Create the object via API
service.loyaltyobject().insert(body=loyalty_object).execute()
# Generate JWT for client
payload = {
"iss": service_account_email,
"aud": "google",
"typ": "savetowallet",
"iat": int(time.time()),
"payload": {
"loyaltyObjects": [{ "id": loyalty_object["id"] }]
}
}
token = jwt.encode(payload, private_key, algorithm="RS256")
JWT is sent to the mobile app. JWT lifespan is maximum 1 hour.
Android: Adding Card via Google Wallet API
import com.google.android.gms.pay.Pay
import com.google.android.gms.pay.PayApiAvailabilityStatus
import com.google.android.gms.pay.PayClient
private lateinit var walletClient: PayClient
override fun onCreate(savedInstanceState: Bundle?) {
walletClient = Pay.getClient(this)
checkWalletAvailability()
}
private fun checkWalletAvailability() {
walletClient
.getPayApiAvailabilityStatus(PayClient.RequestType.SAVE_PASSES)
.addOnSuccessListener { status ->
if (status == PayApiAvailabilityStatus.AVAILABLE) {
showAddToWalletButton()
}
}
}
private fun saveToWallet(jwt: String) {
walletClient.savePasses(jwt, this, ADD_TO_GOOGLE_WALLET_REQUEST_CODE)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == ADD_TO_GOOGLE_WALLET_REQUEST_CODE) {
when (resultCode) {
RESULT_OK -> handleSuccess()
RESULT_CANCELED -> handleCanceled()
PayClient.SavePassesResult.SAVE_ERROR ->
data?.let { handleError(it.getStringExtra(PayClient.EXTRA_API_ERROR_MESSAGE)) }
}
}
}
PayClient.RequestType.SAVE_PASSES checks that Google Wallet is installed and functional. On devices without GMS (Huawei), Google Wallet is unavailable.
Updating Card Data
Change the points balance — PATCH request to the existing object:
patch_body = {
"loyaltyPoints": {
"balance": { "int": new_points_value }
}
}
service.loyaltyobject().patch(
resourceId=f"3388000000022142.user_{user_id}",
body=patch_body
).execute()
Google Wallet automatically syncs changes on the device within minutes. No push notifications required.
Timeline
2–3 days: creating LoyaltyClass, server-side object generation and JWT, integrating PayClient into Android app. Plus 1–3 days for Google's class review. Pricing is calculated individually.







