PHP Google Wallet Event

User
https://developers.google.com/wallet/tickets/events
pass event venue and Seats in payload from php
Assistant
To pass **event venue** and **seats** in the payload for a **Google Wallet Event Ticket** using PHP, you’ll need to structure your pass object according to the [Google Wallet Event Ticket API](https://developers.google.com/wallet/tickets/events) schema.

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.

User
but google ticket still show get event_venue and number_of_seats
Assistant
If you're seeing **`event_venue`** and **`number_of_seats`** as literal text fields (like `event_venue` instead of an actual venue name), it likely means you're **passing them as custom fields**, or not populating the correct standard fields required by **Google Wallet Event Tickets** schema.

### ✅ 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.

User
// Build event ticket object (no seatInfo)
$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
Assistant
Thanks for sharing your PHP payload — you're close, but there are two main issues causing the `event_venue` and `number_of_seats` to show up **incorrectly or not at all** in Google Wallet:

## 🚨 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.

User
 But I want event_venune will use for both name and venue
Assistant
Great — if you want to use `event_venue` **both as the name of the venue** and **as the event name/title**, you can absolutely do that. Here's how to set it **correctly** in your payload:

### ✅ 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.

User
Its still showing as attached
Assistant
Thanks for sharing the screenshot. Based on the pass display, the issue is clear:

## ❌ 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.

User
No I'm passing this
$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']
]
],
];
Assistant
Thanks, Neeraj. Now that you've clarified your actual code again, here's the root issue:

### ❌ 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.

User
okay now custom fields is fixed
BUt its stills shows event_venue text in placer of venue value
Assistant
Perfect — since the custom fields are fixed and **only `event_venue` is still showing as literal text**, that **confirms** one remaining issue:

## ❌ 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.).

User
$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']
],
'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
Assistant
Thanks for the updated code, Neeraj — you're super close. You're passing everything almost correctly now, but the issue is still **Google Wallet displaying `event_venue` and `number_of_seats` on the right-hand summary panel**, even though your values are correct.

## 🔍 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.

User
its still snow event_venue and number_of_seats text without value
Assistant
Thank you for the latest screenshot — now it's 100% clear what’s happening:

## 🧨 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!

User
NO I'm not sending
Assistant
Thanks for the clarification — if you're **not sending** `event_venue` or `number_of_seats` as fields in your PHP payload, but you're **still seeing them in the Google Wallet ticket** (as in your screenshot), then this **only means one thing**:

## ✅ 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.

User
still not working
Assistant
Thanks for confirming, Neeraj. If you:

– ✅ 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

User
what is
EventTicketClass and EventTicketObject and how I will pass it using php
Assistant
Great question, Neeraj. Let’s break it down clearly — this is **central** to working with Google Wallet:

## 🧠 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.

User
Assistant
Thanks for sharing the full working PHP code. Your setup is excellent, and you’re **almost 100% there**. You're now generating everything properly via JWT. But since you're **still seeing** `event_venue` and `number_of_seats` in your Google Wallet ticket, here's the **exact diagnosis and final fix**:

## ✅ 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.

User
But I need event_venue name dynamically update
Assistant
Perfect — and yes, you absolutely **can** have `event_venue` update dynamically **per ticket**, but the key is:

## ✅ `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.

User
okay can i get the EventTicketclass first created by previous class id
Assistant
Yes, Neeraj — you can absolutely retrieve an existing `EventTicketClass` using the **class ID** via the Google Wallet REST API.

## ✅ 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.

Leave a Comment

Your email address will not be published. Required fields are marked *