PHP Google Wallet Event
August 7, 2025 · AI Conversations
pass event venue and Seats in payload from php
Here’s an example of how to send the **event venue** and **seat info** in the payload when creating a new event ticket object in PHP:
—
### ✅ PHP Example for Google Wallet Event Ticket
$passObject = [
'id' => $objectId,
'classId' => $classId,
'state' => 'active',
'eventName' => [
'defaultValue' => [
'language' => 'en-US',
'value' => $order['event_name']
]
],
'eventId' => (string)$order['event_id'],
// 👇 Venue section
'venue' => [
'name' => [
'defaultValue' => [
'language' => 'en-US',
'value' => $order['event_venue'] // e.g. "Ashford Arena"
]
],
'address' => [
'defaultValue' => [
'language' => 'en-US',
'value' => $venue_address // e.g. "123 Main St, Ashford, Ireland"
]
]
],
// 👇 Optional Seat Info
'seatInfo' => [
'seat' => [
'defaultValue' => [
'language' => 'en-US',
'value' => $order['seat'] // e.g. "A12"
]
],
'row' => [
'defaultValue' => [
'language' => 'en-US',
'value' => $order['row'] // e.g. "Front"
]
],
'section' => [
'defaultValue' => [
'language' => 'en-US',
'value' => $order['section'] // e.g. "Ringside"
]
]
],
'barcode' => [
'type' => 'qrCode',
'value' => $order['order_code'],
'alternateText' => 'Order: ' . $order['order_code']
],
'startDateTime' => $startDateTime, // e.g. 2025-08-01T18:00:00Z
'endDateTime' => $endDateTime,
'doorsOpenDateTime' => $doorsOpenDateTime
];
—
### 📝 Notes:
– You must ensure `$order['event_venue']`, `$order['seat']`, etc. are populated before use.
– Google Wallet uses ISO 8601 format for dates like `2025-08-01T18:00:00Z`.
– If a field like `seatInfo` is not needed, you can omit it.
—
Let me know if you need help with sending this via the Google API (with auth setup), or saving it to a JWT file for later use.
### ✅ Here's how to properly pass venue and seat info that actually shows up in the Google Wallet pass:
—
### ✅ 1. Correct Payload Fields for Google Event Tickets
Google Wallet for **event tickets** provides specific fields for venue and seat information in the [`EventTicketObject`](https://developers.google.com/wallet/tickets/events/reference/rest/v1/eventticketobject):
{
"venue": {
"name": {
"defaultValue": {
"language": "en-US",
"value": "Ashford Arena"
}
},
"address": {
"defaultValue": {
"language": "en-US",
"value": "123 Main Street, Dublin"
}
}
},
"seatInfo": {
"seat": {
"defaultValue": {
"language": "en-US",
"value": "A12"
}
},
"row": {
"defaultValue": {
"language": "en-US",
"value": "Front"
}
},
"section": {
"defaultValue": {
"language": "en-US",
"value": "Ringside"
}
}
}
}
—
### ✅ 2. PHP Example (Simplified)
$object = [
'id' => 'issuerId.objectSuffix',
'classId' => 'issuerId.classSuffix',
'state' => 'active',
'eventName' => [
'defaultValue' => [
'language' => 'en-US',
'value' => 'Fossett’s Circus Live'
]
],
'venue' => [
'name' => [
'defaultValue' => [
'language' => 'en-US',
'value' => 'Ashford Arena'
]
],
'address' => [
'defaultValue' => [
'language' => 'en-US',
'value' => '123 Main Street, Dublin'
]
]
],
'seatInfo' => [
'seat' => [
'defaultValue' => [
'language' => 'en-US',
'value' => 'B7'
]
],
'row' => [
'defaultValue' => [
'language' => 'en-US',
'value' => 'Middle'
]
],
'section' => [
'defaultValue' => [
'language' => 'en-US',
'value' => 'Premium'
]
]
]
];
—
### ⚠️ Don’t Do This:
If you’re passing:
'event_venue' => 'Ashford Arena',
'number_of_seats' => '3',
…those are **not recognized fields**. Google Wallet will just render the literal field names unless you **map them to the correct schema** fields like `venue.name`, `seatInfo.seat`, etc.
—
### ✅ If you really need to show extra info (like seat count):
Use **`textModulesData`** to add custom display fields:
'textModulesData' => [
[
'header' => 'Seats',
'body' => '3 seats booked together'
]
]
—
Let me know if you’d like me to review your exact payload or help debug the pass visually — you can also share the JSON you're using or screenshot of what’s showing incorrectly.
$passObject = [
'id' => $objectId,
'classId' => $fullClassId,
'state' => 'active',
'eventName' => [
'defaultValue' => [
'language' => 'en-US',
'value' => $order['event_venue']
]
],
'eventId' => (string)$order['event_id'],
'venue' => [
'name' => [we still
'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,
'customFields' => [
[
'label' => 'Tickets',
'value' => $ticket_summary_str
],
[
'label' => 'Showtime',
'value' => $showtime_formatted
],
[
'label' => 'Holder',
'value' => $order['customer_name']
]
],
];
we are pssing this
—
## 🚨 Issues in Your Code
### ❌ 1. `eventName` is being misused:
You're passing `event_venue` inside `eventName`, which is **intended for the event's name/title**, **not** the venue.
'eventName' => [
'defaultValue' => [
'language' => 'en-US',
'value' => $order['event_venue'] // ❌ Should be actual event name (e.g., "Fossett’s Circus")
]
]
—
### ❌ 2. Custom fields like `ticketCount`, `showtime`, etc. are not valid standard fields
Google Wallet will ignore **unknown fields** like:
'ticketCount' => $ticket_count, // ❌ not recognized
'ticketSummary' => $ticket_summary_str, // ❌ not recognized
'showtime' => $showtime_formatted, // ❌ not recognized
These will be stripped silently or just won't display.
—
### ✅ 3. You should use `textModulesData` for custom content
This is the **correct way** to show ticket count, showtime, and holder name.
—
## ✅ Corrected Version of Your Payload
$passObject = [
'id' => $objectId,
'classId' => $fullClassId,
'state' => 'active',
// Correct usage of eventName
'eventName' => [
'defaultValue' => [
'language' => 'en-US',
'value' => $order['event_name'] // ✅ real event name (e.g., "Fossett’s Circus")
]
],
'eventId' => (string)$order['event_id'],
// Correct venue
'venue' => [
'name' => [
'defaultValue' => [
'language' => 'en-US',
'value' => $order['event_venue'] // e.g., "Ashford Arena"
]
],
'address' => [
'defaultValue' => [
'language' => 'en-US',
'value' => $venue_address // e.g., "Main Street, Dublin"
]
]
],
'doorsOpenDateTime' => $doorsOpenDateTime,
'startDateTime' => $startDateTime,
'endDateTime' => $endDateTime,
'barcode' => [
'type' => 'qrCode',
'value' => $order['order_code'],
'alternateText' => 'Order: ' . $order['order_code']
],
'ticketHolderName' => $order['customer_name'] ?? '',
// ✅ This is the correct way to show extra data
'textModulesData' => [
[
'header' => 'Tickets',
'body' => $ticket_summary_str // e.g., "2 Adults, 1 Child"
],
[
'header' => 'Showtime',
'body' => $showtime_formatted // e.g., "2025-08-01 6:00PM"
],
[
'header' => 'Holder',
'body' => $order['customer_name']
]
]
];
—
### 🧪 Optional Seat Info (if available):
Add this block only if you're assigning specific seats:
'seatInfo' => [
'seat' => [
'defaultValue' => [
'language' => 'en-US',
'value' => 'A12'
]
],
'row' => [
'defaultValue' => [
'language' => 'en-US',
'value' => 'Front'
]
],
'section' => [
'defaultValue' => [
'language' => 'en-US',
'value' => 'Premium'
]
]
]
—
## ✅ Summary
| ✅ Do This | ❌ Avoid This |
|———————————-|———————————-|
| Use `eventName` for event title | Don’t use it for venue |
| Use `venue.name/address` | Don’t use `event_venue` outside it |
| Use `textModulesData` for custom fields | Don’t add unknown keys at root |
| Use `seatInfo` if assigning seats | Don’t rely on `number_of_seats` |
—
Let me know if you want to test the full JWT or if you're using the [Save to Google Wallet](https://developers.google.com/wallet/guides/get-started) flow — I can help generate that too.
—
### ✅ Use `$order['event_venue']` for Both `eventName` and `venue.name`
$passObject = [
'id' => $objectId,
'classId' => $fullClassId,
'state' => 'active',
// 👇 Use event_venue as the event title
'eventName' => [
'defaultValue' => [
'language' => 'en-US',
'value' => $order['event_venue'] // e.g., "Ashford Arena"
]
],
'eventId' => (string)$order['event_id'],
// 👇 Use event_venue again as the venue name
'venue' => [
'name' => [
'defaultValue' => [
'language' => 'en-US',
'value' => $order['event_venue'] // same value reused
]
],
'address' => [
'defaultValue' => [
'language' => 'en-US',
'value' => $venue_address // e.g., "123 Main St, Dublin"
]
]
],
'doorsOpenDateTime' => $doorsOpenDateTime,
'startDateTime' => $startDateTime,
'endDateTime' => $endDateTime,
'barcode' => [
'type' => 'qrCode',
'value' => $order['order_code'],
'alternateText' => 'Order: ' . $order['order_code']
],
'ticketHolderName' => $order['customer_name'] ?? '',
// Optional: use textModulesData to show ticket summary, showtime, etc.
'textModulesData' => [
[
'header' => 'Tickets',
'body' => $ticket_summary_str // e.g., "2 Adults, 1 Child"
],
[
'header' => 'Showtime',
'body' => $showtime_formatted // e.g., "6:00 PM, August 1st"
],
[
'header' => 'Holder',
'body' => $order['customer_name']
]
]
];
—
### 💡 Summary
You’re **allowed to reuse the same string** (`$order['event_venue']`) for both:
– `eventName.defaultValue.value` (event name/title)
– `venue.name.defaultValue.value` (venue name)
Just make sure the structure exactly matches Google Wallet’s API schema — they only render fields they recognize.
Let me know if you also want to add fallback values or dynamically switch between “Circus Tour” and venue name based on conditions.
—
## ❌ Problem:
You're seeing literal text like:
– `event_venue` under **event_venue**
– `number_of_seats` under **Seats**
This means you're likely passing **custom field keys** like `'event_venue'` and `'number_of_seats'` as **custom attributes**, which Google Wallet doesn't understand natively. So it displays the **key** (`event_venue`, `number_of_seats`) instead of actual values.
—
## ✅ Fix: Use `textModulesData` Properly
Here’s how to **correctly display values like venue name, seat count, and seating area** without triggering this issue:
### ✅ Updated PHP Payload
$passObject = [
'id' => $objectId,
'classId' => $fullClassId,
'state' => 'active',
'eventName' => [
'defaultValue' => [
'language' => 'en-US',
'value' => $order['event_venue'] // OK to reuse
]
],
'eventId' => (string)$order['event_id'],
'venue' => [
'name' => [
'defaultValue' => [
'language' => 'en-US',
'value' => $order['event_venue']
]
],
'address' => [
'defaultValue' => [
'language' => 'en-US',
'value' => $venue_address
]
]
],
'barcode' => [
'type' => 'qrCode',
'value' => $order['order_code'],
'alternateText' => 'Order: ' . $order['order_code']
],
'ticketHolderName' => $order['customer_name'] ?? '',
// ✅ Proper way to show custom info
'textModulesData' => [
[
'header' => 'Venue',
'body' => $order['event_venue']
],
[
'header' => 'Seats',
'body' => $order['number_of_seats'] . ' seats'
],
[
'header' => 'Seating Area',
'body' => $order['seating_area'] ?? 'General'
]
],
'doorsOpenDateTime' => $doorsOpenDateTime,
'startDateTime' => $startDateTime,
'endDateTime' => $endDateTime
];
—
## 🚫 What Not to Do
Avoid this:
'event_venue' => $order['event_venue'], // ❌ Not recognized
'number_of_seats' => $order['seat_count'], // ❌ Not recognized
These become undefined/unknown keys and are rendered literally.
—
## 🧪 Test it visually:
After applying the fix:
1. Regenerate the pass.
2. Add to Google Wallet again (it won’t update an existing saved pass unless you create a **new object ID**).
3. Check that:
– The right-side panel shows **actual values**, not labels.
– Custom fields appear under "Text modules" with readable headers like "Venue", "Seats", etc.
—
Let me know if you want a live example or help generating the JWT with this corrected object.
$passObject = [
'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,
'customFields' => [
[
'label' => 'Tickets',
'value' => $ticket_summary_str
],
[
'label' => 'Showtime',
'value' => $showtime_formatted
],
[
'label' => 'Holder',
'value' => $order['customer_name']
]
],
];
—
### ❌ Problem: You're using **non-standard keys** like `ticketCount`, `ticketSummary`, `showtime`, and `customFields`.
Google Wallet **ignores unknown fields** like these unless they're in a supported field like `textModulesData`, `seatInfo`, `location`, etc.
As a result:
– The labels like `event_venue` and `number_of_seats` are being **interpreted as your custom field keys**, and Google Wallet **shows the key itself** (not your intended label).
– The content is showing up **incorrectly or not at all**.
—
### ✅ Fix: Use `textModulesData` Instead of `customFields`
Replace your **invalid** `customFields`, `ticketCount`, `ticketSummary`, and `showtime` entries with **Google-supported** fields.
—
### ✅ Corrected `$passObject` Structure
$passObject = [
'id' => $objectId,
'classId' => $fullClassId,
'state' => 'active',
'eventName' => [
'defaultValue' => [
'language' => 'en-US',
'value' => $order['event_venue'] // Using event_venue as event title
]
],
'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'] ?? '',
// ✅ Use textModulesData for any custom display fields
'textModulesData' => [
[
'header' => 'Tickets',
'body' => $ticket_summary_str // e.g., "2 Adults, 1 Child"
],
[
'header' => 'Showtime',
'body' => $showtime_formatted // e.g., "7:00 PM, Aug 1"
],
[
'header' => 'Seating Area',
'body' => $order['seating_area'] ?? 'Ringside'
]
]
];
—
### 💡 Summary of Required Fixes
| ❌ Incorrect | ✅ Correct |
|————————————–|——————————————-|
| `'ticketCount' => $val` | Move to `textModulesData` as `body` |
| `'customFields' => […]` | ❌ Not supported by Google Wallet |
| `'event_venue' => 'value'` (as key) | Use it **inside** `eventName` and `venue` |
| `'number_of_seats' => 'value'` | Use it in `textModulesData` |
—
### ✅ Pro Tip: Regenerate Pass After Changes
If you've already added the old version to your Wallet, Google may cache the object. Create a **new unique object ID** (e.g., `issuerId.object123-v2`) to ensure the updated fields show properly.
—
Let me know if you want me to help generate the full JWT for this or guide you through the save-to-wallet flow.
BUt its stills shows event_venue text in placer of venue value
—
## ❌ Problem:
You're setting this:
'eventName' => [
'defaultValue' => [
'language' => 'en-US',
'value' => $order['event_venue'] // 👈 you're using the venue name as the event name
]
],
And that’s OK — **but** what you're seeing as `"event_venue"` in the Google Wallet pass (in gray above the event name) is **not the value** — it's the **`eventName.label`**, and if you don’t set that, Google uses the fallback: the **field name**.
That’s why it shows `event_venue` as a literal label above the title.
—
## ✅ Fix: Add `label` to `eventName`
Update your code like this:
'eventName' => [
'defaultValue' => [
'language' => 'en-US',
'value' => $order['event_venue']
],
'label' => 'Event Location' // ✅ This shows up instead of "event_venue"
],
You can label it anything you want: `"Event"`, `"Event Location"`, `"Venue"`, etc.
—
### ✅ Example
'eventName' => [
'defaultValue' => [
'language' => 'en-US',
'value' => 'Fossetts Big Top, Galway'
],
'label' => 'Venue' // This will show in light gray above the event name
]
—
## ✅ Result in Google Wallet
You will now see:
Venue
Fossetts Big Top, Galway
instead of:
event_venue
Fossetts Big Top, Galway
—
Let me know if you'd like me to help verify other fields too (e.g., barcode text, date display, etc.).
'id' => $objectId,
'classId' => $fullClassId,
'state' => 'active',
'eventName' => [
'defaultValue' => [
'language' => 'en-US',
'value' => $order['event_venue']
],
'label' => 'Event Venue'
],
'eventId' => (string)$order['event_id'],
'venue' => [
'name' => [
'defaultValue' => [
'language' => 'en-US',
'value' => $order['event_venue']
],
'label' => 'Event Venue'
],
'address' => [
'defaultValue' => [
'language' => 'en-US',
'value' => $venue_address
],
'label' => 'Event Venue'
]
],
'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,
'textModulesData' => [
[
'header' => 'Event Venue',
'body' => $order['event_venue']
],
[
'header' => 'Tickets',
'body' => $ticket_summary_str
],
[
'header' => 'Showtime',
'body' => $showtime_formatted
]
],
];
its still showin google wallert ticket
event_venue and under Seats->number_of_seats
—
## 🔍 Why This Is Happening
Google Wallet automatically shows certain **fields in the summary section** (right panel) like:
– `ticketHolderName`
– `seatInfo`
– `locations`
– `textModulesData`
But when you include unsupported **custom field names** like:
'ticketCount' => $ticket_count,
'ticketSummary' => $ticket_summary_str,
'showtime' => $showtime_formatted,
Google Wallet **tries to render those keys** literally — `ticketCount`, `event_venue`, `number_of_seats` — even though they're not valid.
—
## ✅ Your Fixes to Make:
### 1. **REMOVE these unsupported fields entirely**:
'ticketCount' => $ticket_count,
'ticketSummary' => $ticket_summary_str,
'showtime' => $showtime_formatted,
They are not part of the official Event Ticket Object schema, and **Google renders them as-is**, which causes the issue.
—
### 2. **Use `textModulesData` only** for displaying info like number of seats and venue.
You’re already doing this part correctly:
'textModulesData' => [
[
'header' => 'Event Venue',
'body' => $order['event_venue']
],
[
'header' => 'Tickets',
'body' => $ticket_summary_str
],
[
'header' => 'Showtime',
'body' => $showtime_formatted
]
],
That is the **correct and only supported way** to show dynamic extra data.
—
### ✅ Final `$passObject` (Cleaned Up)
$passObject = [
'id' => $objectId,
'classId' => $fullClassId,
'state' => 'active',
'eventName' => [
'defaultValue' => [
'language' => 'en-US',
'value' => $order['event_venue']
],
'label' => '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'] ?? '',
// ✅ Only supported custom text
'textModulesData' => [
[
'header' => 'Event Venue',
'body' => $order['event_venue']
],
[
'header' => 'Tickets',
'body' => $ticket_summary_str
],
[
'header' => 'Showtime',
'body' => $showtime_formatted
]
]
];
—
## ✅ Summary
| Fix This | With This |
|————————————-|———————————-|
| ❌ `ticketCount`, `ticketSummary` | ✅ Use `textModulesData` instead |
| ❌ `event_venue` as raw field | ✅ Use inside `eventName`, `venue` only |
| ❌ `number_of_seats` as raw field | ✅ Move into `textModulesData` or `seatInfo` |
—
## 🧪 Next Step
Regenerate the pass with this cleaned payload.
Make sure you use a **new `objectId`** (e.g., append `-v2`) so Google Wallet does not cache the previous version.
Let me know if you want a ready-made JSON or JWT output to test.
—
## 🧨 Root Cause: You Are Still Sending These **Invalid Custom Fields**
'event_venue' => 'value',
'number_of_seats' => 'value',
These **do not exist** in Google Wallet’s Event Ticket schema.
So Google Wallet is:
– Seeing `event_venue` and `number_of_seats` as unrecognized keys,
– And rendering them in the **summary panel** with literal fallback values:
`event_venue` → *event_venue*,
`number_of_seats` → *number_of_seats*
—
## ✅ Absolute Fix: Remove These Two Fields Entirely
Please **remove** or **comment out** these lines:
// REMOVE or COMMENT these
'event_venue' => $order['event_venue'], // ❌ Wrong
'number_of_seats' => $ticket_count, // ❌ Wrong
—
### ✅ You Already Have the Correct Replacement Here:
'textModulesData' => [
[
'header' => 'Event Venue',
'body' => $order['event_venue']
],
[
'header' => 'Tickets',
'body' => $ticket_summary_str
],
[
'header' => 'Showtime',
'body' => $showtime_formatted
]
]
✅ That is how Google Wallet wants you to show this extra info. Nothing else is needed.
—
## ✅ Final `$passObject` Template (Cleaned & Working)
$passObject = [
'id' => $objectId,
'classId' => $fullClassId,
'state' => 'active',
'eventName' => [
'defaultValue' => [
'language' => 'en-US',
'value' => $order['event_venue']
],
'label' => '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'] ?? '',
// ✅ Only valid display section
'textModulesData' => [
[
'header' => 'Event Venue',
'body' => $order['event_venue']
],
[
'header' => 'Tickets',
'body' => $ticket_summary_str
],
[
'header' => 'Showtime',
'body' => $showtime_formatted
]
]
];
—
## ✅ IMPORTANT FINAL STEP
After fixing this payload:
– **Change the `objectId`** (e.g., add `-v2` or a timestamp suffix)
– Re-upload or re-link the pass to Google Wallet
Because once a pass is saved, Google **does not update** it unless the object ID changes.
—
Let me know if you want a working sample JWT or helper script to test this in Google Wallet!
—
## ✅ You Are Using an Outdated or Cached Pass Object
Google Wallet caches the **objectId** and won’t reflect changes unless you do one of the following:
—
## ✅ ✅ Solution: Change the `objectId`
Update this line in your PHP:
'id' => 'issuerId.object123',
to something **unique**, like:
'id' => 'issuerId.object123-v2', // or use timestamp
Why?
> Even if you fix your PHP code perfectly, Google Wallet will **still show old fields** if you're reusing the same object ID that previously had bad data.
—
### 🔄 Also, if you’re regenerating the class as well, make sure:
– `classId` is valid and has no stale default values like `number_of_seats` in it.
—
## 🧪 How to Fully Clean & Re-Test
1. ✅ Ensure `event_venue` and `number_of_seats` are **not in your `$passObject`**
2. ✅ Set a **new `objectId`** (e.g. `'issuerId.ticket-'.time()`)
3. ✅ Push this new object to Google Wallet
4. ✅ Add it to Wallet using the new URL/JWT
5. 🚫 Don’t open an old pass you already saved — test only the new one
—
## 🔧 Optional Debug Tip
If you're unsure what data is still attached to your old pass object, query it directly with:
GET https://walletobjects.googleapis.com/walletobjects/v1/eventTicketObject/{objectId}
Authorization: Bearer {your-access-token}
You’ll likely see `event_venue` or `number_of_seats` still stored.
—
Let me know if you'd like a quick PHP code snippet to auto-generate new object IDs for each ticket instance — or a command to clean old test passes.
– ✅ Are **not** sending `event_venue` or `number_of_seats` in the payload,
– ✅ Already tried **changing `objectId`** to a fresh unique one,
– ✅ Still see `event_venue` and `number_of_seats` as labels in the pass…
Then the last remaining cause is this:
—
## 🧨 Google Wallet **Class (`EventTicketClass`) Still Contains Default `event_venue` and `number_of_seats` Fields**
Even if your **object** is clean, if your **class** (i.e. `EventTicketClass`) has fields defined like:
{
"event_venue": {
"label": "event_venue",
"value": "Fossetts Big Top, Galway"
},
"number_of_seats": {
"label": "number_of_seats",
"value": "3"
}
}
Google Wallet **will render these fields** by default in the ticket preview.
—
### ✅ Fix: Delete or Regenerate a Clean `classId`
There are two ways to fix it:
—
### ✅ Option 1: Regenerate a clean `classId`
Change this in your code:
'classId' => 'issuerId.myTicketClass'
To something like:
$classId = 'issuerId.myTicketClass-' . time(); // unique and clean
And then **do NOT include any custom fields** in the `EventTicketClass` payload.
—
### ✅ Option 2: Clean up existing class
If you're managing your class manually, reissue your class payload like this:
$classPayload = [
'id' => $fullClassId,
'issuerName' => 'Fossetts Circus',
'eventName' => [
'defaultValue' => [
'language' => 'en-US',
'value' => 'Fossetts Big Top'
]
],
// ⚠️ Do NOT include any custom fields like event_venue or number_of_seats
// Do NOT use `textModulesData` in class unless you want static data on all tickets
];
Use the [Google Wallet API](https://developers.google.com/wallet) to update or recreate the class.
—
## ✅ Summary
| Step | What to Do |
|——|————|
| ✅ | Confirm `objectId` is fresh |
| ✅ | Remove all custom fields like `event_venue` or `number_of_seats` |
| ✅ | **Regenerate or clean your `classId`** (this is the hidden culprit) |
| 🚫 | Do not reuse existing class that had old fields — Google caches it |
—
Let me know if you’d like:
– A quick curl/PHP snippet to regenerate the `EventTicketClass`
– A sample JWT with fresh object + class for testing
– Help inspecting the existing class payload via API
EventTicketClass and EventTicketObject and how I will pass it using php
—
## 🧠 Google Wallet Concepts: `EventTicketClass` vs `EventTicketObject`
| Component | Purpose |
|———————-|————————————————————————-|
| **EventTicketClass** | Defines the template for all tickets of a certain type (branding, logo, layout, static info). Think of it like a master pass design. |
| **EventTicketObject**| Represents a **single user’s ticket** (e.g., a specific ticket for David Lawless to Fossetts Circus). |
—
### 🎯 In PHP, your flow is:
1. **Create the Class once** (reusable)
2. **Create a unique Object** per ticket
3. Optionally, generate a JWT to link it to Wallet
—
## ✅ 1. Example: Create `EventTicketClass` (PHP Payload)
Only needs to be created **once per event/template**.
$classPayload = [
'id' => 'issuerId.classId123', // must match issuerId
'issuerName' => 'Fossetts Circus',
'reviewStatus' => 'UNDER_REVIEW',
'eventName' => [
'defaultValue' => [
'language' => 'en-US',
'value' => 'Fossetts Big Top, Galway'
]
],
'logo' => [
'sourceUri' => [
'uri' => 'https://yourdomain.com/logo.png'
]
]
];
// POST to: https://walletobjects.googleapis.com/walletobjects/v1/eventTicketClass
—
## ✅ 2. Create `EventTicketObject` (PHP Payload)
One per ticket/order/customer.
$objectPayload = [
'id' => 'issuerId.object1234', // must be globally unique
'classId' => 'issuerId.classId123', // the class you created above
'state' => 'active',
'eventName' => [
'defaultValue' => [
'language' => 'en-US',
'value' => 'Fossetts Big Top, Galway'
]
],
'ticketHolderName' => 'David Lawless',
'barcode' => [
'type' => 'qrCode',
'value' => '384.2330.3beabe978a',
'alternateText' => 'Order: 384.2330.3beabe978a'
],
'textModulesData' => [
[
'header' => 'Seating Area',
'body' => 'Ringside'
],
[
'header' => 'Showtime',
'body' => 'Thursday, July 24, 2025 at 5:00 PM'
]
]
];
// POST to: https://walletobjects.googleapis.com/walletobjects/v1/eventTicketObject
—
## ✅ 3. Optional: Generate JWT for “Save to Wallet” Button
After you create the class and object, you can use Google’s JWT signing to generate a save link:
// Use firebase/php-jwt
use FirebaseJWTJWT;
$claims = [
"iss" => $serviceAccountEmail,
"aud" => "google",
"typ" => "savetowallet",
"payload" => [
"eventTicketObjects" => [
["id" => "issuerId.object1234"]
]
]
];
$jwt = JWT::encode($claims, $privateKey, "RS256");
$saveUrl = "https://pay.google.com/gp/v/save/" . $jwt;
This gives you a link you can send to users to add the pass to their Wallet.
—
## 📌 Summary
| Step | Endpoint |
|—————————–|———-|
| Create Class (once) | `POST https://walletobjects.googleapis.com/walletobjects/v1/eventTicketClass` |
| Create Object (per ticket) | `POST https://walletobjects.googleapis.com/walletobjects/v1/eventTicketObject` |
| Create JWT (optional) | Use Firebase JWT in PHP to generate Save link |
—
## 🔐 Requirements
– You must authenticate using a **service account** with Google Wallet API access.
– You need:
– `serviceAccount.json`
– `issuerId`
– `credentials` file from Google Cloud Console
– `firebase/php-jwt` installed via Composer
—
Would you like:
– A full working PHP script that does class + object + JWT?
– Help setting up your service account or API credentials?
Just say the word and I’ll walk you through step-by-step.
—
## ✅ The Problem is in the Class — Not the Object
Your `passObject` is clean — no `event_venue` or `number_of_seats` keys.
But your pass **still shows these**, which **can only mean**:
> ❗ You are reusing an existing `EventTicketClass` (`live_fossetts_ticket`) that already contains `event_venue` and `number_of_seats` as custom fields from an earlier version.
Google caches the class **permanently** unless a new one is created — and **every object that refers to that class will inherit its bad fields.**
—
## ✅ The Fix
### 🔁 Create a New Class with a New `classId`
Update this:
$classId = 'live_fossetts_ticket';
To something like:
$classId = 'live_fossetts_ticket_' . date('Ymd_His'); // ensures uniqueness
Then update:
$objectId = $issuerId . '.' . $classId . '_' . $order_code;
$fullClassId = $issuerId . '.' . $classId;
—
### ✅ Create the Clean Class First (via API)
Before redirecting to JWT, you must POST this once:
$eventTicketClass = [
'id' => $fullClassId,
'issuerName' => 'Fossetts Circus',
'eventName' => [
'defaultValue' => [
'language' => 'en-US',
'value' => 'Fossetts Big Top'
]
],
'logo' => [
'sourceUri' => [
'uri' => 'https://yourdomain.com/path-to-logo.png'
]
],
'reviewStatus' => 'UNDER_REVIEW'
];
### 🔧 Send it via cURL or Guzzle (authenticated)
$client = new GuzzleHttpClient();
$res = $client->post('https://walletobjects.googleapis.com/walletobjects/v1/eventTicketClass', [
'headers' => [
'Authorization' => 'Bearer ' . $accessToken,
'Content-Type' => 'application/json',
],
'body' => json_encode($eventTicketClass)
]);
Let me know if you want the full Guzzle implementation including auth using your `serviceAccount` (easy).
—
## ✅ Summary
| Step | What to Do |
|——|————|
| ❌ Still seeing `event_venue` and `number_of_seats`? | ✅ You're using an old cached class that includes those fields |
| ✅ Solution | Create a **new `classId`**, and assign that to your object |
| ✅ Bonus | Repost the class using `POST /eventTicketClass` with clean values |
—
Would you like me to give you a single PHP script that:
– Creates a new class using Guzzle,
– Creates the object,
– Generates the JWT?
Let me know — you’re *one clean `classId` away* from fully solving this.
—
## ✅ `event_venue` Must Go in the **Object**, Not the Class
Let me clarify:
– The `**Class**` is the **shared static template** (logo, issuer, branding).
– The `**Object**` is **individual and dynamic per ticket** (event name, venue, seat info, date, etc).
—
## ✅ How to Dynamically Show `event_venue` in the Object (Correct Way)
Here’s how to show **event venue name dynamically** (for each ticket) **without needing to recreate the class** every time:
### ✅ In the Object:
'eventName' => [
'defaultValue' => [
'language' => 'en-US',
'value' => $order['event_venue']
],
'label' => 'Venue'
],
'venue' => [
'name' => [
'defaultValue' => [
'language' => 'en-US',
'value' => $order['event_venue'] // ✅ dynamic per ticket
]
],
'address' => [
'defaultValue' => [
'language' => 'en-US',
'value' => $venue_address
]
]
]
✅ You’re already doing this correctly in your code!
—
## 🚫 What You Should **Not** Do:
Do **not** try to make `event_venue` dynamic inside the class. That’s what causes the stale `event_venue` and `number_of_seats` issue you're seeing.
—
## ✅ What You Need to Do Now:
Since you said you're **still seeing old field labels** ("event_venue", "number_of_seats"), that means you're using an **old class** which had bad static values.
### ✅ Final Fix Plan (No more stale fields):
1. **Create a new `classId`** (just once) — to avoid cached bad data
2. Continue dynamically passing `event_venue` in the **object**
3. Reuse that `classId` for all future tickets — no need to keep recreating it
4. ✅ You're done — all tickets will now show the correct venue per customer
—
### 🎯 Example:
– Class: `3388000000022962508.live_fossetts_ticket_20250716` ✅ Clean
– Object 1: `3388000000022962508.live_fossetts_ticket_20250716_3842`
– `event_venue`: Ashford Arena
– Object 2: `3388000000022962508.live_fossetts_ticket_20250716_3909`
– `event_venue`: Galway City Big Top
—
Let me know if you want a helper script to create a clean class one-time, then reuse it. I can drop it in a ready-to-run form with your service account.
—
## ✅ Endpoint to Get an Existing Class
### HTTP GET:
GET https://walletobjects.googleapis.com/walletobjects/v1/eventTicketClass/{classId}
Where `{classId}` is in the format:
issuerId.classSuffix
For example:
3388000000022962508.live_fossetts_ticket
—
## ✅ PHP Code (Guzzle Example)
Here's a full PHP snippet to fetch the `EventTicketClass` and inspect what fields exist:
require 'vendor/autoload.php';
use GoogleAuthOAuth2;
// Load your service account credentials
$credentials = json_decode(file_get_contents(__DIR__ . '/certs/fossettstickets-5eaa35f58b0b.json'), true);
// Get access token using GoogleAuth
$oauth = new OAuth2([
'audience' => 'https://walletobjects.googleapis.com/',
'issuer' => $credentials['client_email'],
'signingAlgorithm' => 'RS256',
'signingKey' => $credentials['private_key'],
'tokenCredentialUri' => 'https://oauth2.googleapis.com/token',
'scope' => 'https://www.googleapis.com/auth/wallet_object.issuer'
]);
$token = $oauth->fetchAuthToken();
// Set class ID to fetch
$issuerId = '3388000000022962508';
$classSuffix = 'live_fossetts_ticket';
$fullClassId = "$issuerId.$classSuffix";
// Use Guzzle to call Google Wallet API
$client = new GuzzleHttpClient();
try {
$response = $client->get("https://walletobjects.googleapis.com/walletobjects/v1/eventTicketClass/{$fullClassId}", [
'headers' => [
'Authorization' => 'Bearer ' . $token['access_token'],
'Accept' => 'application/json',
]
]);
$data = json_decode($response->getBody(), true);
echo "<pre>";
print_r($data);
echo "</pre>";
} catch (GuzzleHttpExceptionClientException $e) {
echo 'Error: ' . $e->getResponse()->getBody()->getContents();
}
—
## ✅ What You Can Do With It
– See if it contains bad fields like `event_venue`, `number_of_seats`
– Confirm if it has outdated `textModulesData`
– Use the response to clone a **clean version** with a new classId if needed
—
## ✅ Optional: Delete/Replace?
Unfortunately, **Google Wallet does not let you delete a class** once created. The only option is to **create a new classId** (which you've already started doing). You can reuse the cleaned-up class going forward.
—
Let me know if you’d like me to help create a fixed version of the class with your logo, name, and clean fields.