Google Wallet Pass Variables
August 7, 2025 Β· AI Conversations
Google Wallet API
that has Text modules defined how I will replace values like number_of_seats when generate google wallet pass
### π How Dynamic Text Works
In the **class**:
You define **placeholders** inside `textModulesData.body` like this:
{
"textModulesData": [
{
"header": "Seats",
"body": "number_of_seats"
},
{
"header": "Seating Area",
"body": "ringside"
}
]
}
In the **object**:
You override the `textModulesData` **completely** when you generate a pass, like this:
### β Example: Replace Placeholders in Event Ticket Object
$passObject = [
'id' => $objectId,
'classId' => $fullClassId,
'state' => 'active',
'textModulesData' => [
[
'header' => 'Seats',
'body' => $order['number_of_seats'] // e.g., "3"
],
[
'header' => 'Seating Area',
'body' => $order['seating_area'] // e.g., "Ringside"
]
],
...
];
> π‘ *Note: This will override the static version in the class and insert real-time data into the object pass.*
—
### π§ Summary
– **Class** = Template
– **Object** = Real data (replaces placeholders like `number_of_seats`)
– Always assign `textModulesData` directly in the object if you need dynamic content per ticket.
Let me know if you want a complete sample with JWT creation in PHP.
—
### β Static vs Dynamic in Google Wallet
| **Field** | **In Class (Template)** | **In Object (Dynamic)** |
|———–|————————–|—————————|
| Event Name | Fixed for all passes | β
Can be overridden |
| Venue Name | Fixed in class | β
Override in object |
| Text Modules | Defined in class | β
Replace fully in object |
—
### β Example: Overriding Dynamic Fields in Event Object
Hereβs how you dynamically assign event name and venue details when generating the pass object (via API or JWT):
{
"id": "issuerId.eventTicketObjectId",
"classId": "issuerId.eventTicketClassId",
"state": "active",
"eventName": {
"defaultValue": {
"language": "en-GB",
"value": "Fossetts Circus β Manchester Evening"
}
},
"venue": {
"name": {
"defaultValue": {
"language": "en-GB",
"value": "Manchester City Grounds"
}
},
"address": {
"defaultValue": {
"language": "en-GB",
"value": "123 Circus Road, Manchester, UK"
}
}
},
"textModulesData": [
{
"header": "Seats",
"body": "4"
},
{
"header": "Seating Area",
"body": "Ringside"
}
],
"startDateTime": "2025-08-15T18:00:00Z",
"endDateTime": "2025-08-15T20:30:00Z"
}
—
### π§ If you're using JWT (Passes as Links):
You do this in the payload for JWT:
$payload = [
'eventTicketObjects' => [
[
'id' => "$issuerId.objectId",
'classId' => "$issuerId.classId",
'eventName' => [
'defaultValue' => [
'language' => 'en-GB',
'value' => 'Fossetts Circus β Manchester Evening'
]
],
'venue' => [
'name' => [
'defaultValue' => [
'language' => 'en-GB',
'value' => 'Manchester City Grounds'
]
],
'address' => [
'defaultValue' => [
'language' => 'en-GB',
'value' => '123 Circus Road, Manchester, UK'
]
]
],
...
]
]
];
—
### π§ Summary
– To make event name/venue dynamic, define them in the **object**, not the class.
– Use the structure `eventName.defaultValue.value` and `venue.name.defaultValue.value`.
– Same applies for `startDateTime`, `endDateTime`, and `textModulesData`.
Let me know if you'd like a PHP code snippet for generating the full JWT for this object.
'id' => $objectId,
'classId' => $fullClassId,
'state' => 'active',
'eventName' => [
'defaultValue' => [
'language' => 'en-US',
'value' => $order['event_venue']
]
],
'eventId' => (string)$order['event_id'],
'venue' => [
'name' => [
'defaultValue' => [
'language' => 'en-US',
'value' => $order['event_venue']
]
],
'address' => [
'defaultValue' => [
'language' => 'en-US',
'value' => $venue_address
]
]
],
'doorsOpenDateTime' => $doorsOpenDateTime,
'startDateTime' => $startDateTime,
'endDateTime' => $endDateTime,
'barcode' => [
'type' => 'qrCode',
'value' => $order['order_code'],
'alternateText' => 'Order: ' . $order['order_code']
],
'ticketHolderName' => $order['customer_name'] ?? '',
// Custom fields for more info
// 'ticketCount' => $ticket_count,
// 'ticketSummary' => $ticket_summary_str,
// 'showtime' => $showtime_formatted,
'seatInfo' => [
'seat' => ['defaultValue'=>[
'language'=>'en-US',
'value'=>$ticket_count
]
]
],
'textModulesData' => [
[
'header'=>'Seating Area',
'body'=>$order['ticket_location']
],
[
'header' => 'Seats',
'body' => $ticket_count
],
[
'header' => 'Tickets',
'body' => $ticket_summary_str
],
[
'header' => 'Showtime',
'body' => $showtime_formatted
]
],
];
I have already passed above object
### β
You're Doing It Right
You're already dynamically assigning the values such as:
– `eventName` β from `$order['event_venue']`
– `venue.name` and `venue.address`
– `eventId`, `doorsOpenDateTime`, `startDateTime`, `endDateTime`
– `textModulesData` β for dynamic ticket info
– `seatInfo` β using `$ticket_count`
These will override any static placeholders defined in the class.
—
### π Just a Few Notes for Best Practice
1. **`eventName` should be a real event title**, not a venue name:
'eventName' => [
'defaultValue' => [
'language' => 'en-US',
'value' => $order['event_name'] // e.g., "Fossetts Circus β Evening Show"
]
],
If you're using `'event_venue'` here, change it to something like `'event_name'` for clarity.
2. **`eventId`** is optional unless you're managing multiple events programmatically. Your cast to `(string)` is safe.
3. β `seatInfo.seat.defaultValue.value` is correct and shows up on the pass UI automatically.
4. β
`textModulesData` will override what you defined in the Class. So your entries for:
– **Seating Area** (`ticket_location`)
– **Seats** (`$ticket_count`)
– **Tickets** (`$ticket_summary_str`)
– **Showtime** (`$showtime_formatted`)
will appear in the order youβve defined.
—
### π§ͺ Tip: Validate Your Payload
You can validate your JSON payload using:
– [Google Wallet REST API Try It](https://developers.google.com/wallet/generic/rest/v1/genericobject/insert)
– Or if you're using JWT, paste your final JWT into [jwt.io](https://jwt.io/) and inspect the object structure.
—
### β
Final Thoughts
You're dynamically replacing everything correctly at the **object level**, which is how Google Wallet intends dynamic personalization to work. You're good to go!
Let me know if you want to:
– Add images/logos
– Localize to other languages
– Embed a call-to-action (e.g., `heroImage`, `linksModuleData`)
– Generate a JWT pass link from this object
'eventName' => [ 'defaultValue' => ['value' => $order['event_name']] ],
'venue' => [
'name' => [ 'defaultValue' => ['value' => $order['event_venue']] ],
'address' => [ 'defaultValue' => ['value' => $venue_address] ]
],
Then the issue is **most likely that the event ticket object is not overriding the values defined in the class**.
—
### β Explanation: Why This Happens
Google Wallet objects inherit values from their **class**. But:
> π‘ **Once an object is created**, if you donβt explicitly override a field (e.g., `venue.name`) or if the override is ignored due to formatting, the pass will show the default class value (`event_venue1`, `event_venue2` in your case).
—
### β Fix Checklist
#### β
1. Ensure your object override is complete
You're using this:
'venue' => [
'name' => [
'defaultValue' => [
'language' => 'en-US',
'value' => $order['event_venue']
]
],
'address' => [
'defaultValue' => [
'language' => 'en-US',
'value' => $venue_address
]
]
],
This is **correct**.
#### β
2. Make sure you're not just **reusing an old object ID**
If the object already exists and you're **not updating** it, the API will silently keep showing the old data.
π **Solution**: Use a new object ID each time or explicitly call the `PATCH` endpoint to update the existing object.
—
### β How to Test It Fresh
$passObject = [
'id' => "$issuerId.$objectId", // must be unique!
...
];
Generate a **new `$objectId`** for each user or order like:
$objectId = 'eventTicketObject_' . $order['order_code']; // ensure uniqueness
—
### β 3. Double-check Class Defaults
In your **event ticket class**, if you had set:
"venue": {
"name": {
"defaultValue": {
"value": "event_venue1"
}
},
"address": {
"defaultValue": {
"value": "event_venue2"
}
}
}
These values will show unless you **override them** at the object level AND that object is new or updated.
—
### β 4. Final Debug Tip
Use `GET` on your object to inspect it:
GET https://walletobjects.googleapis.com/walletobjects/v1/eventTicketObject/{objectId}
See if it contains your dynamic values or still has `event_venue1`.
—
### β Summary
| Step | Action |
|——|——–|
| β
| Make sure you're using a new `objectId` each time |
| β
| Confirm you're passing `venue.name` and `venue.address` with correct structure |
| β
| Delete or update the old object if you're reusing `id` |
| β
| Use the API `GET` to confirm what the object really contains |
—
If you want, share your full object ID or JWT payload structure (without credentials), and Iβll tell you exactly where itβs going wrong.
'name' => [
'defaultValue' => [
'language' => 'en-US',
'value' => $order['event_venue']
]
],
'address' => [
'defaultValue' => [
'language' => 'en-US',
'value' => $venue_address
]
]
],
check above correct?
Hereβs a breakdown of your structure:
'venue' => [
'name' => [
'defaultValue' => [
'language' => 'en-US',
'value' => $order['event_venue'] // e.g., "Manchester Arena"
]
],
'address' => [
'defaultValue' => [
'language' => 'en-US',
'value' => $venue_address // e.g., "123 Main Street, Manchester"
]
]
],
This is **100% valid** and should work.
—
### β What to Double-Check If It's Still Showing `event_venue1`:
1. **Is `$order['event_venue']` and `$venue_address` populated correctly?**
Try logging or dumping the values before passing them in:
var_dump($order['event_venue'], $venue_address);
2. **Are you creating a new `objectId` every time?**
If not, and the object already exists, the new data might not apply unless you:
– `PATCH` the object via API
– or delete and recreate the object
3. **Is the object created using your custom `$passObject`?**
If you're generating a JWT, inspect the payload using [https://jwt.io](https://jwt.io) to make sure the `venue` block is included and matches your data.
4. **Check with a fresh Wallet link** β not cached or already saved.
—
### β
Test With Static Value (Optional)
Try hardcoding temporarily:
'value' => 'Test Venue Name'
If this works but your dynamic one doesnβt, then `$order['event_venue']` is empty or wrong.
—
Would you like me to review your JWT payload or full object generation logic to confirm it's properly injected?
—
### π Root Cause
Even though you correctly passed:
'venue' => [
'name' => [ 'defaultValue' => [ 'language' => 'en-US', 'value' => $order['event_venue'] ] ],
'address' => [ 'defaultValue' => [ 'language' => 'en-US', 'value' => $venue_address ] ]
],
The **Google Wallet UI sometimes continues to show values from the class** unless:
1. The **object is freshly created**.
2. The **JWT includes the updated fields and is properly encoded**.
3. The fields in the **object match exactly the schema** and are not being ignored due to format mismatch or silent error.
—
### β Immediate Fix Path
#### β
1. Hardcode the values for testing
Replace dynamic values temporarily:
'venue' => [
'name' => [
'defaultValue' => [
'language' => 'en-US',
'value' => 'Fossetts Arena'
]
],
'address' => [
'defaultValue' => [
'language' => 'en-US',
'value' => '123 Main Street, Brighton, UK'
]
]
],
**β If this works:** The issue is in your `$order['event_venue']` or `$venue_address` values.
—
#### β
2. Generate a new object ID
Google Wallet **caches object data**. If you're using the same `id` (`issuerId.objectId`), it may not update values.
Update this:
'id' => "$issuerId.eventObject_" . uniqid(),
—
#### β
3. Use the Google API `GET` to verify the object
Call:
GET https://walletobjects.googleapis.com/walletobjects/v1/eventTicketObject/{your-object-id}
Check if the returned JSON includes:
"venue": {
"name": {
"defaultValue": {
"value": "Fossetts Arena"
}
},
"address": {
"defaultValue": {
"value": "123 Main Street, Brighton, UK"
}
}
}
If not β your object is not being created or updated properly.
—
#### β
4. Confirm if you're using JWT
If you're using a JWT to create the pass, **inspect the payload** at https://jwt.io and confirm that it contains:
"eventTicketObjects": [
{
"venue": {
"name": {
"defaultValue": {
"value": "Fossetts Arena"
}
}
}
}
]
—
### π§ͺ Optional: Full Test Payload
Use this as your object payload to test:
$passObject = [
'id' => "$issuerId.eventObject_" . uniqid(),
'classId' => $fullClassId,
'state' => 'active',
'eventName' => [
'defaultValue' => [
'language' => 'en-US',
'value' => 'Fossetts Circus Evening Show'
]
],
'venue' => [
'name' => [
'defaultValue' => [
'language' => 'en-US',
'value' => 'Fossetts Arena'
]
],
'address' => [
'defaultValue' => [
'language' => 'en-US',
'value' => '123 Main Street, Brighton, UK'
]
]
],
...
];
—
### β Summary
| Step | Action |
|——|——–|
| β
| Hardcode test values to verify itβs not data issue |
| β
| Use a new object ID every time (`uniqid()`) |
| β
| Confirm via `GET` API or JWT payload that `venue.name` is included |
| β
| Regenerate wallet link after every change |
—
If you're still stuck, feel free to paste:
– Your JWT payload (sanitized)
– Or share the raw response from the `GET` object endpoint
I'll pinpoint the exact problem for you.
—
### β Step-by-Step: How to Check Your Object via Google Wallet API
—
### π 1. Get OAuth 2.0 Access Token
You need an access token authorized for the Google Wallet API.
#### a. Set up OAuth 2.0 credentials (only once)
– Go to [Google Cloud Console](https://console.cloud.google.com/)
– Enable the **Google Wallet API**
– Create a **Service Account**
– Download the JSON key
#### b. Use this command to get a token:
gcloud auth activate-service-account --key-file=PATH_TO_YOUR_KEY.json
gcloud auth print-access-token
If you donβt use `gcloud`, use this PHP snippet:
$client = new Google_Client();
$client->setAuthConfig('path-to-key.json');
$client->addScope('https://www.googleapis.com/auth/wallet_object.issuer');
$accessToken = $client->fetchAccessTokenWithAssertion()['access_token'];
—
### π§ͺ 2. Use cURL or Postman to Call the `GET` API
Once you have the access token and the object ID, use this:
curl -X GET
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
"https://walletobjects.googleapis.com/walletobjects/v1/eventTicketObject/ISSUER_ID.OBJECT_ID"
π Replace:
– `YOUR_ACCESS_TOKEN` β from step 1
– `ISSUER_ID.OBJECT_ID` β e.g., `issuerId.eventObject_abc123`
—
### β 3. What to Look For
In the JSON response, verify:
"eventName": {
"defaultValue": {
"value": "Fossetts Circus Evening Show"
}
},
"venue": {
"name": {
"defaultValue": {
"value": "Fossetts Arena"
}
},
"address": {
"defaultValue": {
"value": "123 Main Street, Brighton, UK"
}
}
}
If it still shows `"event_venue1"`, the object was never updated correctly.
—
### π§Ό 4. Optional: Delete Old Object (if needed)
You canβt truly delete an object, but you can **generate a new one** with a unique ID each time:
$objectId = 'eventObject_' . uniqid(); // New for each user/order
—
### Need Help?
If you share:
– your issuer ID format
– how you're creating the JWT or inserting the object
I can give you a command or test script tailored to your setup.