Added new use case examples (#51)

* Added examples for the following
  * Update a class/object
  * Patch a class/object
  * Add a message to a class/object
  * Expire an object
  * Create a JWT with new classes/objects
  * Create a JWT with existing classes/objects
* Fixed various minor formatting issues
* Made function/method names more general (ease of replication
   across different languages)
* Added checks for class/object presence
* Clarified some docstrings and comments
This commit is contained in:
Nick Alteen
2022-12-02 09:55:02 -05:00
committed by GitHub
parent 2040ecd695
commit 957f0419c0
48 changed files with 21398 additions and 10477 deletions

View File

@@ -1,21 +1,25 @@
# Google Wallet Samples
This project contains samples for using the [Google Wallet REST APIs](https://developers.google.com/wallet/) in the following languages:
This project contains samples for using the
[Google Wallet REST APIs](https://developers.google.com/wallet/) in the
following languages:
* [Java](./java/README.md)
* [C#](./dotnet/README.md)
* [JavaScript (Node.js)](./nodejs/README.md)
* [PHP](./php/README.md)
* [Python](./python/README.md)
* [Java](./java/README.md)
* [C#](./dotnet/README.md)
* [JavaScript (Node.js)](./nodejs/README.md)
* [PHP](./php/README.md)
* [Python](./python/README.md)
Within each language's directory, you'll find standalone samples for each of the pass types supported by the Google Wallet APIs.
Within each language's directory, you'll find standalone samples for each of the
pass types supported by the Google Wallet APIs.
Each sample demonstrates the following:
* Authenticating using a Google Cloud service account
* Creating a pass class
* Creating/retrieving a pass object
* Creating a signed JWT and a "Add to Google Wallet" URL
* Creating a Google Wallet issuer account
* Updating permissions for an issuer account
* Performing batch API calls to improve performance
* Authenticating using a Google Cloud service account
* Creating, updating, and patching a pass class
* Adding messages to a pass class
* Creating, updating, and patching a pass object
* Adding messages to a pass object
* Expiring a pass object
* Creating a signed JWT and a "Add to Google Wallet" URL
* Performing batch API calls to improve performance

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -6,22 +6,24 @@ The files in this directory each implement a demo class for a specific Google
Wallet pass type. Each class implements methods for performing tasks such as
creating a pass class, updating issuer permissions, and more.
| Pass type | File |
|-----------|------|
| Event tickets | [DemoEventTicket.cs](./DemoEventTicket.cs) |
| Flight boarding passes | [DemoFlight.cs](./DemoFlight.cs) |
| Generic passes | [DemoGeneric.cs](./DemoGeneric.cs) |
| Gift cards | [DemoGiftCard.cs](./DemoGiftCard.cs) |
| Loyalty program membership | [DemoLoyalty.cs](./DemoLoyalty.cs) |
| Offers and promotions | [DemoOffer.cs](./DemoOffer.cs) |
| Transit passes | [DemoTransit.cs](./DemoTransit.cs) |
| Pass type | File |
|----------------------------|--------------------------------------------|
| Event tickets | [DemoEventTicket.cs](./DemoEventTicket.cs) |
| Flight boarding passes | [DemoFlight.cs](./DemoFlight.cs) |
| Generic passes | [DemoGeneric.cs](./DemoGeneric.cs) |
| Gift cards | [DemoGiftCard.cs](./DemoGiftCard.cs) |
| Loyalty program membership | [DemoLoyalty.cs](./DemoLoyalty.cs) |
| Offers and promotions | [DemoOffer.cs](./DemoOffer.cs) |
| Transit passes | [DemoTransit.cs](./DemoTransit.cs) |
## Prerequisites
* .NET 6.0
* Follow the steps outlined in the [Google Wallet prerequisites](https://developers.google.com/wallet/generic/web/prerequisites) to create the Google Wallet issuer account and Google Cloud service account
* Download the C#
[Google Wallet API Client library](https://developers.google.com/wallet/generic/resources/libraries#c)
* .NET 6.0
* Follow the steps outlined in the
[Google Wallet prerequisites](https://developers.google.com/wallet/generic/web/prerequisites)
to create the Google Wallet issuer account and Google Cloud service account
* Download the C#
[Google Wallet API Client library](https://developers.google.com/wallet/generic/resources/libraries#c)
## Environment variables
@@ -29,46 +31,65 @@ The following environment variables must be set. Alternatively, you can update
the code files to set the values directly. They can be found in the constructor
for each class file.
| Enviroment variable | Description | Example |
|---------------------|-------------|---------|
| Enviroment variable | Description | Example |
|----------------------------------|-------------------------------------------------|---------------------|
| `GOOGLE_APPLICATION_CREDENTIALS` | Path to a Google Cloud service account key file | `/path/to/key.json` |
## How to use the code samples
1. Open the [`wallet-rest-samples.csproj`](./wallet-rest-samples.csproj) file
in your .NET editor of choice.
2. Copy the path to the Google Wallet API Client library (
`Google.Apis.Walletobjects.v1.csproj` file) you downloaded. If needed, update
the path in [`wallet-rest-samples.csproj`](./wallet-rest-samples.csproj) (line
19).
1. Open the [`wallet-rest-samples.csproj`](./wallet-rest-samples.csproj) file
in your .NET editor of choice.
2. Copy the path to the Google Wallet API Client library (
`Google.Apis.Walletobjects.v1.csproj` file) you downloaded. If needed, update
the path in [`wallet-rest-samples.csproj`](./wallet-rest-samples.csproj) (line
19).
```xml
<CodeFiles Include="lib/Google.Apis.Walletobjects.v1.cs" />
```
3. Build the project to install the dependencies.
4. In your C# code, import a demo class and call its method(s). An example
can be found below
3. Build the project to install the dependencies.
4. In your C# code, import a demo class and call its method(s). An example
can be found below
```csharp
// Create a demo class instance
// Creates the authenticated HTTP client
DemoEventTicket demo = new DemoEventTicket();
// Create the authenticated HTTP client
demo.Auth();
// Create a pass class
demo.CreateEventTicketClass("issuer_id", "class_suffix");
demo.CreateClass("issuer_id", "class_suffix");
// Update a pass class
demo.UpdateClass("issuer_id", "class_suffix");
// Patch a pass class
demo.PatchClass("issuer_id", "class_suffix");
// Add a message to a pass class
demo.AddClassMessage("issuer_id", "class_suffix", "header", "body");
// Create a pass object
demo.CreateEventTicketObject("issuer_id", "class_suffix", "user_id");
demo.CreateObject("issuer_id", "class_suffix", "object_suffix");
// Create an Add to Google Wallet link
demo.CreateJWTSaveURL("issuer_id", "class_suffix", "user_id");
// Update a pass object
demo.UpdateObject("issuer_id", "object_suffix");
// Create an issuer account
demo.CreateIssuerAccount("issuer_name", "issuer_email");
// Patch a pass object
demo.PatchObject("issuer_id", "object_suffix");
// Add a message to a pass object
demo.AddObjectMessage("issuer_id", "object_suffix", "header", "body");
// Expire a pass object
demo.ExpireObject("issuer_id", "object_suffix");
// Generate an Add to Google Wallet link that creates a new pass class and object
demo.CreateJWTNewObjects("issuer_id", "class_suffix", "object_suffix");
// Generate an Add to Google Wallet link that references existing pass object(s)
demo.CreateJWTExistingObjects("issuer_id");
// Create pass objects in batch
demo.BatchCreateEventTicketObjects("issuer_id", "class_suffix");
demo.BatchCreateObjects("issuer_id", "class_suffix");
```

View File

@@ -1,461 +0,0 @@
# [START class]
POST /walletobjects/v1/eventTicketClass HTTP/1.1
Host: walletobjects.googleapis.com
Content-Type: application/json
Authorization: Bearer ACCESS_TOKEN;
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
{
"id": "ISSUER_ID.CLASS_SUFFIX",
"issuerName": "Issuer name",
"reviewStatus": "UNDER_REVIEW",
"eventName": {
"defaultValue": {
"language": "en-US",
"value": "Event name"
}
}
}
# [END class]
# [START object]
POST /walletobjects/v1/eventTicketObject HTTP/1.1
Host: walletobjects.googleapis.com
Content-Type: application/json
Authorization: Bearer ACCESS_TOKEN;
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
{
"id": "ISSUER_ID.OBJECT_ID",
"classId": "ISSUER_ID.CLASS_SUFFIX",
"state": "ACTIVE",
"heroImage": {
"sourceUri": {
"uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Hero image description"
}
}
},
"textModulesData": [
{
"header": "Text module header",
"body": "Text module body",
"id": "TEXT_MODULE_ID"
}
],
"linksModuleData": {
"uris": [
{
"uri": "http://maps.google.com/",
"description": "Link module URI description",
"id": "LINK_MODULE_URI_ID"
},
{
"uri": "tel:6505555555",
"description": "Link module tel description",
"id": "LINK_MODULE_TEL_ID"
}
]
},
"imageModulesData": [
{
"mainImage": {
"sourceUri": {
"uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Image module description"
}
}
},
"id": "IMAGE_MODULE_ID"
}
],
"barcode": {
"type": "QR_CODE",
"value": "QR code"
},
"locations": [
{
"latitude": 37.424015499999996,
"longitude": -122.09259560000001
}
],
"seatInfo": {
"seat": {
"defaultValue": {
"language": "en-US",
"value": "42"
}
},
"row": {
"defaultValue": {
"language": "en-US",
"value": "G3"
}
},
"section": {
"defaultValue": {
"language": "en-US",
"value": "5"
}
},
"gate": {
"defaultValue": {
"language": "en-US",
"value": "A"
}
}
},
"ticketHolderName": "Ticket holder name",
"ticketNumber": "Ticket number"
}
# [END object]
# [START createIssuer]
POST /walletobjects/v1/issuer HTTP/1.1
Host: walletobjects.googleapis.com
Content-Type: application/json
Authorization: Bearer ACCESS_TOKEN;
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
{
"name": "ISSUER_NAME",
"contactInfo": {
"email": "ISSUER_EMAIL"
}
}
# [END createIssuer]
# [START updatePermissions]
PUT /walletobjects/v1/permissions/ISSUER_ID HTTP/1.1
Host: walletobjects.googleapis.com
Content-Type: application/json
Authorization: Bearer ACCESS_TOKEN;
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
{
"issuerId": "ISSUER_ID",
"permissions": [
{
emailAddress = "EMAIL_ADDRESS",
role = "READER | WRITER | OWNER"
}
]
}
# [END updatePermissions]
# [START batch]
POST /batch HTTP/1.1
Host: walletobjects.googleapis.com
Content-Type: multipart/mixed; boundary=batch_createobjectbatch
Authorization: Bearer ACCESS_TOKEN
Content-Length: TOTAL_CONTENT_LENGTH
--batch_createobjectbatch
Content-Type: application/json
POST /walletobjects/v1/eventTicketObject/
{
"id": "ISSUER_ID.OBJECT_ID",
"classId": "ISSUER_ID.CLASS_SUFFIX",
"state": "ACTIVE",
"heroImage": {
"sourceUri": {
"uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Hero image description"
}
}
},
"textModulesData": [
{
"header": "Text module header",
"body": "Text module body",
"id": "TEXT_MODULE_ID"
}
],
"linksModuleData": {
"uris": [
{
"uri": "http://maps.google.com/",
"description": "Link module URI description",
"id": "LINK_MODULE_URI_ID"
},
{
"uri": "tel:6505555555",
"description": "Link module tel description",
"id": "LINK_MODULE_TEL_ID"
}
]
},
"imageModulesData": [
{
"mainImage": {
"sourceUri": {
"uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Image module description"
}
}
},
"id": "IMAGE_MODULE_ID"
}
],
"barcode": {
"type": "QR_CODE",
"value": "QR code"
},
"locations": [
{
"latitude": 37.424015499999996,
"longitude": -122.09259560000001
}
],
"seatInfo": {
"seat": {
"defaultValue": {
"language": "en-US",
"value": "42"
}
},
"row": {
"defaultValue": {
"language": "en-US",
"value": "G3"
}
},
"section": {
"defaultValue": {
"language": "en-US",
"value": "5"
}
},
"gate": {
"defaultValue": {
"language": "en-US",
"value": "A"
}
}
},
"ticketHolderName": "Ticket holder name",
"ticketNumber": "Ticket number"
}
--batch_createobjectbatch
Content-Type: application/json
POST /walletobjects/v1/eventTicketObject/
{
"id": "ISSUER_ID.OBJECT_ID",
"classId": "ISSUER_ID.CLASS_SUFFIX",
"state": "ACTIVE",
"heroImage": {
"sourceUri": {
"uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Hero image description"
}
}
},
"textModulesData": [
{
"header": "Text module header",
"body": "Text module body",
"id": "TEXT_MODULE_ID"
}
],
"linksModuleData": {
"uris": [
{
"uri": "http://maps.google.com/",
"description": "Link module URI description",
"id": "LINK_MODULE_URI_ID"
},
{
"uri": "tel:6505555555",
"description": "Link module tel description",
"id": "LINK_MODULE_TEL_ID"
}
]
},
"imageModulesData": [
{
"mainImage": {
"sourceUri": {
"uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Image module description"
}
}
},
"id": "IMAGE_MODULE_ID"
}
],
"barcode": {
"type": "QR_CODE",
"value": "QR code"
},
"locations": [
{
"latitude": 37.424015499999996,
"longitude": -122.09259560000001
}
],
"seatInfo": {
"seat": {
"defaultValue": {
"language": "en-US",
"value": "42"
}
},
"row": {
"defaultValue": {
"language": "en-US",
"value": "G3"
}
},
"section": {
"defaultValue": {
"language": "en-US",
"value": "5"
}
},
"gate": {
"defaultValue": {
"language": "en-US",
"value": "A"
}
}
},
"ticketHolderName": "Ticket holder name",
"ticketNumber": "Ticket number"
}
--batch_createobjectbatch
Content-Type: application/json
POST /walletobjects/v1/eventTicketObject/
{
"id": "ISSUER_ID.OBJECT_ID",
"classId": "ISSUER_ID.CLASS_SUFFIX",
"state": "ACTIVE",
"heroImage": {
"sourceUri": {
"uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Hero image description"
}
}
},
"textModulesData": [
{
"header": "Text module header",
"body": "Text module body",
"id": "TEXT_MODULE_ID"
}
],
"linksModuleData": {
"uris": [
{
"uri": "http://maps.google.com/",
"description": "Link module URI description",
"id": "LINK_MODULE_URI_ID"
},
{
"uri": "tel:6505555555",
"description": "Link module tel description",
"id": "LINK_MODULE_TEL_ID"
}
]
},
"imageModulesData": [
{
"mainImage": {
"sourceUri": {
"uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Image module description"
}
}
},
"id": "IMAGE_MODULE_ID"
}
],
"barcode": {
"type": "QR_CODE",
"value": "QR code"
},
"locations": [
{
"latitude": 37.424015499999996,
"longitude": -122.09259560000001
}
],
"seatInfo": {
"seat": {
"defaultValue": {
"language": "en-US",
"value": "42"
}
},
"row": {
"defaultValue": {
"language": "en-US",
"value": "G3"
}
},
"section": {
"defaultValue": {
"language": "en-US",
"value": "5"
}
},
"gate": {
"defaultValue": {
"language": "en-US",
"value": "A"
}
}
},
"ticketHolderName": "Ticket holder name",
"ticketNumber": "Ticket number"
}
--batch_createobjectbatch--
# [END batch]

View File

@@ -1,392 +0,0 @@
# [START class]
POST /walletobjects/v1/flightClass HTTP/1.1
Host: walletobjects.googleapis.com
Content-Type: application/json
Authorization: Bearer ACCESS_TOKEN;
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
{
"id": "ISSUER_ID.CLASS_SUFFIX",
"issuerName": "Issuer name",
"reviewStatus": "UNDER_REVIEW",
"localScheduledDepartureDateTime": "2023-07-02T15:30:00",
"flightHeader": {
"carrier": {
"carrierIataCode": "LX"
},
"flightNumber": "123"
},
"origin": {
"airportIataCode": "LAX",
"terminal": "1",
"gate": "A2"
},
"destination": {
"airportIataCode": "SFO",
"terminal": "2",
"gate": "C3"
}
}
# [END class]
# [START object]
POST /walletobjects/v1/flightObject HTTP/1.1
Host: walletobjects.googleapis.com
Content-Type: application/json
Authorization: Bearer ACCESS_TOKEN;
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
{
"id": "ISSUER_ID.OBJECT_ID",
"classId": "ISSUER_ID.CLASS_SUFFIX",
"state": "ACTIVE",
"heroImage": {
"sourceUri": {
"uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Hero image description"
}
}
},
"textModulesData": [
{
"header": "Text module header",
"body": "Text module body",
"id": "TEXT_MODULE_ID"
}
],
"linksModuleData": {
"uris": [
{
"uri": "http://maps.google.com/",
"description": "Link module URI description",
"id": "LINK_MODULE_URI_ID"
},
{
"uri": "tel:6505555555",
"description": "Link module tel description",
"id": "LINK_MODULE_TEL_ID"
}
]
},
"imageModulesData": [
{
"mainImage": {
"sourceUri": {
"uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Image module description"
}
}
},
"id": "IMAGE_MODULE_ID"
}
],
"barcode": {
"type": "QR_CODE",
"value": "QR code"
},
"locations": [
{
"latitude": 37.424015499999996,
"longitude": -122.09259560000001
}
],
"passengerName": "Passenger name",
"boardingAndSeatingInfo": {
"boardingGroup": "B",
"seatNumber": "42"
},
"reservationInfo": {
"confirmationCode": "Confirmation code"
}
}
# [END object]
# [START createIssuer]
POST /walletobjects/v1/issuer HTTP/1.1
Host: walletobjects.googleapis.com
Content-Type: application/json
Authorization: Bearer ACCESS_TOKEN;
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
{
"name": "ISSUER_NAME",
"contactInfo": {
"email": "ISSUER_EMAIL"
}
}
# [END createIssuer]
# [START updatePermissions]
PUT /walletobjects/v1/permissions/ISSUER_ID HTTP/1.1
Host: walletobjects.googleapis.com
Content-Type: application/json
Authorization: Bearer ACCESS_TOKEN;
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
{
"issuerId": "ISSUER_ID",
"permissions": [
{
emailAddress = "EMAIL_ADDRESS",
role = "READER | WRITER | OWNER"
}
]
}
# [END updatePermissions]
# [START batch]
POST /batch HTTP/1.1
Host: walletobjects.googleapis.com
Content-Type: multipart/mixed; boundary=batch_createobjectbatch
Authorization: Bearer ACCESS_TOKEN
Content-Length: TOTAL_CONTENT_LENGTH
--batch_createobjectbatch
Content-Type: application/json
POST /walletobjects/v1/flightObject/
{
"id": "ISSUER_ID.OBJECT_ID",
"classId": "ISSUER_ID.CLASS_SUFFIX",
"state": "ACTIVE",
"heroImage": {
"sourceUri": {
"uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Hero image description"
}
}
},
"textModulesData": [
{
"header": "Text module header",
"body": "Text module body",
"id": "TEXT_MODULE_ID"
}
],
"linksModuleData": {
"uris": [
{
"uri": "http://maps.google.com/",
"description": "Link module URI description",
"id": "LINK_MODULE_URI_ID"
},
{
"uri": "tel:6505555555",
"description": "Link module tel description",
"id": "LINK_MODULE_TEL_ID"
}
]
},
"imageModulesData": [
{
"mainImage": {
"sourceUri": {
"uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Image module description"
}
}
},
"id": "IMAGE_MODULE_ID"
}
],
"barcode": {
"type": "QR_CODE",
"value": "QR code"
},
"locations": [
{
"latitude": 37.424015499999996,
"longitude": -122.09259560000001
}
],
"passengerName": "Passenger name",
"boardingAndSeatingInfo": {
"boardingGroup": "B",
"seatNumber": "42"
},
"reservationInfo": {
"confirmationCode": "Confirmation code"
}
}
--batch_createobjectbatch
Content-Type: application/json
POST /walletobjects/v1/flightObject/
{
"id": "ISSUER_ID.OBJECT_ID",
"classId": "ISSUER_ID.CLASS_SUFFIX",
"state": "ACTIVE",
"heroImage": {
"sourceUri": {
"uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Hero image description"
}
}
},
"textModulesData": [
{
"header": "Text module header",
"body": "Text module body",
"id": "TEXT_MODULE_ID"
}
],
"linksModuleData": {
"uris": [
{
"uri": "http://maps.google.com/",
"description": "Link module URI description",
"id": "LINK_MODULE_URI_ID"
},
{
"uri": "tel:6505555555",
"description": "Link module tel description",
"id": "LINK_MODULE_TEL_ID"
}
]
},
"imageModulesData": [
{
"mainImage": {
"sourceUri": {
"uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Image module description"
}
}
},
"id": "IMAGE_MODULE_ID"
}
],
"barcode": {
"type": "QR_CODE",
"value": "QR code"
},
"locations": [
{
"latitude": 37.424015499999996,
"longitude": -122.09259560000001
}
],
"passengerName": "Passenger name",
"boardingAndSeatingInfo": {
"boardingGroup": "B",
"seatNumber": "42"
},
"reservationInfo": {
"confirmationCode": "Confirmation code"
}
}
--batch_createobjectbatch
Content-Type: application/json
POST /walletobjects/v1/flightObject/
{
"id": "ISSUER_ID.OBJECT_ID",
"classId": "ISSUER_ID.CLASS_SUFFIX",
"state": "ACTIVE",
"heroImage": {
"sourceUri": {
"uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Hero image description"
}
}
},
"textModulesData": [
{
"header": "Text module header",
"body": "Text module body",
"id": "TEXT_MODULE_ID"
}
],
"linksModuleData": {
"uris": [
{
"uri": "http://maps.google.com/",
"description": "Link module URI description",
"id": "LINK_MODULE_URI_ID"
},
{
"uri": "tel:6505555555",
"description": "Link module tel description",
"id": "LINK_MODULE_TEL_ID"
}
]
},
"imageModulesData": [
{
"mainImage": {
"sourceUri": {
"uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Image module description"
}
}
},
"id": "IMAGE_MODULE_ID"
}
],
"barcode": {
"type": "QR_CODE",
"value": "QR code"
},
"locations": [
{
"latitude": 37.424015499999996,
"longitude": -122.09259560000001
}
],
"passengerName": "Passenger name",
"boardingAndSeatingInfo": {
"boardingGroup": "B",
"seatNumber": "42"
},
"reservationInfo": {
"confirmationCode": "Confirmation code"
}
}
--batch_createobjectbatch--
# [END batch]

View File

@@ -1,413 +0,0 @@
# [START class]
POST /walletobjects/v1/genericClass HTTP/1.1
Host: walletobjects.googleapis.com
Content-Type: application/json
Authorization: Bearer ACCESS_TOKEN;
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
{
"id": "ISSUER_ID.CLASS_SUFFIX"
}
# [END class]
# [START object]
POST /walletobjects/v1/genericObject HTTP/1.1
Host: walletobjects.googleapis.com
Content-Type: application/json
Authorization: Bearer ACCESS_TOKEN;
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
{
"id": "ISSUER_ID.OBJECT_ID",
"classId": "ISSUER_ID.CLASS_SUFFIX",
"state": "ACTIVE",
"heroImage": {
"sourceUri": {
"uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Hero image description"
}
}
},
"textModulesData": [
{
"header": "Text module header",
"body": "Text module body",
"id": "TEXT_MODULE_ID"
}
],
"linksModuleData": {
"uris": [
{
"uri": "http://maps.google.com/",
"description": "Link module URI description",
"id": "LINK_MODULE_URI_ID"
},
{
"uri": "tel:6505555555",
"description": "Link module tel description",
"id": "LINK_MODULE_TEL_ID"
}
]
},
"imageModulesData": [
{
"mainImage": {
"sourceUri": {
"uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Image module description"
}
}
},
"id": "IMAGE_MODULE_ID"
}
],
"barcode": {
"type": "QR_CODE",
"value": "QR code"
},
"cardTitle": {
"defaultValue": {
"language": "en-US",
"value": "Generic card title"
}
},
"header": {
"defaultValue": {
"language": "en-US",
"value": "Generic header"
}
},
"hexBackgroundColor": "#4285f4",
"logo": {
"sourceUri": {
"uri": "https://storage.googleapis.com/wallet-lab-tools-codelab-artifacts-public/pass_google_logo.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Generic card logo"
}
}
}
}
# [END object]
# [START createIssuer]
POST /walletobjects/v1/issuer HTTP/1.1
Host: walletobjects.googleapis.com
Content-Type: application/json
Authorization: Bearer ACCESS_TOKEN;
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
{
"name": "ISSUER_NAME",
"contactInfo": {
"email": "ISSUER_EMAIL"
}
}
# [END createIssuer]
# [START updatePermissions]
PUT /walletobjects/v1/permissions/ISSUER_ID HTTP/1.1
Host: walletobjects.googleapis.com
Content-Type: application/json
Authorization: Bearer ACCESS_TOKEN;
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
{
"issuerId": "ISSUER_ID",
"permissions": [
{
emailAddress = "EMAIL_ADDRESS",
role = "READER | WRITER | OWNER"
}
]
}
# [END updatePermissions]
# [START batch]
POST /batch HTTP/1.1
Host: walletobjects.googleapis.com
Content-Type: multipart/mixed; boundary=batch_createobjectbatch
Authorization: Bearer ACCESS_TOKEN
Content-Length: TOTAL_CONTENT_LENGTH
--batch_createobjectbatch
Content-Type: application/json
POST /walletobjects/v1/genericObject/
{
"id": "ISSUER_ID.OBJECT_ID",
"classId": "ISSUER_ID.CLASS_SUFFIX",
"state": "ACTIVE",
"heroImage": {
"sourceUri": {
"uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Hero image description"
}
}
},
"textModulesData": [
{
"header": "Text module header",
"body": "Text module body",
"id": "TEXT_MODULE_ID"
}
],
"linksModuleData": {
"uris": [
{
"uri": "http://maps.google.com/",
"description": "Link module URI description",
"id": "LINK_MODULE_URI_ID"
},
{
"uri": "tel:6505555555",
"description": "Link module tel description",
"id": "LINK_MODULE_TEL_ID"
}
]
},
"imageModulesData": [
{
"mainImage": {
"sourceUri": {
"uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Image module description"
}
}
},
"id": "IMAGE_MODULE_ID"
}
],
"barcode": {
"type": "QR_CODE",
"value": "QR code"
},
"cardTitle": {
"defaultValue": {
"language": "en-US",
"value": "Generic card title"
}
},
"header": {
"defaultValue": {
"language": "en-US",
"value": "Generic header"
}
},
"hexBackgroundColor": "#4285f4",
"logo": {
"sourceUri": {
"uri": "https://storage.googleapis.com/wallet-lab-tools-codelab-artifacts-public/pass_google_logo.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Generic card logo"
}
}
}
}
--batch_createobjectbatch
Content-Type: application/json
POST /walletobjects/v1/genericObject/
{
"id": "ISSUER_ID.OBJECT_ID",
"classId": "ISSUER_ID.CLASS_SUFFIX",
"state": "ACTIVE",
"heroImage": {
"sourceUri": {
"uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Hero image description"
}
}
},
"textModulesData": [
{
"header": "Text module header",
"body": "Text module body",
"id": "TEXT_MODULE_ID"
}
],
"linksModuleData": {
"uris": [
{
"uri": "http://maps.google.com/",
"description": "Link module URI description",
"id": "LINK_MODULE_URI_ID"
},
{
"uri": "tel:6505555555",
"description": "Link module tel description",
"id": "LINK_MODULE_TEL_ID"
}
]
},
"imageModulesData": [
{
"mainImage": {
"sourceUri": {
"uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Image module description"
}
}
},
"id": "IMAGE_MODULE_ID"
}
],
"barcode": {
"type": "QR_CODE",
"value": "QR code"
},
"cardTitle": {
"defaultValue": {
"language": "en-US",
"value": "Generic card title"
}
},
"header": {
"defaultValue": {
"language": "en-US",
"value": "Generic header"
}
},
"hexBackgroundColor": "#4285f4",
"logo": {
"sourceUri": {
"uri": "https://storage.googleapis.com/wallet-lab-tools-codelab-artifacts-public/pass_google_logo.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Generic card logo"
}
}
}
}
--batch_createobjectbatch
Content-Type: application/json
POST /walletobjects/v1/genericObject/
{
"id": "ISSUER_ID.OBJECT_ID",
"classId": "ISSUER_ID.CLASS_SUFFIX",
"state": "ACTIVE",
"heroImage": {
"sourceUri": {
"uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Hero image description"
}
}
},
"textModulesData": [
{
"header": "Text module header",
"body": "Text module body",
"id": "TEXT_MODULE_ID"
}
],
"linksModuleData": {
"uris": [
{
"uri": "http://maps.google.com/",
"description": "Link module URI description",
"id": "LINK_MODULE_URI_ID"
},
{
"uri": "tel:6505555555",
"description": "Link module tel description",
"id": "LINK_MODULE_TEL_ID"
}
]
},
"imageModulesData": [
{
"mainImage": {
"sourceUri": {
"uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Image module description"
}
}
},
"id": "IMAGE_MODULE_ID"
}
],
"barcode": {
"type": "QR_CODE",
"value": "QR code"
},
"cardTitle": {
"defaultValue": {
"language": "en-US",
"value": "Generic card title"
}
},
"header": {
"defaultValue": {
"language": "en-US",
"value": "Generic header"
}
},
"hexBackgroundColor": "#4285f4",
"logo": {
"sourceUri": {
"uri": "https://storage.googleapis.com/wallet-lab-tools-codelab-artifacts-public/pass_google_logo.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Generic card logo"
}
}
}
}
--batch_createobjectbatch--
# [END batch]

View File

@@ -1,379 +0,0 @@
# [START class]
POST /walletobjects/v1/giftCardClass HTTP/1.1
Host: walletobjects.googleapis.com
Content-Type: application/json
Authorization: Bearer ACCESS_TOKEN;
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
{
"id": "ISSUER_ID.CLASS_SUFFIX",
"issuerName": "Issuer name",
"reviewStatus": "UNDER_REVIEW"
}
# [END class]
# [START object]
POST /walletobjects/v1/giftCardObject HTTP/1.1
Host: walletobjects.googleapis.com
Content-Type: application/json
Authorization: Bearer ACCESS_TOKEN;
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
{
"id": "ISSUER_ID.OBJECT_ID",
"classId": "ISSUER_ID.CLASS_SUFFIX",
"state": "ACTIVE",
"heroImage": {
"sourceUri": {
"uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Hero image description"
}
}
},
"textModulesData": [
{
"header": "Text module header",
"body": "Text module body",
"id": "TEXT_MODULE_ID"
}
],
"linksModuleData": {
"uris": [
{
"uri": "http://maps.google.com/",
"description": "Link module URI description",
"id": "LINK_MODULE_URI_ID"
},
{
"uri": "tel:6505555555",
"description": "Link module tel description",
"id": "LINK_MODULE_TEL_ID"
}
]
},
"imageModulesData": [
{
"mainImage": {
"sourceUri": {
"uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Image module description"
}
}
},
"id": "IMAGE_MODULE_ID"
}
],
"locations": [
{
"latitude": 37.424015499999996,
"longitude": -122.09259560000001
}
],
"barcode": {
"type": "QR_CODE",
"value": "QR code"
},
"cardNumber": "Card number",
"pin": "1234",
"balance": {
"micros": 20000000,
"currencyCode": "USD"
},
"balanceUpdateTime": {
"date": "2020-04-12T16:20:50.52-04:00"
}
}
# [END object]
# [START createIssuer]
POST /walletobjects/v1/issuer HTTP/1.1
Host: walletobjects.googleapis.com
Content-Type: application/json
Authorization: Bearer ACCESS_TOKEN;
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
{
"name": "ISSUER_NAME",
"contactInfo": {
"email": "ISSUER_EMAIL"
}
}
# [END createIssuer]
# [START updatePermissions]
PUT /walletobjects/v1/permissions/ISSUER_ID HTTP/1.1
Host: walletobjects.googleapis.com
Content-Type: application/json
Authorization: Bearer ACCESS_TOKEN;
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
{
"issuerId": "ISSUER_ID",
"permissions": [
{
emailAddress = "EMAIL_ADDRESS",
role = "READER | WRITER | OWNER"
}
]
}
# [END updatePermissions]
# [START batch]
POST /batch HTTP/1.1
Host: walletobjects.googleapis.com
Content-Type: multipart/mixed; boundary=batch_createobjectbatch
Authorization: Bearer ACCESS_TOKEN
Content-Length: TOTAL_CONTENT_LENGTH
--batch_createobjectbatch
Content-Type: application/json
POST /walletobjects/v1/giftCardObject/
{
"id": "ISSUER_ID.OBJECT_ID",
"classId": "ISSUER_ID.CLASS_SUFFIX",
"state": "ACTIVE",
"heroImage": {
"sourceUri": {
"uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Hero image description"
}
}
},
"textModulesData": [
{
"header": "Text module header",
"body": "Text module body",
"id": "TEXT_MODULE_ID"
}
],
"linksModuleData": {
"uris": [
{
"uri": "http://maps.google.com/",
"description": "Link module URI description",
"id": "LINK_MODULE_URI_ID"
},
{
"uri": "tel:6505555555",
"description": "Link module tel description",
"id": "LINK_MODULE_TEL_ID"
}
]
},
"imageModulesData": [
{
"mainImage": {
"sourceUri": {
"uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Image module description"
}
}
},
"id": "IMAGE_MODULE_ID"
}
],
"locations": [
{
"latitude": 37.424015499999996,
"longitude": -122.09259560000001
}
],
"barcode": {
"type": "QR_CODE",
"value": "QR code"
},
"cardNumber": "Card number",
"pin": "1234",
"balance": {
"micros": 20000000,
"currencyCode": "USD"
},
"balanceUpdateTime": {
"date": "2020-04-12T16:20:50.52-04:00"
}
}
--batch_createobjectbatch
Content-Type: application/json
POST /walletobjects/v1/giftCardObject/
{
"id": "ISSUER_ID.OBJECT_ID",
"classId": "ISSUER_ID.CLASS_SUFFIX",
"state": "ACTIVE",
"heroImage": {
"sourceUri": {
"uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Hero image description"
}
}
},
"textModulesData": [
{
"header": "Text module header",
"body": "Text module body",
"id": "TEXT_MODULE_ID"
}
],
"linksModuleData": {
"uris": [
{
"uri": "http://maps.google.com/",
"description": "Link module URI description",
"id": "LINK_MODULE_URI_ID"
},
{
"uri": "tel:6505555555",
"description": "Link module tel description",
"id": "LINK_MODULE_TEL_ID"
}
]
},
"imageModulesData": [
{
"mainImage": {
"sourceUri": {
"uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Image module description"
}
}
},
"id": "IMAGE_MODULE_ID"
}
],
"locations": [
{
"latitude": 37.424015499999996,
"longitude": -122.09259560000001
}
],
"barcode": {
"type": "QR_CODE",
"value": "QR code"
},
"cardNumber": "Card number",
"pin": "1234",
"balance": {
"micros": 20000000,
"currencyCode": "USD"
},
"balanceUpdateTime": {
"date": "2020-04-12T16:20:50.52-04:00"
}
}
--batch_createobjectbatch
Content-Type: application/json
POST /walletobjects/v1/giftCardObject/
{
"id": "ISSUER_ID.OBJECT_ID",
"classId": "ISSUER_ID.CLASS_SUFFIX",
"state": "ACTIVE",
"heroImage": {
"sourceUri": {
"uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Hero image description"
}
}
},
"textModulesData": [
{
"header": "Text module header",
"body": "Text module body",
"id": "TEXT_MODULE_ID"
}
],
"linksModuleData": {
"uris": [
{
"uri": "http://maps.google.com/",
"description": "Link module URI description",
"id": "LINK_MODULE_URI_ID"
},
{
"uri": "tel:6505555555",
"description": "Link module tel description",
"id": "LINK_MODULE_TEL_ID"
}
]
},
"imageModulesData": [
{
"mainImage": {
"sourceUri": {
"uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Image module description"
}
}
},
"id": "IMAGE_MODULE_ID"
}
],
"locations": [
{
"latitude": 37.424015499999996,
"longitude": -122.09259560000001
}
],
"barcode": {
"type": "QR_CODE",
"value": "QR code"
},
"cardNumber": "Card number",
"pin": "1234",
"balance": {
"micros": 20000000,
"currencyCode": "USD"
},
"balanceUpdateTime": {
"date": "2020-04-12T16:20:50.52-04:00"
}
}
--batch_createobjectbatch--
# [END batch]

View File

@@ -1,387 +0,0 @@
# [START class]
POST /walletobjects/v1/loyaltyClass HTTP/1.1
Host: walletobjects.googleapis.com
Content-Type: application/json
Authorization: Bearer ACCESS_TOKEN;
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
{
"id": "ISSUER_ID.CLASS_SUFFIX",
"issuerName": "Issuer name",
"reviewStatus": "UNDER_REVIEW",
"programName": "Program name",
"programLogo": {
"sourceUri": {
"uri": "http://farm8.staticflickr.com/7340/11177041185_a61a7f2139_o.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Logo description"
}
}
}
}
# [END class]
# [START object]
POST /walletobjects/v1/loyaltyObject HTTP/1.1
Host: walletobjects.googleapis.com
Content-Type: application/json
Authorization: Bearer ACCESS_TOKEN;
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
{
"id": "ISSUER_ID.OBJECT_ID",
"classId": "ISSUER_ID.CLASS_SUFFIX",
"state": "ACTIVE",
"heroImage": {
"sourceUri": {
"uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Hero image description"
}
}
},
"textModulesData": [
{
"header": "Text module header",
"body": "Text module body",
"id": "TEXT_MODULE_ID"
}
],
"linksModuleData": {
"uris": [
{
"uri": "http://maps.google.com/",
"description": "Link module URI description",
"id": "LINK_MODULE_URI_ID"
},
{
"uri": "tel:6505555555",
"description": "Link module tel description",
"id": "LINK_MODULE_TEL_ID"
}
]
},
"imageModulesData": [
{
"mainImage": {
"sourceUri": {
"uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Image module description"
}
}
},
"id": "IMAGE_MODULE_ID"
}
],
"barcode": {
"type": "QR_CODE",
"value": "QR code"
},
"locations": [
{
"latitude": 37.424015499999996,
"longitude": -122.09259560000001
}
],
"accountId": "Account id",
"accountName": "Account name",
"loyaltyPoints": {
"label": "Points",
"balance": {
"int": 800
}
}
}
# [END object]
# [START createIssuer]
POST /walletobjects/v1/issuer HTTP/1.1
Host: walletobjects.googleapis.com
Content-Type: application/json
Authorization: Bearer ACCESS_TOKEN;
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
{
"name": "ISSUER_NAME",
"contactInfo": {
"email": "ISSUER_EMAIL"
}
}
# [END createIssuer]
# [START updatePermissions]
PUT /walletobjects/v1/permissions/ISSUER_ID HTTP/1.1
Host: walletobjects.googleapis.com
Content-Type: application/json
Authorization: Bearer ACCESS_TOKEN;
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
{
"issuerId": "ISSUER_ID",
"permissions": [
{
emailAddress = "EMAIL_ADDRESS",
role = "READER | WRITER | OWNER"
}
]
}
# [END updatePermissions]
# [START batch]
POST /batch HTTP/1.1
Host: walletobjects.googleapis.com
Content-Type: multipart/mixed; boundary=batch_createobjectbatch
Authorization: Bearer ACCESS_TOKEN
Content-Length: TOTAL_CONTENT_LENGTH
--batch_createobjectbatch
Content-Type: application/json
POST /walletobjects/v1/loyaltyObject/
{
"id": "ISSUER_ID.OBJECT_ID",
"classId": "ISSUER_ID.CLASS_SUFFIX",
"state": "ACTIVE",
"heroImage": {
"sourceUri": {
"uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Hero image description"
}
}
},
"textModulesData": [
{
"header": "Text module header",
"body": "Text module body",
"id": "TEXT_MODULE_ID"
}
],
"linksModuleData": {
"uris": [
{
"uri": "http://maps.google.com/",
"description": "Link module URI description",
"id": "LINK_MODULE_URI_ID"
},
{
"uri": "tel:6505555555",
"description": "Link module tel description",
"id": "LINK_MODULE_TEL_ID"
}
]
},
"imageModulesData": [
{
"mainImage": {
"sourceUri": {
"uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Image module description"
}
}
},
"id": "IMAGE_MODULE_ID"
}
],
"barcode": {
"type": "QR_CODE",
"value": "QR code"
},
"locations": [
{
"latitude": 37.424015499999996,
"longitude": -122.09259560000001
}
],
"accountId": "Account id",
"accountName": "Account name",
"loyaltyPoints": {
"label": "Points",
"balance": {
"int": 800
}
}
}
--batch_createobjectbatch
Content-Type: application/json
POST /walletobjects/v1/loyaltyObject/
{
"id": "ISSUER_ID.OBJECT_ID",
"classId": "ISSUER_ID.CLASS_SUFFIX",
"state": "ACTIVE",
"heroImage": {
"sourceUri": {
"uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Hero image description"
}
}
},
"textModulesData": [
{
"header": "Text module header",
"body": "Text module body",
"id": "TEXT_MODULE_ID"
}
],
"linksModuleData": {
"uris": [
{
"uri": "http://maps.google.com/",
"description": "Link module URI description",
"id": "LINK_MODULE_URI_ID"
},
{
"uri": "tel:6505555555",
"description": "Link module tel description",
"id": "LINK_MODULE_TEL_ID"
}
]
},
"imageModulesData": [
{
"mainImage": {
"sourceUri": {
"uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Image module description"
}
}
},
"id": "IMAGE_MODULE_ID"
}
],
"barcode": {
"type": "QR_CODE",
"value": "QR code"
},
"locations": [
{
"latitude": 37.424015499999996,
"longitude": -122.09259560000001
}
],
"accountId": "Account id",
"accountName": "Account name",
"loyaltyPoints": {
"label": "Points",
"balance": {
"int": 800
}
}
}
--batch_createobjectbatch
Content-Type: application/json
POST /walletobjects/v1/loyaltyObject/
{
"id": "ISSUER_ID.OBJECT_ID",
"classId": "ISSUER_ID.CLASS_SUFFIX",
"state": "ACTIVE",
"heroImage": {
"sourceUri": {
"uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Hero image description"
}
}
},
"textModulesData": [
{
"header": "Text module header",
"body": "Text module body",
"id": "TEXT_MODULE_ID"
}
],
"linksModuleData": {
"uris": [
{
"uri": "http://maps.google.com/",
"description": "Link module URI description",
"id": "LINK_MODULE_URI_ID"
},
{
"uri": "tel:6505555555",
"description": "Link module tel description",
"id": "LINK_MODULE_TEL_ID"
}
]
},
"imageModulesData": [
{
"mainImage": {
"sourceUri": {
"uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Image module description"
}
}
},
"id": "IMAGE_MODULE_ID"
}
],
"barcode": {
"type": "QR_CODE",
"value": "QR code"
},
"locations": [
{
"latitude": 37.424015499999996,
"longitude": -122.09259560000001
}
],
"accountId": "Account id",
"accountName": "Account name",
"loyaltyPoints": {
"label": "Points",
"balance": {
"int": 800
}
}
}
--batch_createobjectbatch--
# [END batch]

View File

@@ -1,378 +0,0 @@
# [START class]
POST /walletobjects/v1/offerClass HTTP/1.1
Host: walletobjects.googleapis.com
Content-Type: application/json
Authorization: Bearer ACCESS_TOKEN;
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
{
"id": "ISSUER_ID.CLASS_SUFFIX",
"issuerName": "Issuer name",
"reviewStatus": "UNDER_REVIEW",
"provider": "Provider name",
"title": "Offer title",
"redemptionChannel": "ONLINE"
}
# [END class]
# [START object]
POST /walletobjects/v1/offerObject HTTP/1.1
Host: walletobjects.googleapis.com
Content-Type: application/json
Authorization: Bearer ACCESS_TOKEN;
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
{
"id": "ISSUER_ID.OBJECT_ID",
"classId": "ISSUER_ID.CLASS_SUFFIX",
"state": "ACTIVE",
"heroImage": {
"sourceUri": {
"uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Hero image description"
}
}
},
"textModulesData": [
{
"header": "Text module header",
"body": "Text module body",
"id": "TEXT_MODULE_ID"
}
],
"linksModuleData": {
"uris": [
{
"uri": "http://maps.google.com/",
"description": "Link module URI description",
"id": "LINK_MODULE_URI_ID"
},
{
"uri": "tel:6505555555",
"description": "Link module tel description",
"id": "LINK_MODULE_TEL_ID"
}
]
},
"imageModulesData": [
{
"mainImage": {
"sourceUri": {
"uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Image module description"
}
}
},
"id": "IMAGE_MODULE_ID"
}
],
"barcode": {
"type": "QR_CODE",
"value": "QR code"
},
"locations": [
{
"latitude": 37.424015499999996,
"longitude": -122.09259560000001
}
],
"validTimeInterval": {
"start": {
"date": "2023-06-12T23:20:50.52Z"
},
"end": {
"date": "2023-12-12T23:20:50.52Z"
}
}
}
# [END object]
# [START createIssuer]
POST /walletobjects/v1/issuer HTTP/1.1
Host: walletobjects.googleapis.com
Content-Type: application/json
Authorization: Bearer ACCESS_TOKEN;
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
{
"name": "ISSUER_NAME",
"contactInfo": {
"email": "ISSUER_EMAIL"
}
}
# [END createIssuer]
# [START updatePermissions]
PUT /walletobjects/v1/permissions/ISSUER_ID HTTP/1.1
Host: walletobjects.googleapis.com
Content-Type: application/json
Authorization: Bearer ACCESS_TOKEN;
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
{
"issuerId": "ISSUER_ID",
"permissions": [
{
emailAddress = "EMAIL_ADDRESS",
role = "READER | WRITER | OWNER"
}
]
}
# [END updatePermissions]
# [START batch]
POST /batch HTTP/1.1
Host: walletobjects.googleapis.com
Content-Type: multipart/mixed; boundary=batch_createobjectbatch
Authorization: Bearer ACCESS_TOKEN
Content-Length: TOTAL_CONTENT_LENGTH
--batch_createobjectbatch
Content-Type: application/json
POST /walletobjects/v1/offerObject/
{
"id": "ISSUER_ID.OBJECT_ID",
"classId": "ISSUER_ID.CLASS_SUFFIX",
"state": "ACTIVE",
"heroImage": {
"sourceUri": {
"uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Hero image description"
}
}
},
"textModulesData": [
{
"header": "Text module header",
"body": "Text module body",
"id": "TEXT_MODULE_ID"
}
],
"linksModuleData": {
"uris": [
{
"uri": "http://maps.google.com/",
"description": "Link module URI description",
"id": "LINK_MODULE_URI_ID"
},
{
"uri": "tel:6505555555",
"description": "Link module tel description",
"id": "LINK_MODULE_TEL_ID"
}
]
},
"imageModulesData": [
{
"mainImage": {
"sourceUri": {
"uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Image module description"
}
}
},
"id": "IMAGE_MODULE_ID"
}
],
"barcode": {
"type": "QR_CODE",
"value": "QR code"
},
"locations": [
{
"latitude": 37.424015499999996,
"longitude": -122.09259560000001
}
],
"validTimeInterval": {
"start": {
"date": "2023-06-12T23:20:50.52Z"
},
"end": {
"date": "2023-12-12T23:20:50.52Z"
}
}
}
--batch_createobjectbatch
Content-Type: application/json
POST /walletobjects/v1/offerObject/
{
"id": "ISSUER_ID.OBJECT_ID",
"classId": "ISSUER_ID.CLASS_SUFFIX",
"state": "ACTIVE",
"heroImage": {
"sourceUri": {
"uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Hero image description"
}
}
},
"textModulesData": [
{
"header": "Text module header",
"body": "Text module body",
"id": "TEXT_MODULE_ID"
}
],
"linksModuleData": {
"uris": [
{
"uri": "http://maps.google.com/",
"description": "Link module URI description",
"id": "LINK_MODULE_URI_ID"
},
{
"uri": "tel:6505555555",
"description": "Link module tel description",
"id": "LINK_MODULE_TEL_ID"
}
]
},
"imageModulesData": [
{
"mainImage": {
"sourceUri": {
"uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Image module description"
}
}
},
"id": "IMAGE_MODULE_ID"
}
],
"barcode": {
"type": "QR_CODE",
"value": "QR code"
},
"locations": [
{
"latitude": 37.424015499999996,
"longitude": -122.09259560000001
}
],
"validTimeInterval": {
"start": {
"date": "2023-06-12T23:20:50.52Z"
},
"end": {
"date": "2023-12-12T23:20:50.52Z"
}
}
}
--batch_createobjectbatch
Content-Type: application/json
POST /walletobjects/v1/offerObject/
{
"id": "ISSUER_ID.OBJECT_ID",
"classId": "ISSUER_ID.CLASS_SUFFIX",
"state": "ACTIVE",
"heroImage": {
"sourceUri": {
"uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Hero image description"
}
}
},
"textModulesData": [
{
"header": "Text module header",
"body": "Text module body",
"id": "TEXT_MODULE_ID"
}
],
"linksModuleData": {
"uris": [
{
"uri": "http://maps.google.com/",
"description": "Link module URI description",
"id": "LINK_MODULE_URI_ID"
},
{
"uri": "tel:6505555555",
"description": "Link module tel description",
"id": "LINK_MODULE_TEL_ID"
}
]
},
"imageModulesData": [
{
"mainImage": {
"sourceUri": {
"uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Image module description"
}
}
},
"id": "IMAGE_MODULE_ID"
}
],
"barcode": {
"type": "QR_CODE",
"value": "QR code"
},
"locations": [
{
"latitude": 37.424015499999996,
"longitude": -122.09259560000001
}
],
"validTimeInterval": {
"start": {
"date": "2023-06-12T23:20:50.52Z"
},
"end": {
"date": "2023-12-12T23:20:50.52Z"
}
}
}
--batch_createobjectbatch--
# [END batch]

View File

@@ -1,463 +0,0 @@
# [START class]
POST /walletobjects/v1/transitClass HTTP/1.1
Host: walletobjects.googleapis.com
Content-Type: application/json
Authorization: Bearer ACCESS_TOKEN;
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
{
"id": "ISSUER_ID.CLASS_SUFFIX",
"issuerName": "Issuer name",
"reviewStatus": "UNDER_REVIEW",
"logo": {
"sourceUri": {
"uri": "https://live.staticflickr.com/65535/48690277162_cd05f03f4d_o.png"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Logo description"
}
}
},
"transitType": "BUS"
}
# [END class]
# [START object]
POST /walletobjects/v1/transitObject HTTP/1.1
Host: walletobjects.googleapis.com
Content-Type: application/json
Authorization: Bearer ACCESS_TOKEN;
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
{
"id": "ISSUER_ID.OBJECT_ID",
"classId": "ISSUER_ID.CLASS_SUFFIX",
"state": "ACTIVE",
"heroImage": {
"sourceUri": {
"uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Hero image description"
}
}
},
"textModulesData": [
{
"header": "Text module header",
"body": "Text module body",
"id": "TEXT_MODULE_ID"
}
],
"linksModuleData": {
"uris": [
{
"uri": "http://maps.google.com/",
"description": "Link module URI description",
"id": "LINK_MODULE_URI_ID"
},
{
"uri": "tel:6505555555",
"description": "Link module tel description",
"id": "LINK_MODULE_TEL_ID"
}
]
},
"imageModulesData": [
{
"mainImage": {
"sourceUri": {
"uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Image module description"
}
}
},
"id": "IMAGE_MODULE_ID"
}
],
"barcode": {
"type": "QR_CODE",
"value": "QR code"
},
"locations": [
{
"latitude": 37.424015499999996,
"longitude": -122.09259560000001
}
],
"passengerType": "SINGLE_PASSENGER",
"passengerNames": "Passenger names",
"tripType": "ONE_WAY",
"ticketLeg": {
"originStationCode": "LA",
"originName": {
"defaultValue": {
"language": "en-US",
"value": "Origin name"
}
},
"destinationStationCode": "SFO",
"destinationName": {
"defaultValue": {
"language": "en-US",
"value": "Destination name"
}
},
"departureDateTime": "2020-04-12T16:20:50.52Z",
"arrivalDateTime": "2020-04-12T20:20:50.52Z",
"fareName": {
"defaultValue": {
"language": "en-US",
"value": "Fare name"
}
}
}
}
# [END object]
# [START createIssuer]
POST /walletobjects/v1/issuer HTTP/1.1
Host: walletobjects.googleapis.com
Content-Type: application/json
Authorization: Bearer ACCESS_TOKEN;
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
{
"name": "ISSUER_NAME",
"contactInfo": {
"email": "ISSUER_EMAIL"
}
}
# [END createIssuer]
# [START updatePermissions]
PUT /walletobjects/v1/permissions/ISSUER_ID HTTP/1.1
Host: walletobjects.googleapis.com
Content-Type: application/json
Authorization: Bearer ACCESS_TOKEN;
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
{
"issuerId": "ISSUER_ID",
"permissions": [
{
emailAddress = "EMAIL_ADDRESS",
role = "READER | WRITER | OWNER"
}
]
}
# [END updatePermissions]
# [START batch]
POST /batch HTTP/1.1
Host: walletobjects.googleapis.com
Content-Type: multipart/mixed; boundary=batch_createobjectbatch
Authorization: Bearer ACCESS_TOKEN
Content-Length: TOTAL_CONTENT_LENGTH
--batch_createobjectbatch
Content-Type: application/json
POST /walletobjects/v1/transitObject/
{
"id": "ISSUER_ID.OBJECT_ID",
"classId": "ISSUER_ID.CLASS_SUFFIX",
"state": "ACTIVE",
"heroImage": {
"sourceUri": {
"uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Hero image description"
}
}
},
"textModulesData": [
{
"header": "Text module header",
"body": "Text module body",
"id": "TEXT_MODULE_ID"
}
],
"linksModuleData": {
"uris": [
{
"uri": "http://maps.google.com/",
"description": "Link module URI description",
"id": "LINK_MODULE_URI_ID"
},
{
"uri": "tel:6505555555",
"description": "Link module tel description",
"id": "LINK_MODULE_TEL_ID"
}
]
},
"imageModulesData": [
{
"mainImage": {
"sourceUri": {
"uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Image module description"
}
}
},
"id": "IMAGE_MODULE_ID"
}
],
"barcode": {
"type": "QR_CODE",
"value": "QR code"
},
"locations": [
{
"latitude": 37.424015499999996,
"longitude": -122.09259560000001
}
],
"passengerType": "SINGLE_PASSENGER",
"passengerNames": "Passenger names",
"tripType": "ONE_WAY",
"ticketLeg": {
"originStationCode": "LA",
"originName": {
"defaultValue": {
"language": "en-US",
"value": "Origin name"
}
},
"destinationStationCode": "SFO",
"destinationName": {
"defaultValue": {
"language": "en-US",
"value": "Destination name"
}
},
"departureDateTime": "2020-04-12T16:20:50.52Z",
"arrivalDateTime": "2020-04-12T20:20:50.52Z",
"fareName": {
"defaultValue": {
"language": "en-US",
"value": "Fare name"
}
}
}
}
--batch_createobjectbatch
Content-Type: application/json
POST /walletobjects/v1/transitObject/
{
"id": "ISSUER_ID.OBJECT_ID",
"classId": "ISSUER_ID.CLASS_SUFFIX",
"state": "ACTIVE",
"heroImage": {
"sourceUri": {
"uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Hero image description"
}
}
},
"textModulesData": [
{
"header": "Text module header",
"body": "Text module body",
"id": "TEXT_MODULE_ID"
}
],
"linksModuleData": {
"uris": [
{
"uri": "http://maps.google.com/",
"description": "Link module URI description",
"id": "LINK_MODULE_URI_ID"
},
{
"uri": "tel:6505555555",
"description": "Link module tel description",
"id": "LINK_MODULE_TEL_ID"
}
]
},
"imageModulesData": [
{
"mainImage": {
"sourceUri": {
"uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Image module description"
}
}
},
"id": "IMAGE_MODULE_ID"
}
],
"barcode": {
"type": "QR_CODE",
"value": "QR code"
},
"locations": [
{
"latitude": 37.424015499999996,
"longitude": -122.09259560000001
}
],
"passengerType": "SINGLE_PASSENGER",
"passengerNames": "Passenger names",
"tripType": "ONE_WAY",
"ticketLeg": {
"originStationCode": "LA",
"originName": {
"defaultValue": {
"language": "en-US",
"value": "Origin name"
}
},
"destinationStationCode": "SFO",
"destinationName": {
"defaultValue": {
"language": "en-US",
"value": "Destination name"
}
},
"departureDateTime": "2020-04-12T16:20:50.52Z",
"arrivalDateTime": "2020-04-12T20:20:50.52Z",
"fareName": {
"defaultValue": {
"language": "en-US",
"value": "Fare name"
}
}
}
}
--batch_createobjectbatch
Content-Type: application/json
POST /walletobjects/v1/transitObject/
{
"id": "ISSUER_ID.OBJECT_ID",
"classId": "ISSUER_ID.CLASS_SUFFIX",
"state": "ACTIVE",
"heroImage": {
"sourceUri": {
"uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Hero image description"
}
}
},
"textModulesData": [
{
"header": "Text module header",
"body": "Text module body",
"id": "TEXT_MODULE_ID"
}
],
"linksModuleData": {
"uris": [
{
"uri": "http://maps.google.com/",
"description": "Link module URI description",
"id": "LINK_MODULE_URI_ID"
},
{
"uri": "tel:6505555555",
"description": "Link module tel description",
"id": "LINK_MODULE_TEL_ID"
}
]
},
"imageModulesData": [
{
"mainImage": {
"sourceUri": {
"uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
},
"contentDescription": {
"defaultValue": {
"language": "en-US",
"value": "Image module description"
}
}
},
"id": "IMAGE_MODULE_ID"
}
],
"barcode": {
"type": "QR_CODE",
"value": "QR code"
},
"locations": [
{
"latitude": 37.424015499999996,
"longitude": -122.09259560000001
}
],
"passengerType": "SINGLE_PASSENGER",
"passengerNames": "Passenger names",
"tripType": "ONE_WAY",
"ticketLeg": {
"originStationCode": "LA",
"originName": {
"defaultValue": {
"language": "en-US",
"value": "Origin name"
}
},
"destinationStationCode": "SFO",
"destinationName": {
"defaultValue": {
"language": "en-US",
"value": "Destination name"
}
},
"departureDateTime": "2020-04-12T16:20:50.52Z",
"arrivalDateTime": "2020-04-12T20:20:50.52Z",
"fareName": {
"defaultValue": {
"language": "en-US",
"value": "Fare name"
}
}
}
}
--batch_createobjectbatch--
# [END batch]

View File

@@ -6,23 +6,25 @@ The files in this directory each implement a demo class for a specific Google
Wallet pass type. Each class implements methods for performing tasks such as
creating a pass class, updating issuer permissions, and more.
| Pass type | File |
|-----------|------|
| Event tickets | [DemoEventTicket.java](./src/main/java/DemoEventTicket.java) |
| Flight boarding passes | [DemoFlight.java](./src/main/java/DemoFlight.java) |
| Generic passes | [DemoGeneric.java](./src/main/java/DemoGeneric.java) |
| Gift cards | [DemoGiftCard.java](./src/main/java/DemoGiftCard.java) |
| Loyalty program membership | [DemoLoyalty.java](./src/main/java/DemoLoyalty.java) |
| Offers and promotions | [DemoOffer.java](./src/main/java/DemoOffer.java) |
| Transit passes | [DemoTransit.java](./src/main/java/DemoTransit.java) |
| Pass type | File |
|----------------------------|--------------------------------------------------------------|
| Event tickets | [DemoEventTicket.java](./src/main/java/DemoEventTicket.java) |
| Flight boarding passes | [DemoFlight.java](./src/main/java/DemoFlight.java) |
| Generic passes | [DemoGeneric.java](./src/main/java/DemoGeneric.java) |
| Gift cards | [DemoGiftCard.java](./src/main/java/DemoGiftCard.java) |
| Loyalty program membership | [DemoLoyalty.java](./src/main/java/DemoLoyalty.java) |
| Offers and promotions | [DemoOffer.java](./src/main/java/DemoOffer.java) |
| Transit passes | [DemoTransit.java](./src/main/java/DemoTransit.java) |
## Prerequisites
* Java 17+
* JDK 11+
* Follow the steps outlined in the [Google Wallet prerequisites](https://developers.google.com/wallet/generic/web/prerequisites) to create the Google Wallet issuer account and Google Cloud service account
* Download the Java
[Google Wallet API Client library](https://developers.google.com/wallet/generic/resources/libraries#java)
* Java 17+
* JDK 11+
* Follow the steps outlined in the
[Google Wallet prerequisites](https://developers.google.com/wallet/generic/web/prerequisites)
to create the Google Wallet issuer account and Google Cloud service account
* Download the Java
[Google Wallet API Client library](https://developers.google.com/wallet/generic/resources/libraries#java)
## Environment variables
@@ -30,44 +32,63 @@ The following environment variables must be set. Alternatively, you can update
the code files to set the values directly. They can be found in the constructor
for each class file.
| Enviroment variable | Description | Example |
|---------------------|-------------|---------|
| Enviroment variable | Description | Example |
|----------------------------------|-------------------------------------------------|---------------------|
| `GOOGLE_APPLICATION_CREDENTIALS` | Path to a Google Cloud service account key file | `/path/to/key.json` |
## How to use the code samples
1. Open the [`java`](./java/) project folder in your editor of choice.
2. Copy the path to the Google Wallet API Client library (
`libwalletobjects_public_java_lib_v1.jar` file) you downloaded. If needed,
update the path in [`build.gradle`](./build.gradle) (line 14).
1. Open the [`java`](./java/) project folder in your editor of choice.
2. Copy the path to the Google Wallet API Client library (
`libwalletobjects_public_java_lib_v1.jar` file) you downloaded. If needed,
update the path in [`build.gradle`](./build.gradle) (line 14).
```plain
implementation files('lib/libwalletobjects_public_java_lib_v1.jar')
```
3. Build the project to install the dependencies.
4. In your Java code, import a demo class and call its method(s). An example
can be found below
3. Build the project to install the dependencies.
4. In your Java code, import a demo class and call its method(s). An example
can be found below
```java
// Create a demo class instance
// Creates the authenticated HTTP client
DemoEventTicket demo = new DemoEventTicket();
// Create the authenticated HTTP client
demo.Auth();
// Create a pass class
demo.CreateEventTicketClass("issuer_id", "class_suffix");
demo.CreateClass("issuer_id", "class_suffix");
// Update a pass class
demo.UpdateClass("issuer_id", "class_suffix");
// Patch a pass class
demo.PatchClass("issuer_id", "class_suffix");
// Add a message to a pass class
demo.AddClassMessage("issuer_id", "class_suffix", "header", "body");
// Create a pass object
demo.CreateEventTicketObject("issuer_id", "class_suffix", "user_id");
demo.CreateObject("issuer_id", "class_suffix", "object_suffix");
// Create an Add to Google Wallet link
demo.CreateJWTSaveURL("issuer_id", "class_suffix", "user_id");
// Update a pass object
demo.UpdateObject("issuer_id", "object_suffix");
// Create an issuer account
demo.CreateIssuerAccount("issuer_name", "issuer_email");
// Patch a pass object
demo.PatchObject("issuer_id", "object_suffix");
// Add a message to a pass object
demo.AddObjectMessage("issuer_id", "object_suffix", "header", "body");
// Expire a pass object
demo.ExpireObject("issuer_id", "object_suffix");
// Generate an Add to Google Wallet link that creates a new pass class and object
demo.CreateJWTNewObjects("issuer_id", "class_suffix", "object_suffix");
// Generate an Add to Google Wallet link that references existing pass object(s)
demo.CreateJWTExistingObjects("issuer_id");
// Create pass objects in batch
demo.BatchCreateEventTicketObjects("issuer_id", "class_suffix");
demo.BatchCreateObjects("issuer_id", "class_suffix");
```

View File

@@ -49,9 +49,11 @@ public class DemoEventTicket {
/** Google Wallet service client. */
public static Walletobjects service;
public DemoEventTicket() {
public DemoEventTicket() throws Exception {
keyFilePath =
System.getenv().getOrDefault("GOOGLE_APPLICATION_CREDENTIALS", "/path/to/key.json");
Auth();
}
// [END setup]
@@ -71,6 +73,7 @@ public class DemoEventTicket {
HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
// Initialize Google Wallet API service
service =
new Walletobjects.Builder(
httpTransport,
@@ -81,87 +84,232 @@ public class DemoEventTicket {
}
// [END auth]
// [START class]
// [START createClass]
/**
* Create a class via the API. This can also be done in the Google Pay and Wallet console.
* Create a class.
*
* @param issuerId The issuer ID being used for this request.
* @param classSuffix Developer-defined unique ID for this pass class.
* @return The pass class ID: "{issuerId}.{classSuffix}"
* @throws IOException
*/
public String CreateEventTicketClass(String issuerId, String classSuffix) throws IOException {
// See below for more information on required properties
public String CreateClass(String issuerId, String classSuffix) throws IOException {
// Check if the class exists
try {
service.eventticketclass().get(String.format("%s.%s", issuerId, classSuffix)).execute();
System.out.println(String.format("Class %s.%s already exists!", issuerId, classSuffix));
return String.format("%s.%s", issuerId, classSuffix);
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() != 404) {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, classSuffix);
}
}
// See link below for more information on required properties
// https://developers.google.com/wallet/tickets/events/rest/v1/eventticketclass
EventTicketClass eventTicketClass =
EventTicketClass newClass =
new EventTicketClass()
.setId(String.format("%s.%s", issuerId, classSuffix))
.setIssuerName("Issuer name")
.setReviewStatus("UNDER_REVIEW")
.setEventId(String.format("%s.%s", issuerId, classSuffix))
.setEventName(
new LocalizedString()
.setDefaultValue(
new TranslatedString().setLanguage("en-US").setValue("Event name")));
new TranslatedString().setLanguage("en-US").setValue("Event name")))
.setId(String.format("%s.%s", issuerId, classSuffix))
.setIssuerName("Issuer name")
.setReviewStatus("UNDER_REVIEW");
try {
EventTicketClass response = service.eventticketclass().insert(eventTicketClass).execute();
EventTicketClass response = service.eventticketclass().insert(newClass).execute();
System.out.println("Class insert response");
System.out.println(response.toPrettyString());
System.out.println("Class insert response");
System.out.println(response.toPrettyString());
return response.getId();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() == 409) {
System.out.println(String.format("Class %s.%s already exists", issuerId, classSuffix));
return String.format("%s.%s", issuerId, classSuffix);
}
// Something else went wrong
ex.printStackTrace();
return ex.getMessage();
}
return response.getId();
}
// [END class]
// [END createClass]
// [START object]
// [START updateClass]
/**
* Create an object via the API.
* Update a class.
*
* <p><strong>Warning:</strong> This replaces all existing class attributes!
*
* @param issuerId The issuer ID being used for this request.
* @param classSuffix Developer-defined unique ID for this pass class.
* @param userId Developer-defined user ID for this object.
* @return The pass object ID: "{issuerId}.{userId}"
* @return The pass class ID: "{issuerId}.{classSuffix}"
* @throws IOException
*/
public String CreateEventTicketObject(String issuerId, String classSuffix, String userId)
throws IOException {
// Generate the object ID
// Should only include alphanumeric characters, '.', '_', or '-'
String newUserId = userId.replaceAll("[^\\w.-]", "_");
String objectId = String.format("%s.%s", issuerId, newUserId);
public String UpdateClass(String issuerId, String classSuffix) throws IOException {
EventTicketClass updatedClass;
// Check if the class exists
try {
// Check if the object exists
EventTicketObject response = service.eventticketobject().get(objectId).execute();
System.out.println("Object get response");
System.out.println(response.toPrettyString());
return response.getId();
updatedClass =
service.eventticketclass().get(String.format("%s.%s", issuerId, classSuffix)).execute();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() != 404) {
// Something else went wrong
if (ex.getStatusCode() == 404) {
// Class does not exist
System.out.println(String.format("Class %s.%s not found!", issuerId, classSuffix));
return String.format("%s.%s", issuerId, classSuffix);
} else {
// Something else went wrong...
ex.printStackTrace();
return ex.getMessage();
return String.format("%s.%s", issuerId, classSuffix);
}
}
// Object doesn't exist, create it now
// See below for more information on required properties
// Class exists
// Update the class by adding a homepage
updatedClass.setHomepageUri(
new Uri()
.setUri("https://developers.google.com/wallet")
.setDescription("Homepage description"));
// Note: reviewStatus must be 'UNDER_REVIEW' or 'DRAFT' for updates
updatedClass.setReviewStatus("UNDER_REVIEW");
EventTicketClass response =
service
.eventticketclass()
.update(String.format("%s.%s", issuerId, classSuffix), updatedClass)
.execute();
System.out.println("Class update response");
System.out.println(response.toPrettyString());
return response.getId();
}
// [END updateClass]
// [START patchClass]
/**
* Patch a class.
*
* <p>The PATCH method supports patch semantics.
*
* @param issuerId The issuer ID being used for this request.
* @param classSuffix Developer-defined unique ID for this pass class.
* @return The pass class ID: "{issuerId}.{classSuffix}"
* @throws IOException
*/
public String PatchClass(String issuerId, String classSuffix) throws IOException {
// Check if the class exists
try {
service.eventticketclass().get(String.format("%s.%s", issuerId, classSuffix)).execute();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() == 404) {
// Class does not exist
System.out.println(String.format("Class %s.%s not found!", issuerId, classSuffix));
return String.format("%s.%s", issuerId, classSuffix);
} else {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, classSuffix);
}
}
// Class exists
// Patch the class by adding a homepage
EventTicketClass patchBody =
new EventTicketClass()
.setHomepageUri(
new Uri()
.setUri("https://developers.google.com/wallet")
.setDescription("Homepage description"))
// Note: reviewStatus must be 'UNDER_REVIEW' or 'DRAFT' for updates
.setReviewStatus("UNDER_REVIEW");
EventTicketClass response =
service
.eventticketclass()
.patch(String.format("%s.%s", issuerId, classSuffix), patchBody)
.execute();
System.out.println("Class patch response");
System.out.println(response.toPrettyString());
return response.getId();
}
// [END patchClass]
// [START addMessageClass]
/**
* Add a message to a pass class.
*
* @param issuerId The issuer ID being used for this request.
* @param classSuffix Developer-defined unique ID for this pass class.
* @param header The message header.
* @param body The message body.
* @return The pass class ID: "{issuerId}.{classSuffix}"
* @throws IOException
*/
public String AddClassMessage(String issuerId, String classSuffix, String header, String body)
throws IOException {
// Check if the class exists
try {
service.eventticketclass().get(String.format("%s.%s", issuerId, classSuffix)).execute();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() == 404) {
// Class does not exist
System.out.println(String.format("Class %s.%s not found!", issuerId, classSuffix));
return String.format("%s.%s", issuerId, classSuffix);
} else {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, classSuffix);
}
}
AddMessageRequest message =
new AddMessageRequest().setMessage(new Message().setHeader(header).setBody(body));
EventTicketClassAddMessageResponse response =
service
.eventticketclass()
.addmessage(String.format("%s.%s", issuerId, classSuffix), message)
.execute();
System.out.println("Class addMessage response");
System.out.println(response.toPrettyString());
return String.format("%s.%s", issuerId, classSuffix);
}
// [END addMessageClass]
// [START createObject]
/**
* Create an object.
*
* @param issuerId The issuer ID being used for this request.
* @param classSuffix Developer-defined unique ID for this pass class.
* @param objectSuffix Developer-defined unique ID for this pass object.
* @return The pass object ID: "{issuerId}.{objectSuffix}"
* @throws IOException
*/
public String CreateObject(String issuerId, String classSuffix, String objectSuffix)
throws IOException {
// Check if the object exists
try {
service.eventticketobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute();
System.out.println(String.format("Object %s.%s already exists!", issuerId, objectSuffix));
return String.format("%s.%s", issuerId, objectSuffix);
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() != 404) {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, objectSuffix);
}
}
// See link below for more information on required properties
// https://developers.google.com/wallet/tickets/events/rest/v1/eventticketobject
EventTicketObject eventTicketObject =
EventTicketObject newObject =
new EventTicketObject()
.setId(objectId)
.setId(String.format("%s.%s", issuerId, objectSuffix))
.setClassId(String.format("%s.%s", issuerId, classSuffix))
.setState("ACTIVE")
.setHeroImage(
@@ -237,16 +385,219 @@ public class DemoEventTicket {
.setTicketHolderName("Ticket holder name")
.setTicketNumber("Ticket number");
EventTicketObject response = service.eventticketobject().insert(eventTicketObject).execute();
EventTicketObject response = service.eventticketobject().insert(newObject).execute();
System.out.println("Object insert response");
System.out.println(response.toPrettyString());
return response.getId();
}
// [END object]
// [END createObject]
// [START jwt]
// [START updateObject]
/**
* Update an object.
*
* <p><strong>Warning:</strong> This replaces all existing object attributes!
*
* @param issuerId The issuer ID being used for this request.
* @param objectSuffix Developer-defined unique ID for this pass object.
* @return The pass object ID: "{issuerId}.{objectSuffix}"
* @throws IOException
*/
public String UpdateObject(String issuerId, String objectSuffix) throws IOException {
EventTicketObject updatedObject;
// Check if the object exists
try {
updatedObject =
service.eventticketobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() == 404) {
// Object does not exist
System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix));
return String.format("%s.%s", issuerId, objectSuffix);
} else {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, objectSuffix);
}
}
// Object exists
// Update the object by adding a link
Uri newLink =
new Uri()
.setUri("https://developers.google.com/wallet")
.setDescription("New link description");
if (updatedObject.getLinksModuleData() == null) {
// LinksModuleData was not set on the original object
updatedObject.setLinksModuleData(new LinksModuleData().setUris(Arrays.asList(newLink)));
} else {
updatedObject.getLinksModuleData().getUris().add(newLink);
}
EventTicketObject response =
service
.eventticketobject()
.update(String.format("%s.%s", issuerId, objectSuffix), updatedObject)
.execute();
System.out.println("Object update response");
System.out.println(response.toPrettyString());
return response.getId();
}
// [END updateObject]
// [START patchObject]
/**
* Patch an object.
*
* @param issuerId The issuer ID being used for this request.
* @param objectSuffix Developer-defined unique ID for this pass object.
* @return The pass object ID: "{issuerId}.{objectSuffix}"
* @throws IOException
*/
public String PatchObject(String issuerId, String objectSuffix) throws IOException {
EventTicketObject existingObject;
// Check if the object exists
try {
existingObject =
service.eventticketobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() == 404) {
// Object does not exist
System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix));
return String.format("%s.%s", issuerId, objectSuffix);
} else {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, objectSuffix);
}
}
// Object exists
// Patch the object by adding a link
Uri newLink =
new Uri()
.setUri("https://developers.google.com/wallet")
.setDescription("New link description");
EventTicketObject patchBody = new EventTicketObject();
if (existingObject.getLinksModuleData() == null) {
// LinksModuleData was not set on the original object
patchBody.setLinksModuleData(new LinksModuleData().setUris(new ArrayList<Uri>()));
} else {
patchBody.setLinksModuleData(existingObject.getLinksModuleData());
}
patchBody.getLinksModuleData().getUris().add(newLink);
EventTicketObject response =
service
.eventticketobject()
.patch(String.format("%s.%s", issuerId, objectSuffix), patchBody)
.execute();
System.out.println("Object patch response");
System.out.println(response.toPrettyString());
return response.getId();
}
// [END patchObject]
// [START expireObject]
/**
* Expire an object.
*
* <p>Sets the object's state to Expired. If the valid time interval is already set, the pass will
* expire automatically up to 24 hours after.
*
* @param issuerId The issuer ID being used for this request.
* @param objectSuffix Developer-defined unique ID for this pass object.
* @return The pass object ID: "{issuerId}.{objectSuffix}"
* @throws IOException
*/
public String ExpireObject(String issuerId, String objectSuffix) throws IOException {
// Check if the object exists
try {
service.eventticketobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() == 404) {
// Object does not exist
System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix));
return String.format("%s.%s", issuerId, objectSuffix);
} else {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, objectSuffix);
}
}
// Patch the object, setting the pass as expired
EventTicketObject patchBody = new EventTicketObject().setState("EXPIRED");
EventTicketObject response =
service
.eventticketobject()
.patch(String.format("%s.%s", issuerId, objectSuffix), patchBody)
.execute();
System.out.println("Object expiration response");
System.out.println(response.toPrettyString());
return response.getId();
}
// [END expireObject]
// [START addMessageObject]
/**
* Add a message to a pass object.
*
* @param issuerId The issuer ID being used for this request.
* @param objectSuffix Developer-defined unique ID for this pass object.
* @param header The message header.
* @param body The message body.
* @return The pass object ID: "{issuerId}.{objectSuffix}"
* @throws IOException
*/
public String AddObjectMessage(String issuerId, String objectSuffix, String header, String body)
throws IOException {
// Check if the object exists
try {
service.eventticketobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() == 404) {
// Object does not exist
System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix));
return String.format("%s.%s", issuerId, objectSuffix);
} else {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, objectSuffix);
}
}
AddMessageRequest message =
new AddMessageRequest().setMessage(new Message().setHeader(header).setBody(body));
EventTicketObjectAddMessageResponse response =
service
.eventticketobject()
.addmessage(String.format("%s.%s", issuerId, objectSuffix), message)
.execute();
System.out.println("Object addMessage response");
System.out.println(response.toPrettyString());
return String.format("%s.%s", issuerId, objectSuffix);
}
// [END addMessageObject]
// [START jwtNew]
/**
* Generate a signed JWT that creates a new pass class and object.
*
@@ -256,18 +607,13 @@ public class DemoEventTicket {
*
* @param issuerId The issuer ID being used for this request.
* @param classSuffix Developer-defined unique ID for this pass class.
* @param userId Developer-defined user ID for this object.
* @param objectSuffix Developer-defined unique ID for the pass object.
* @return An "Add to Google Wallet" link.
*/
public String CreateJWTSaveURL(String issuerId, String classSuffix, String userId) {
// Generate the object ID
// Should only include alphanumeric characters, '.', '_', or '-'
String newUserId = userId.replaceAll("[^\\w.-]", "_");
String objectId = String.format("%s.%s", issuerId, newUserId);
// See below for more information on required properties
public String CreateJWTNewObjects(String issuerId, String classSuffix, String objectSuffix) {
// See link below for more information on required properties
// https://developers.google.com/wallet/tickets/events/rest/v1/eventticketclass
EventTicketClass eventTicketClass =
EventTicketClass newClass =
new EventTicketClass()
.setId(String.format("%s.%s", issuerId, classSuffix))
.setIssuerName("Issuer name")
@@ -277,11 +623,11 @@ public class DemoEventTicket {
.setDefaultValue(
new TranslatedString().setLanguage("en-US").setValue("Event name")));
// See below for more information on required properties
// See link below for more information on required properties
// https://developers.google.com/wallet/tickets/events/rest/v1/eventticketobject
EventTicketObject eventTicketObject =
EventTicketObject newObject =
new EventTicketObject()
.setId(objectId)
.setId(String.format("%s.%s", issuerId, objectSuffix))
.setClassId(String.format("%s.%s", issuerId, classSuffix))
.setState("ACTIVE")
.setHeroImage(
@@ -366,8 +712,8 @@ public class DemoEventTicket {
// Create the Google Wallet payload and add to the JWT
HashMap<String, Object> payload = new HashMap<String, Object>();
payload.put("eventTicketClasses", Arrays.asList(eventTicketClass));
payload.put("eventTicketObjects", Arrays.asList(eventTicketObject));
payload.put("eventTicketClasses", Arrays.asList(newClass));
payload.put("eventTicketObjects", Arrays.asList(newObject));
claims.put("payload", payload);
// The service account credentials are used to sign the JWT
@@ -381,62 +727,105 @@ public class DemoEventTicket {
return String.format("https://pay.google.com/gp/v/save/%s", token);
}
// [END jwt]
// [END jwtNew]
// [START createIssuer]
// [START jwtExisting]
/**
* Create a new Google Wallet issuer account.
* Generate a signed JWT that references an existing pass object.
*
* @param issuerName The issuer's name.
* @param issuerEmail The issuer's email address.
* @throws IOException
*/
public void CreateIssuerAccount(String issuerName, String issuerEmail) throws IOException {
// New issuer information
Issuer issuer =
new Issuer()
.setName(issuerName)
.setContactInfo(new IssuerContactInfo().setEmail(issuerEmail));
Issuer response = service.issuer().insert(issuer).execute();
System.out.println("Issuer insert response");
System.out.println(response.toPrettyString());
}
// [END createIssuer]
// [START updatePermissions]
/**
* Update permissions for an existing Google Wallet issuer account. <strong>Warning:</strong> This
* operation overwrites all existing permissions!
* <p>When the user opens the "Add to Google Wallet" URL and saves the pass to their wallet, the
* pass objects defined in the JWT are added to the user's Google Wallet app. This allows the user
* to save multiple pass objects in one API call.
*
* <p>Example permissions list argument below. Copy the add entry as needed for each email address
* that will need access. Supported values for role are: 'READER', 'WRITER', and 'OWNER'
* <p>The objects to add must follow the below format:
*
* <pre><code>
* ArrayList<Permission> permissions = new ArrayList<Permission>();
* permissions.add(new Permission().setEmailAddress("emailAddress").setRole("OWNER"));
* </code></pre>
* <p>{ 'id': 'ISSUER_ID.OBJECT_SUFFIX', 'classId': 'ISSUER_ID.CLASS_SUFFIX' }
*
* @param issuerId The issuer ID being used for this request.
* @param permissions The list of email addresses and roles to assign.
* @throws IOException
* @return An "Add to Google Wallet" link.
*/
public void UpdateIssuerAccountPermissions(String issuerId, ArrayList<Permission> permissions)
throws IOException {
public String CreateJWTExistingObjects(String issuerId) {
// Multiple pass types can be added at the same time
// At least one type must be specified in the JWT claims
// Note: Make sure to replace the placeholder class and object suffixes
HashMap<String, Object> objectsToAdd = new HashMap<String, Object>();
Permissions response =
service
.permissions()
.update(
Long.parseLong(issuerId),
new Permissions().setIssuerId(Long.parseLong(issuerId)).setPermissions(permissions))
.execute();
// Event tickets
objectsToAdd.put(
"eventTicketObjects",
Arrays.asList(
new EventTicketObject()
.setId(String.format("%s.%s", issuerId, "EVENT_OBJECT_SUFFIX"))
.setClassId(String.format("%s.%s", issuerId, "EVENT_CLASS_SUFFIX"))));
System.out.println("Issuer permissions update response");
System.out.println(response.toPrettyString());
// Boarding passes
objectsToAdd.put(
"flightObjects",
Arrays.asList(
new FlightObject()
.setId(String.format("%s.%s", issuerId, "FLIGHT_OBJECT_SUFFIX"))
.setClassId(String.format("%s.%s", issuerId, "FLIGHT_CLASS_SUFFIX"))));
// Generic passes
objectsToAdd.put(
"genericObjects",
Arrays.asList(
new GenericObject()
.setId(String.format("%s.%s", issuerId, "GENERIC_OBJECT_SUFFIX"))
.setClassId(String.format("%s.%s", issuerId, "GENERIC_CLASS_SUFFIX"))));
// Gift cards
objectsToAdd.put(
"giftCardObjects",
Arrays.asList(
new GiftCardObject()
.setId(String.format("%s.%s", issuerId, "GIFT_CARD_OBJECT_SUFFIX"))
.setClassId(String.format("%s.%s", issuerId, "GIFT_CARD_CLASS_SUFFIX"))));
// Loyalty cards
objectsToAdd.put(
"loyaltyObjects",
Arrays.asList(
new LoyaltyObject()
.setId(String.format("%s.%s", issuerId, "LOYALTY_OBJECT_SUFFIX"))
.setClassId(String.format("%s.%s", issuerId, "LOYALTY_CLASS_SUFFIX"))));
// Offers
objectsToAdd.put(
"offerObjects",
Arrays.asList(
new OfferObject()
.setId(String.format("%s.%s", issuerId, "OFFER_OBJECT_SUFFIX"))
.setClassId(String.format("%s.%s", issuerId, "OFFER_CLASS_SUFFIX"))));
// Transit passes
objectsToAdd.put(
"transitObjects",
Arrays.asList(
new TransitObject()
.setId(String.format("%s.%s", issuerId, "TRANSIT_OBJECT_SUFFIX"))
.setClassId(String.format("%s.%s", issuerId, "TRANSIT_CLASS_SUFFIX"))));
// Create the JWT as a HashMap object
HashMap<String, Object> claims = new HashMap<String, Object>();
claims.put("iss", ((ServiceAccountCredentials) credentials).getClientEmail());
claims.put("aud", "google");
claims.put("origins", Arrays.asList("www.example.com"));
claims.put("typ", "savetowallet");
claims.put("payload", objectsToAdd);
// The service account credentials are used to sign the JWT
Algorithm algorithm =
Algorithm.RSA256(
null, (RSAPrivateKey) ((ServiceAccountCredentials) credentials).getPrivateKey());
String token = JWT.create().withPayload(claims).sign(algorithm);
System.out.println("Add to Google Wallet link");
System.out.println(String.format("https://pay.google.com/gp/v/save/%s", token));
return String.format("https://pay.google.com/gp/v/save/%s", token);
}
// [END updatePermissions]
// [END jwtExisting]
// [START batch]
/**
@@ -446,7 +835,7 @@ public class DemoEventTicket {
* @param classSuffix Developer-defined unique ID for this pass class.
* @throws IOException
*/
public void BatchCreateEventTicketObjects(String issuerId, String classSuffix) throws IOException {
public void BatchCreateObjects(String issuerId, String classSuffix) throws IOException {
// Create the batch request client
BatchRequest batch = service.batch(new HttpCredentialsAdapter(credentials));
@@ -455,6 +844,7 @@ public class DemoEventTicket {
new JsonBatchCallback<EventTicketObject>() {
// Invoked if the request was successful
public void onSuccess(EventTicketObject response, HttpHeaders responseHeaders) {
System.out.println("Batch insert response");
System.out.println(response.toString());
}
@@ -466,18 +856,14 @@ public class DemoEventTicket {
// Example: Generate three new pass objects
for (int i = 0; i < 3; i++) {
// Generate a random user ID
String userId = UUID.randomUUID().toString().replaceAll("[^\\w.-]", "_");
// Generate a random object suffix
String objectSuffix = UUID.randomUUID().toString().replaceAll("[^\\w.-]", "_");
// Generate a random object ID with the user ID
// Should only include alphanumeric characters, '.', '_', or '-'
String objectId = String.format("%s.%s-%s", issuerId, userId, classSuffix);
// See below for more information on required properties
// See link below for more information on required properties
// https://developers.google.com/wallet/tickets/events/rest/v1/eventticketobject
EventTicketObject eventTicketObject =
EventTicketObject batchObject =
new EventTicketObject()
.setId(objectId)
.setId(String.format("%s.%s", issuerId, objectSuffix))
.setClassId(String.format("%s.%s", issuerId, classSuffix))
.setState("ACTIVE")
.setHeroImage(
@@ -553,7 +939,7 @@ public class DemoEventTicket {
.setTicketHolderName("Ticket holder name")
.setTicketNumber("Ticket number");
service.eventticketobject().insert(eventTicketObject).queue(batch, callback);
service.eventticketobject().insert(batchObject).queue(batch, callback);
}
// Invoke the batch API calls

View File

@@ -49,9 +49,11 @@ public class DemoFlight {
/** Google Wallet service client. */
public static Walletobjects service;
public DemoFlight() {
public DemoFlight() throws Exception {
keyFilePath =
System.getenv().getOrDefault("GOOGLE_APPLICATION_CREDENTIALS", "/path/to/key.json");
Auth();
}
// [END setup]
@@ -71,6 +73,7 @@ public class DemoFlight {
HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
// Initialize Google Wallet API service
service =
new Walletobjects.Builder(
httpTransport,
@@ -81,19 +84,33 @@ public class DemoFlight {
}
// [END auth]
// [START class]
// [START createClass]
/**
* Create a class via the API. This can also be done in the Google Pay and Wallet console.
* Create a class.
*
* @param issuerId The issuer ID being used for this request.
* @param classSuffix Developer-defined unique ID for this pass class.
* @return The pass class ID: "{issuerId}.{classSuffix}"
* @throws IOException
*/
public String CreateFlightClass(String issuerId, String classSuffix) throws IOException {
public String CreateClass(String issuerId, String classSuffix) throws IOException {
// Check if the class exists
try {
service.flightclass().get(String.format("%s.%s", issuerId, classSuffix)).execute();
System.out.println(String.format("Class %s.%s already exists!", issuerId, classSuffix));
return String.format("%s.%s", issuerId, classSuffix);
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() != 404) {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, classSuffix);
}
}
// See link below for more information on required properties
// https://developers.google.com/wallet/tickets/boarding-passes/rest/v1/flightclass
FlightClass flightClass =
FlightClass newClass =
new FlightClass()
.setId(String.format("%s.%s", issuerId, classSuffix))
.setIssuerName("Issuer name")
@@ -107,65 +124,195 @@ public class DemoFlight {
.setDestination(
new AirportInfo().setAirportIataCode("SFO").setTerminal("2").setGate("C3"));
try {
FlightClass response = service.flightclass().insert(flightClass).execute();
FlightClass response = service.flightclass().insert(newClass).execute();
System.out.println("Class insert response");
System.out.println(response.toPrettyString());
System.out.println("Class insert response");
System.out.println(response.toPrettyString());
return response.getId();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() == 409) {
System.out.println(String.format("Class %s.%s already exists", issuerId, classSuffix));
return String.format("%s.%s", issuerId, classSuffix);
}
// Something else went wrong
ex.printStackTrace();
return ex.getMessage();
}
return response.getId();
}
// [END class]
// [END createClass]
// [START object]
// [START updateClass]
/**
* Create an object via the API.
* Update a class.
*
* <p><strong>Warning:</strong> This replaces all existing class attributes!
*
* @param issuerId The issuer ID being used for this request.
* @param classSuffix Developer-defined unique ID for this pass class.
* @param userId Developer-defined user ID for this object.
* @return The pass object ID: "{issuerId}.{userId}"
* @return The pass class ID: "{issuerId}.{classSuffix}"
* @throws IOException
*/
public String CreateFlightObject(String issuerId, String classSuffix, String userId)
throws IOException {
// Generate the object ID
// Should only include alphanumeric characters, '.', '_', or '-'
String newUserId = userId.replaceAll("[^\\w.-]", "_");
String objectId = String.format("%s.%s", issuerId, newUserId);
public String UpdateClass(String issuerId, String classSuffix) throws IOException {
FlightClass updatedClass;
// Check if the class exists
try {
// Check if the object exists
FlightObject response = service.flightobject().get(objectId).execute();
System.out.println("Object get response");
System.out.println(response.toPrettyString());
return response.getId();
updatedClass =
service.flightclass().get(String.format("%s.%s", issuerId, classSuffix)).execute();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() != 404) {
// Something else went wrong
if (ex.getStatusCode() == 404) {
// Class does not exist
System.out.println(String.format("Class %s.%s not found!", issuerId, classSuffix));
return String.format("%s.%s", issuerId, classSuffix);
} else {
// Something else went wrong...
ex.printStackTrace();
return ex.getMessage();
return String.format("%s.%s", issuerId, classSuffix);
}
}
// Class exists
// Update the class by adding a homepage
updatedClass.setHomepageUri(
new Uri()
.setUri("https://developers.google.com/wallet")
.setDescription("Homepage description"));
// Note: reviewStatus must be 'UNDER_REVIEW' or 'DRAFT' for updates
updatedClass.setReviewStatus("UNDER_REVIEW");
FlightClass response =
service
.flightclass()
.update(String.format("%s.%s", issuerId, classSuffix), updatedClass)
.execute();
System.out.println("Class update response");
System.out.println(response.toPrettyString());
return response.getId();
}
// [END updateClass]
// [START patchClass]
/**
* Patch a class.
*
* <p>The PATCH method supports patch semantics.
*
* @param issuerId The issuer ID being used for this request.
* @param classSuffix Developer-defined unique ID for this pass class.
* @return The pass class ID: "{issuerId}.{classSuffix}"
* @throws IOException
*/
public String PatchClass(String issuerId, String classSuffix) throws IOException {
// Check if the class exists
try {
service.flightclass().get(String.format("%s.%s", issuerId, classSuffix)).execute();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() == 404) {
// Class does not exist
System.out.println(String.format("Class %s.%s not found!", issuerId, classSuffix));
return String.format("%s.%s", issuerId, classSuffix);
} else {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, classSuffix);
}
}
// Class exists
// Patch the class by adding a homepage
FlightClass patchBody =
new FlightClass()
.setHomepageUri(
new Uri()
.setUri("https://developers.google.com/wallet")
.setDescription("Homepage description"))
// Note: reviewStatus must be 'UNDER_REVIEW' or 'DRAFT' for updates
.setReviewStatus("UNDER_REVIEW");
FlightClass response =
service
.flightclass()
.patch(String.format("%s.%s", issuerId, classSuffix), patchBody)
.execute();
System.out.println("Class patch response");
System.out.println(response.toPrettyString());
return response.getId();
}
// [END patchClass]
// [START addMessageClass]
/**
* Add a message to a pass class.
*
* @param issuerId The issuer ID being used for this request.
* @param classSuffix Developer-defined unique ID for this pass class.
* @param header The message header.
* @param body The message body.
* @return The pass class ID: "{issuerId}.{classSuffix}"
* @throws IOException
*/
public String AddClassMessage(String issuerId, String classSuffix, String header, String body)
throws IOException {
// Check if the class exists
try {
service.flightclass().get(String.format("%s.%s", issuerId, classSuffix)).execute();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() == 404) {
// Class does not exist
System.out.println(String.format("Class %s.%s not found!", issuerId, classSuffix));
return String.format("%s.%s", issuerId, classSuffix);
} else {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, classSuffix);
}
}
AddMessageRequest message =
new AddMessageRequest().setMessage(new Message().setHeader(header).setBody(body));
FlightClassAddMessageResponse response =
service
.flightclass()
.addmessage(String.format("%s.%s", issuerId, classSuffix), message)
.execute();
System.out.println("Class addMessage response");
System.out.println(response.toPrettyString());
return String.format("%s.%s", issuerId, classSuffix);
}
// [END addMessageClass]
// [START createObject]
/**
* Create an object.
*
* @param issuerId The issuer ID being used for this request.
* @param classSuffix Developer-defined unique ID for this pass class.
* @param objectSuffix Developer-defined unique ID for this pass object.
* @return The pass object ID: "{issuerId}.{objectSuffix}"
* @throws IOException
*/
public String CreateObject(String issuerId, String classSuffix, String objectSuffix)
throws IOException {
// Check if the object exists
try {
service.flightobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute();
System.out.println(String.format("Object %s.%s already exists!", issuerId, objectSuffix));
return String.format("%s.%s", issuerId, objectSuffix);
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() != 404) {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, objectSuffix);
}
}
// Object doesn't exist, create it now
// See link below for more information on required properties
// https://developers.google.com/wallet/tickets/boarding-passes/rest/v1/flightobject
FlightObject flightObject =
FlightObject newObject =
new FlightObject()
.setId(objectId)
.setId(String.format("%s.%s", issuerId, objectSuffix))
.setClassId(String.format("%s.%s", issuerId, classSuffix))
.setState("ACTIVE")
.setHeroImage(
@@ -225,16 +372,219 @@ public class DemoFlight {
new BoardingAndSeatingInfo().setBoardingGroup("B").setSeatNumber("42"))
.setReservationInfo(new ReservationInfo().setConfirmationCode("Confirmation code"));
FlightObject response = service.flightobject().insert(flightObject).execute();
FlightObject response = service.flightobject().insert(newObject).execute();
System.out.println("Object insert response");
System.out.println(response.toPrettyString());
return response.getId();
}
// [END object]
// [END createObject]
// [START jwt]
// [START updateObject]
/**
* Update an object.
*
* <p><strong>Warning:</strong> This replaces all existing object attributes!
*
* @param issuerId The issuer ID being used for this request.
* @param objectSuffix Developer-defined unique ID for this pass object.
* @return The pass object ID: "{issuerId}.{objectSuffix}"
* @throws IOException
*/
public String UpdateObject(String issuerId, String objectSuffix) throws IOException {
FlightObject updatedObject;
// Check if the object exists
try {
updatedObject =
service.flightobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() == 404) {
// Object does not exist
System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix));
return String.format("%s.%s", issuerId, objectSuffix);
} else {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, objectSuffix);
}
}
// Object exists
// Update the object by adding a link
Uri newLink =
new Uri()
.setUri("https://developers.google.com/wallet")
.setDescription("New link description");
if (updatedObject.getLinksModuleData() == null) {
// LinksModuleData was not set on the original object
updatedObject.setLinksModuleData(new LinksModuleData().setUris(Arrays.asList(newLink)));
} else {
updatedObject.getLinksModuleData().getUris().add(newLink);
}
FlightObject response =
service
.flightobject()
.update(String.format("%s.%s", issuerId, objectSuffix), updatedObject)
.execute();
System.out.println("Object update response");
System.out.println(response.toPrettyString());
return response.getId();
}
// [END updateObject]
// [START patchObject]
/**
* Patch an object.
*
* @param issuerId The issuer ID being used for this request.
* @param objectSuffix Developer-defined unique ID for this pass object.
* @return The pass object ID: "{issuerId}.{objectSuffix}"
* @throws IOException
*/
public String PatchObject(String issuerId, String objectSuffix) throws IOException {
FlightObject existingObject;
// Check if the object exists
try {
existingObject =
service.flightobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() == 404) {
// Object does not exist
System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix));
return String.format("%s.%s", issuerId, objectSuffix);
} else {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, objectSuffix);
}
}
// Object exists
// Patch the object by adding a link
Uri newLink =
new Uri()
.setUri("https://developers.google.com/wallet")
.setDescription("New link description");
FlightObject patchBody = new FlightObject();
if (existingObject.getLinksModuleData() == null) {
// LinksModuleData was not set on the original object
patchBody.setLinksModuleData(new LinksModuleData().setUris(new ArrayList<Uri>()));
} else {
patchBody.setLinksModuleData(existingObject.getLinksModuleData());
}
patchBody.getLinksModuleData().getUris().add(newLink);
FlightObject response =
service
.flightobject()
.patch(String.format("%s.%s", issuerId, objectSuffix), patchBody)
.execute();
System.out.println("Object patch response");
System.out.println(response.toPrettyString());
return response.getId();
}
// [END patchObject]
// [START expireObject]
/**
* Expire an object.
*
* <p>Sets the object's state to Expired. If the valid time interval is already set, the pass will
* expire automatically up to 24 hours after.
*
* @param issuerId The issuer ID being used for this request.
* @param objectSuffix Developer-defined unique ID for this pass object.
* @return The pass object ID: "{issuerId}.{objectSuffix}"
* @throws IOException
*/
public String ExpireObject(String issuerId, String objectSuffix) throws IOException {
// Check if the object exists
try {
service.flightobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() == 404) {
// Object does not exist
System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix));
return String.format("%s.%s", issuerId, objectSuffix);
} else {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, objectSuffix);
}
}
// Patch the object, setting the pass as expired
FlightObject patchBody = new FlightObject().setState("EXPIRED");
FlightObject response =
service
.flightobject()
.patch(String.format("%s.%s", issuerId, objectSuffix), patchBody)
.execute();
System.out.println("Object expiration response");
System.out.println(response.toPrettyString());
return response.getId();
}
// [END expireObject]
// [START addMessageObject]
/**
* Add a message to a pass object.
*
* @param issuerId The issuer ID being used for this request.
* @param objectSuffix Developer-defined unique ID for this pass object.
* @param header The message header.
* @param body The message body.
* @return The pass object ID: "{issuerId}.{objectSuffix}"
* @throws IOException
*/
public String AddObjectMessage(String issuerId, String objectSuffix, String header, String body)
throws IOException {
// Check if the object exists
try {
service.flightobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() == 404) {
// Object does not exist
System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix));
return String.format("%s.%s", issuerId, objectSuffix);
} else {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, objectSuffix);
}
}
AddMessageRequest message =
new AddMessageRequest().setMessage(new Message().setHeader(header).setBody(body));
FlightObjectAddMessageResponse response =
service
.flightobject()
.addmessage(String.format("%s.%s", issuerId, objectSuffix), message)
.execute();
System.out.println("Object addMessage response");
System.out.println(response.toPrettyString());
return String.format("%s.%s", issuerId, objectSuffix);
}
// [END addMessageObject]
// [START jwtNew]
/**
* Generate a signed JWT that creates a new pass class and object.
*
@@ -244,18 +594,13 @@ public class DemoFlight {
*
* @param issuerId The issuer ID being used for this request.
* @param classSuffix Developer-defined unique ID for this pass class.
* @param userId Developer-defined user ID for this object.
* @param objectSuffix Developer-defined unique ID for the pass object.
* @return An "Add to Google Wallet" link.
*/
public String CreateJWTSaveURL(String issuerId, String classSuffix, String userId) {
// Generate the object ID
// Should only include alphanumeric characters, '.', '_', or '-'
String newUserId = userId.replaceAll("[^\\w.-]", "_");
String objectId = String.format("%s.%s", issuerId, newUserId);
public String CreateJWTNewObjects(String issuerId, String classSuffix, String objectSuffix) {
// See link below for more information on required properties
// https://developers.google.com/wallet/tickets/boarding-passes/rest/v1/flightclass
FlightClass flightClass =
FlightClass newClass =
new FlightClass()
.setId(String.format("%s.%s", issuerId, classSuffix))
.setIssuerName("Issuer name")
@@ -271,9 +616,9 @@ public class DemoFlight {
// See link below for more information on required properties
// https://developers.google.com/wallet/tickets/boarding-passes/rest/v1/flightobject
FlightObject flightObject =
FlightObject newObject =
new FlightObject()
.setId(objectId)
.setId(String.format("%s.%s", issuerId, objectSuffix))
.setClassId(String.format("%s.%s", issuerId, classSuffix))
.setState("ACTIVE")
.setHeroImage(
@@ -342,8 +687,8 @@ public class DemoFlight {
// Create the Google Wallet payload and add to the JWT
HashMap<String, Object> payload = new HashMap<String, Object>();
payload.put("flightClasses", Arrays.asList(flightClass));
payload.put("flightObjects", Arrays.asList(flightObject));
payload.put("flightClasses", Arrays.asList(newClass));
payload.put("flightObjects", Arrays.asList(newObject));
claims.put("payload", payload);
// The service account credentials are used to sign the JWT
@@ -357,62 +702,105 @@ public class DemoFlight {
return String.format("https://pay.google.com/gp/v/save/%s", token);
}
// [END jwt]
// [END jwtNew]
// [START createIssuer]
// [START jwtExisting]
/**
* Create a new Google Wallet issuer account.
* Generate a signed JWT that references an existing pass object.
*
* @param issuerName The issuer's name.
* @param issuerEmail The issuer's email address.
* @throws IOException
*/
public void CreateIssuerAccount(String issuerName, String issuerEmail) throws IOException {
// New issuer information
Issuer issuer =
new Issuer()
.setName(issuerName)
.setContactInfo(new IssuerContactInfo().setEmail(issuerEmail));
Issuer response = service.issuer().insert(issuer).execute();
System.out.println("Issuer insert response");
System.out.println(response.toPrettyString());
}
// [END createIssuer]
// [START updatePermissions]
/**
* Update permissions for an existing Google Wallet issuer account. <strong>Warning:</strong> This
* operation overwrites all existing permissions!
* <p>When the user opens the "Add to Google Wallet" URL and saves the pass to their wallet, the
* pass objects defined in the JWT are added to the user's Google Wallet app. This allows the user
* to save multiple pass objects in one API call.
*
* <p>Example permissions list argument below. Copy the add entry as needed for each email address
* that will need access. Supported values for role are: 'READER', 'WRITER', and 'OWNER'
* <p>The objects to add must follow the below format:
*
* <pre><code>
* ArrayList<Permission> permissions = new ArrayList<Permission>();
* permissions.add(new Permission().setEmailAddress("emailAddress").setRole("OWNER"));
* </code></pre>
* <p>{ 'id': 'ISSUER_ID.OBJECT_SUFFIX', 'classId': 'ISSUER_ID.CLASS_SUFFIX' }
*
* @param issuerId The issuer ID being used for this request.
* @param permissions The list of email addresses and roles to assign.
* @throws IOException
* @return An "Add to Google Wallet" link.
*/
public void UpdateIssuerAccountPermissions(String issuerId, ArrayList<Permission> permissions)
throws IOException {
public String CreateJWTExistingObjects(String issuerId) {
// Multiple pass types can be added at the same time
// At least one type must be specified in the JWT claims
// Note: Make sure to replace the placeholder class and object suffixes
HashMap<String, Object> objectsToAdd = new HashMap<String, Object>();
Permissions response =
service
.permissions()
.update(
Long.parseLong(issuerId),
new Permissions().setIssuerId(Long.parseLong(issuerId)).setPermissions(permissions))
.execute();
// Event tickets
objectsToAdd.put(
"eventTicketObjects",
Arrays.asList(
new EventTicketObject()
.setId(String.format("%s.%s", issuerId, "EVENT_OBJECT_SUFFIX"))
.setClassId(String.format("%s.%s", issuerId, "EVENT_CLASS_SUFFIX"))));
System.out.println("Issuer permissions update response");
System.out.println(response.toPrettyString());
// Boarding passes
objectsToAdd.put(
"flightObjects",
Arrays.asList(
new FlightObject()
.setId(String.format("%s.%s", issuerId, "FLIGHT_OBJECT_SUFFIX"))
.setClassId(String.format("%s.%s", issuerId, "FLIGHT_CLASS_SUFFIX"))));
// Generic passes
objectsToAdd.put(
"genericObjects",
Arrays.asList(
new GenericObject()
.setId(String.format("%s.%s", issuerId, "GENERIC_OBJECT_SUFFIX"))
.setClassId(String.format("%s.%s", issuerId, "GENERIC_CLASS_SUFFIX"))));
// Gift cards
objectsToAdd.put(
"giftCardObjects",
Arrays.asList(
new GiftCardObject()
.setId(String.format("%s.%s", issuerId, "GIFT_CARD_OBJECT_SUFFIX"))
.setClassId(String.format("%s.%s", issuerId, "GIFT_CARD_CLASS_SUFFIX"))));
// Loyalty cards
objectsToAdd.put(
"loyaltyObjects",
Arrays.asList(
new LoyaltyObject()
.setId(String.format("%s.%s", issuerId, "LOYALTY_OBJECT_SUFFIX"))
.setClassId(String.format("%s.%s", issuerId, "LOYALTY_CLASS_SUFFIX"))));
// Offers
objectsToAdd.put(
"offerObjects",
Arrays.asList(
new OfferObject()
.setId(String.format("%s.%s", issuerId, "OFFER_OBJECT_SUFFIX"))
.setClassId(String.format("%s.%s", issuerId, "OFFER_CLASS_SUFFIX"))));
// Transit passes
objectsToAdd.put(
"transitObjects",
Arrays.asList(
new TransitObject()
.setId(String.format("%s.%s", issuerId, "TRANSIT_OBJECT_SUFFIX"))
.setClassId(String.format("%s.%s", issuerId, "TRANSIT_CLASS_SUFFIX"))));
// Create the JWT as a HashMap object
HashMap<String, Object> claims = new HashMap<String, Object>();
claims.put("iss", ((ServiceAccountCredentials) credentials).getClientEmail());
claims.put("aud", "google");
claims.put("origins", Arrays.asList("www.example.com"));
claims.put("typ", "savetowallet");
claims.put("payload", objectsToAdd);
// The service account credentials are used to sign the JWT
Algorithm algorithm =
Algorithm.RSA256(
null, (RSAPrivateKey) ((ServiceAccountCredentials) credentials).getPrivateKey());
String token = JWT.create().withPayload(claims).sign(algorithm);
System.out.println("Add to Google Wallet link");
System.out.println(String.format("https://pay.google.com/gp/v/save/%s", token));
return String.format("https://pay.google.com/gp/v/save/%s", token);
}
// [END updatePermissions]
// [END jwtExisting]
// [START batch]
/**
@@ -422,7 +810,7 @@ public class DemoFlight {
* @param classSuffix Developer-defined unique ID for this pass class.
* @throws IOException
*/
public void BatchCreateFlightObjects(String issuerId, String classSuffix) throws IOException {
public void BatchCreateObjects(String issuerId, String classSuffix) throws IOException {
// Create the batch request client
BatchRequest batch = service.batch(new HttpCredentialsAdapter(credentials));
@@ -431,6 +819,7 @@ public class DemoFlight {
new JsonBatchCallback<FlightObject>() {
// Invoked if the request was successful
public void onSuccess(FlightObject response, HttpHeaders responseHeaders) {
System.out.println("Batch insert response");
System.out.println(response.toString());
}
@@ -442,18 +831,14 @@ public class DemoFlight {
// Example: Generate three new pass objects
for (int i = 0; i < 3; i++) {
// Generate a random user ID
String userId = UUID.randomUUID().toString().replaceAll("[^\\w.-]", "_");
// Generate a random object ID with the user ID
// Should only include alphanumeric characters, '.', '_', or '-'
String objectId = String.format("%s.%s", issuerId, userId);
// Generate a random object suffix
String objectSuffix = UUID.randomUUID().toString().replaceAll("[^\\w.-]", "_");
// See link below for more information on required properties
// https://developers.google.com/wallet/tickets/boarding-passes/rest/v1/flightobject
FlightObject flightObject =
FlightObject batchObject =
new FlightObject()
.setId(objectId)
.setId(String.format("%s.%s", issuerId, objectSuffix))
.setClassId(String.format("%s.%s", issuerId, classSuffix))
.setState("ACTIVE")
.setHeroImage(
@@ -513,7 +898,7 @@ public class DemoFlight {
new BoardingAndSeatingInfo().setBoardingGroup("B").setSeatNumber("42"))
.setReservationInfo(new ReservationInfo().setConfirmationCode("Confirmation code"));
service.flightobject().insert(flightObject).queue(batch, callback);
service.flightobject().insert(batchObject).queue(batch, callback);
}
// Invoke the batch API calls

View File

@@ -49,9 +49,11 @@ public class DemoGeneric {
/** Google Wallet service client. */
public static Walletobjects service;
public DemoGeneric() {
public DemoGeneric() throws Exception {
keyFilePath =
System.getenv().getOrDefault("GOOGLE_APPLICATION_CREDENTIALS", "/path/to/key.json");
Auth();
}
// [END setup]
@@ -71,6 +73,7 @@ public class DemoGeneric {
HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
// Initialize Google Wallet API service
service =
new Walletobjects.Builder(
httpTransport,
@@ -81,81 +84,194 @@ public class DemoGeneric {
}
// [END auth]
// [START class]
// [START createClass]
/**
* Create a class via the API. This can also be done in the Google Pay and Wallet console.
* Create a class.
*
* @param issuerId The issuer ID being used for this request.
* @param classSuffix Developer-defined unique ID for this pass class.
* @return The pass class ID: "{issuerId}.{classSuffix}"
* @throws IOException
*/
public String CreateGenericClass(String issuerId, String classSuffix) throws IOException {
// See link below for more information on required properties
// https://developers.google.com/wallet/generic/rest/v1/genericclass
GenericClass genericClass = new GenericClass().setId(String.format("%s.%s", issuerId, classSuffix));
public String CreateClass(String issuerId, String classSuffix) throws IOException {
// Check if the class exists
try {
GenericClass response = service.genericclass().insert(genericClass).execute();
service.genericclass().get(String.format("%s.%s", issuerId, classSuffix)).execute();
System.out.println("Class insert response");
System.out.println(response.toPrettyString());
return response.getId();
System.out.println(String.format("Class %s.%s already exists!", issuerId, classSuffix));
return String.format("%s.%s", issuerId, classSuffix);
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() == 409) {
System.out.println(String.format("Class %s.%s already exists", issuerId, classSuffix));
if (ex.getStatusCode() != 404) {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, classSuffix);
}
// Something else went wrong
ex.printStackTrace();
return ex.getMessage();
}
}
// [END class]
// [START object]
// See link below for more information on required properties
// https://developers.google.com/wallet/generic/rest/v1/genericclass
GenericClass newClass = new GenericClass().setId(String.format("%s.%s", issuerId, classSuffix));
GenericClass response = service.genericclass().insert(newClass).execute();
System.out.println("Class insert response");
System.out.println(response.toPrettyString());
return response.getId();
}
// [END createClass]
// [START updateClass]
/**
* Create an object via the API.
* Update a class.
*
* <p><strong>Warning:</strong> This replaces all existing class attributes!
*
* @param issuerId The issuer ID being used for this request.
* @param classSuffix Developer-defined unique ID for this pass class.
* @param userId Developer-defined user ID for this object.
* @return The pass object ID: "{issuerId}.{userId}"
* @return The pass class ID: "{issuerId}.{classSuffix}"
* @throws IOException
*/
public String CreateGenericObject(String issuerId, String classSuffix, String userId)
throws IOException {
// Generate the object ID
// Should only include alphanumeric characters, '.', '_', or '-'
String newUserId = userId.replaceAll("[^\\w.-]", "_");
String objectId = String.format("%s.%s", issuerId, newUserId);
public String UpdateClass(String issuerId, String classSuffix) throws IOException {
GenericClass updatedClass;
// Check if the class exists
try {
// Check if the object exists
GenericObject response = service.genericobject().get(objectId).execute();
System.out.println("Object get response");
System.out.println(response.toPrettyString());
return response.getId();
updatedClass =
service.genericclass().get(String.format("%s.%s", issuerId, classSuffix)).execute();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() != 404) {
// Something else went wrong
if (ex.getStatusCode() == 404) {
// Class does not exist
System.out.println(String.format("Class %s.%s not found!", issuerId, classSuffix));
return String.format("%s.%s", issuerId, classSuffix);
} else {
// Something else went wrong...
ex.printStackTrace();
return ex.getMessage();
return String.format("%s.%s", issuerId, classSuffix);
}
}
// Class exists
// Update the class by adding a link
Uri newLink =
new Uri()
.setUri("https://developers.google.com/wallet")
.setDescription("New link description");
if (updatedClass.getLinksModuleData() == null) {
// LinksModuleData was not set on the original object
updatedClass.setLinksModuleData(new LinksModuleData().setUris(new ArrayList<Uri>()));
}
updatedClass.getLinksModuleData().getUris().add(newLink);
GenericClass response =
service
.genericclass()
.update(String.format("%s.%s", issuerId, classSuffix), updatedClass)
.execute();
System.out.println("Class update response");
System.out.println(response.toPrettyString());
return response.getId();
}
// [END updateClass]
// [START patchClass]
/**
* Patch a class.
*
* <p>The PATCH method supports patch semantics.
*
* @param issuerId The issuer ID being used for this request.
* @param classSuffix Developer-defined unique ID for this pass class.
* @return The pass class ID: "{issuerId}.{classSuffix}"
* @throws IOException
*/
public String PatchClass(String issuerId, String classSuffix) throws IOException {
GenericClass existingClass;
// Check if the class exists
try {
existingClass =
service.genericclass().get(String.format("%s.%s", issuerId, classSuffix)).execute();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() == 404) {
// Class does not exist
System.out.println(String.format("Class %s.%s not found!", issuerId, classSuffix));
return String.format("%s.%s", issuerId, classSuffix);
} else {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, classSuffix);
}
}
// Class exists
// Patch the class by adding a homepage
GenericClass patchBody = new GenericClass();
// Class exists
// Update the class by adding a link
Uri newLink =
new Uri()
.setUri("https://developers.google.com/wallet")
.setDescription("New link description");
if (existingClass.getLinksModuleData() == null) {
// LinksModuleData was not set on the original object
patchBody.setLinksModuleData(new LinksModuleData().setUris(new ArrayList<Uri>()));
} else {
patchBody.setLinksModuleData(existingClass.getLinksModuleData());
}
patchBody.getLinksModuleData().getUris().add(newLink);
GenericClass response =
service
.genericclass()
.patch(String.format("%s.%s", issuerId, classSuffix), patchBody)
.execute();
System.out.println("Class patch response");
System.out.println(response.toPrettyString());
return response.getId();
}
// [END patchClass]
// [START createObject]
/**
* Create an object.
*
* @param issuerId The issuer ID being used for this request.
* @param classSuffix Developer-defined unique ID for this pass class.
* @param objectSuffix Developer-defined unique ID for this pass object.
* @return The pass object ID: "{issuerId}.{objectSuffix}"
* @throws IOException
*/
public String CreateObject(String issuerId, String classSuffix, String objectSuffix)
throws IOException {
// Check if the object exists
try {
service.genericobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute();
System.out.println(String.format("Object %s.%s already exists!", issuerId, objectSuffix));
return String.format("%s.%s", issuerId, objectSuffix);
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() != 404) {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, objectSuffix);
}
}
// Object doesn't exist, create it now
// See link below for more information on required properties
// https://developers.google.com/wallet/generic/rest/v1/genericobject
GenericObject genericObject =
GenericObject newObject =
new GenericObject()
.setId(objectId)
.setId(String.format("%s.%s", issuerId, objectSuffix))
.setClassId(String.format("%s.%s", issuerId, classSuffix))
.set("state", "ACTIVE")
.setState("ACTIVE")
.setHeroImage(
new Image()
.setSourceUri(
@@ -225,16 +341,175 @@ public class DemoGeneric {
.setLanguage("en-US")
.setValue("Generic card logo"))));
GenericObject response = service.genericobject().insert(genericObject).execute();
GenericObject response = service.genericobject().insert(newObject).execute();
System.out.println("Object insert response");
System.out.println(response.toPrettyString());
return response.getId();
}
// [END object]
// [END createObject]
// [START jwt]
// [START updateObject]
/**
* Update an object.
*
* <p><strong>Warning:</strong> This replaces all existing object attributes!
*
* @param issuerId The issuer ID being used for this request.
* @param objectSuffix Developer-defined unique ID for this pass object.
* @return The pass object ID: "{issuerId}.{objectSuffix}"
* @throws IOException
*/
public String UpdateObject(String issuerId, String objectSuffix) throws IOException {
GenericObject updatedObject;
// Check if the object exists
try {
updatedObject =
service.genericobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() == 404) {
// Object does not exist
System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix));
return String.format("%s.%s", issuerId, objectSuffix);
} else {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, objectSuffix);
}
}
// Object exists
// Update the object by adding a link
Uri newLink =
new Uri()
.setUri("https://developers.google.com/wallet")
.setDescription("New link description");
if (updatedObject.getLinksModuleData() == null) {
// LinksModuleData was not set on the original object
updatedObject.setLinksModuleData(new LinksModuleData().setUris(Arrays.asList(newLink)));
} else {
updatedObject.getLinksModuleData().getUris().add(newLink);
}
GenericObject response =
service
.genericobject()
.update(String.format("%s.%s", issuerId, objectSuffix), updatedObject)
.execute();
System.out.println("Object update response");
System.out.println(response.toPrettyString());
return response.getId();
}
// [END updateObject]
// [START patchObject]
/**
* Patch an object.
*
* @param issuerId The issuer ID being used for this request.
* @param objectSuffix Developer-defined unique ID for this pass object.
* @return The pass object ID: "{issuerId}.{objectSuffix}"
* @throws IOException
*/
public String PatchObject(String issuerId, String objectSuffix) throws IOException {
GenericObject existingObject;
// Check if the object exists
try {
existingObject =
service.genericobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() == 404) {
// Object does not exist
System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix));
return String.format("%s.%s", issuerId, objectSuffix);
} else {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, objectSuffix);
}
}
// Object exists
// Patch the object by adding a link
Uri newLink =
new Uri()
.setUri("https://developers.google.com/wallet")
.setDescription("New link description");
GenericObject patchBody = new GenericObject();
if (existingObject.getLinksModuleData() == null) {
// LinksModuleData was not set on the original object
patchBody.setLinksModuleData(new LinksModuleData().setUris(new ArrayList<Uri>()));
} else {
patchBody.setLinksModuleData(existingObject.getLinksModuleData());
}
patchBody.getLinksModuleData().getUris().add(newLink);
GenericObject response =
service
.genericobject()
.patch(String.format("%s.%s", issuerId, objectSuffix), patchBody)
.execute();
System.out.println("Object patch response");
System.out.println(response.toPrettyString());
return response.getId();
}
// [END patchObject]
// [START expireObject]
/**
* Expire an object.
*
* <p>Sets the object's state to Expired. If the valid time interval is already set, the pass will
* expire automatically up to 24 hours after.
*
* @param issuerId The issuer ID being used for this request.
* @param objectSuffix Developer-defined unique ID for this pass object.
* @return The pass object ID: "{issuerId}.{objectSuffix}"
* @throws IOException
*/
public String ExpireObject(String issuerId, String objectSuffix) throws IOException {
// Check if the object exists
try {
service.genericobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() == 404) {
// Object does not exist
System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix));
return String.format("%s.%s", issuerId, objectSuffix);
} else {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, objectSuffix);
}
}
// Patch the object, setting the pass as expired
GenericObject patchBody = new GenericObject().setState("EXPIRED");
GenericObject response =
service
.genericobject()
.patch(String.format("%s.%s", issuerId, objectSuffix), patchBody)
.execute();
System.out.println("Object expiration response");
System.out.println(response.toPrettyString());
return response.getId();
}
// [END expireObject]
// [START jwtNew]
/**
* Generate a signed JWT that creates a new pass class and object.
*
@@ -244,26 +519,21 @@ public class DemoGeneric {
*
* @param issuerId The issuer ID being used for this request.
* @param classSuffix Developer-defined unique ID for this pass class.
* @param userId Developer-defined user ID for this object.
* @param objectSuffix Developer-defined unique ID for the pass object.
* @return An "Add to Google Wallet" link.
*/
public String CreateJWTSaveURL(String issuerId, String classSuffix, String userId) {
// Generate the object ID
// Should only include alphanumeric characters, '.', '_', or '-'
String newUserId = userId.replaceAll("[^\\w.-]", "_");
String objectId = String.format("%s.%s", issuerId, newUserId);
public String CreateJWTNewObjects(String issuerId, String classSuffix, String objectSuffix) {
// See link below for more information on required properties
// https://developers.google.com/wallet/generic/rest/v1/genericclass
GenericClass genericClass = new GenericClass().setId(String.format("%s.%s", issuerId, classSuffix));
GenericClass newClass = new GenericClass().setId(String.format("%s.%s", issuerId, classSuffix));
// See link below for more information on required properties
// https://developers.google.com/wallet/generic/rest/v1/genericobject
GenericObject genericObject =
GenericObject newObject =
new GenericObject()
.setId(objectId)
.setId(String.format("%s.%s", issuerId, objectSuffix))
.setClassId(String.format("%s.%s", issuerId, classSuffix))
.set("state", "ACTIVE")
.setState("ACTIVE")
.setHeroImage(
new Image()
.setSourceUri(
@@ -342,8 +612,8 @@ public class DemoGeneric {
// Create the Google Wallet payload and add to the JWT
HashMap<String, Object> payload = new HashMap<String, Object>();
payload.put("genericClasses", Arrays.asList(genericClass));
payload.put("genericObjects", Arrays.asList(genericObject));
payload.put("genericClasses", Arrays.asList(newClass));
payload.put("genericObjects", Arrays.asList(newObject));
claims.put("payload", payload);
// The service account credentials are used to sign the JWT
@@ -357,62 +627,105 @@ public class DemoGeneric {
return String.format("https://pay.google.com/gp/v/save/%s", token);
}
// [END jwt]
// [END jwtNew]
// [START createIssuer]
// [START jwtExisting]
/**
* Create a new Google Wallet issuer account.
* Generate a signed JWT that references an existing pass object.
*
* @param issuerName The issuer's name.
* @param issuerEmail The issuer's email address.
* @throws IOException
*/
public void CreateIssuerAccount(String issuerName, String issuerEmail) throws IOException {
// New issuer information
Issuer issuer =
new Issuer()
.setName(issuerName)
.setContactInfo(new IssuerContactInfo().setEmail(issuerEmail));
Issuer response = service.issuer().insert(issuer).execute();
System.out.println("Issuer insert response");
System.out.println(response.toPrettyString());
}
// [END createIssuer]
// [START updatePermissions]
/**
* Update permissions for an existing Google Wallet issuer account. <strong>Warning:</strong> This
* operation overwrites all existing permissions!
* <p>When the user opens the "Add to Google Wallet" URL and saves the pass to their wallet, the
* pass objects defined in the JWT are added to the user's Google Wallet app. This allows the user
* to save multiple pass objects in one API call.
*
* <p>Example permissions list argument below. Copy the add entry as needed for each email address
* that will need access. Supported values for role are: 'READER', 'WRITER', and 'OWNER'
* <p>The objects to add must follow the below format:
*
* <pre><code>
* ArrayList<Permission> permissions = new ArrayList<Permission>();
* permissions.add(new Permission().setEmailAddress("emailAddress").setRole("OWNER"));
* </code></pre>
* <p>{ 'id': 'ISSUER_ID.OBJECT_SUFFIX', 'classId': 'ISSUER_ID.CLASS_SUFFIX' }
*
* @param issuerId The issuer ID being used for this request.
* @param permissions The list of email addresses and roles to assign.
* @throws IOException
* @return An "Add to Google Wallet" link.
*/
public void UpdateIssuerAccountPermissions(String issuerId, ArrayList<Permission> permissions)
throws IOException {
public String CreateJWTExistingObjects(String issuerId) {
// Multiple pass types can be added at the same time
// At least one type must be specified in the JWT claims
// Note: Make sure to replace the placeholder class and object suffixes
HashMap<String, Object> objectsToAdd = new HashMap<String, Object>();
Permissions response =
service
.permissions()
.update(
Long.parseLong(issuerId),
new Permissions().setIssuerId(Long.parseLong(issuerId)).setPermissions(permissions))
.execute();
// Event tickets
objectsToAdd.put(
"eventTicketObjects",
Arrays.asList(
new EventTicketObject()
.setId(String.format("%s.%s", issuerId, "EVENT_OBJECT_SUFFIX"))
.setClassId(String.format("%s.%s", issuerId, "EVENT_CLASS_SUFFIX"))));
System.out.println("Issuer permissions update response");
System.out.println(response.toPrettyString());
// Boarding passes
objectsToAdd.put(
"flightObjects",
Arrays.asList(
new FlightObject()
.setId(String.format("%s.%s", issuerId, "FLIGHT_OBJECT_SUFFIX"))
.setClassId(String.format("%s.%s", issuerId, "FLIGHT_CLASS_SUFFIX"))));
// Generic passes
objectsToAdd.put(
"genericObjects",
Arrays.asList(
new GenericObject()
.setId(String.format("%s.%s", issuerId, "GENERIC_OBJECT_SUFFIX"))
.setClassId(String.format("%s.%s", issuerId, "GENERIC_CLASS_SUFFIX"))));
// Gift cards
objectsToAdd.put(
"giftCardObjects",
Arrays.asList(
new GiftCardObject()
.setId(String.format("%s.%s", issuerId, "GIFT_CARD_OBJECT_SUFFIX"))
.setClassId(String.format("%s.%s", issuerId, "GIFT_CARD_CLASS_SUFFIX"))));
// Loyalty cards
objectsToAdd.put(
"loyaltyObjects",
Arrays.asList(
new LoyaltyObject()
.setId(String.format("%s.%s", issuerId, "LOYALTY_OBJECT_SUFFIX"))
.setClassId(String.format("%s.%s", issuerId, "LOYALTY_CLASS_SUFFIX"))));
// Offers
objectsToAdd.put(
"offerObjects",
Arrays.asList(
new OfferObject()
.setId(String.format("%s.%s", issuerId, "OFFER_OBJECT_SUFFIX"))
.setClassId(String.format("%s.%s", issuerId, "OFFER_CLASS_SUFFIX"))));
// Transit passes
objectsToAdd.put(
"transitObjects",
Arrays.asList(
new TransitObject()
.setId(String.format("%s.%s", issuerId, "TRANSIT_OBJECT_SUFFIX"))
.setClassId(String.format("%s.%s", issuerId, "TRANSIT_CLASS_SUFFIX"))));
// Create the JWT as a HashMap object
HashMap<String, Object> claims = new HashMap<String, Object>();
claims.put("iss", ((ServiceAccountCredentials) credentials).getClientEmail());
claims.put("aud", "google");
claims.put("origins", Arrays.asList("www.example.com"));
claims.put("typ", "savetowallet");
claims.put("payload", objectsToAdd);
// The service account credentials are used to sign the JWT
Algorithm algorithm =
Algorithm.RSA256(
null, (RSAPrivateKey) ((ServiceAccountCredentials) credentials).getPrivateKey());
String token = JWT.create().withPayload(claims).sign(algorithm);
System.out.println("Add to Google Wallet link");
System.out.println(String.format("https://pay.google.com/gp/v/save/%s", token));
return String.format("https://pay.google.com/gp/v/save/%s", token);
}
// [END updatePermissions]
// [END jwtExisting]
// [START batch]
/**
@@ -422,7 +735,7 @@ public class DemoGeneric {
* @param classSuffix Developer-defined unique ID for this pass class.
* @throws IOException
*/
public void BatchCreateGenericObjects(String issuerId, String classSuffix) throws IOException {
public void BatchCreateObjects(String issuerId, String classSuffix) throws IOException {
// Create the batch request client
BatchRequest batch = service.batch(new HttpCredentialsAdapter(credentials));
@@ -431,6 +744,7 @@ public class DemoGeneric {
new JsonBatchCallback<GenericObject>() {
// Invoked if the request was successful
public void onSuccess(GenericObject response, HttpHeaders responseHeaders) {
System.out.println("Batch insert response");
System.out.println(response.toString());
}
@@ -442,20 +756,16 @@ public class DemoGeneric {
// Example: Generate three new pass objects
for (int i = 0; i < 3; i++) {
// Generate a random user ID
String userId = UUID.randomUUID().toString().replaceAll("[^\\w.-]", "_");
// Generate a random object ID with the user ID
// Should only include alphanumeric characters, '.', '_', or '-'
String objectId = String.format("%s.%s", issuerId, userId);
// Generate a random object suffix
String objectSuffix = UUID.randomUUID().toString().replaceAll("[^\\w.-]", "_");
// See link below for more information on required properties
// https://developers.google.com/wallet/generic/rest/v1/genericobject
GenericObject genericObject =
GenericObject batchObject =
new GenericObject()
.setId(objectId)
.setId(String.format("%s.%s", issuerId, objectSuffix))
.setClassId(String.format("%s.%s", issuerId, classSuffix))
.set("state", "ACTIVE")
.setState("ACTIVE")
.setHeroImage(
new Image()
.setSourceUri(
@@ -527,7 +837,7 @@ public class DemoGeneric {
.setLanguage("en-US")
.setValue("Generic card logo"))));
service.genericobject().insert(genericObject).queue(batch, callback);
service.genericobject().insert(batchObject).queue(batch, callback);
}
// Invoke the batch API calls

View File

@@ -49,9 +49,11 @@ public class DemoGiftCard {
/** Google Wallet service client. */
public static Walletobjects service;
public DemoGiftCard() {
public DemoGiftCard() throws Exception {
keyFilePath =
System.getenv().getOrDefault("GOOGLE_APPLICATION_CREDENTIALS", "/path/to/key.json");
Auth();
}
// [END setup]
@@ -71,6 +73,7 @@ public class DemoGiftCard {
HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
// Initialize Google Wallet API service
service =
new Walletobjects.Builder(
httpTransport,
@@ -81,83 +84,227 @@ public class DemoGiftCard {
}
// [END auth]
// [START class]
// [START createClass]
/**
* Create a class via the API. This can also be done in the Google Pay and Wallet console.
* Create a class.
*
* @param issuerId The issuer ID being used for this request.
* @param classSuffix Developer-defined unique ID for this pass class.
* @return The pass class ID: "{issuerId}.{classSuffix}"
* @throws IOException
*/
public String CreateGiftCardClass(String issuerId, String classSuffix) throws IOException {
public String CreateClass(String issuerId, String classSuffix) throws IOException {
// Check if the class exists
try {
service.giftcardclass().get(String.format("%s.%s", issuerId, classSuffix)).execute();
System.out.println(String.format("Class %s.%s already exists!", issuerId, classSuffix));
return String.format("%s.%s", issuerId, classSuffix);
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() != 404) {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, classSuffix);
}
}
// See link below for more information on required properties
// https://developers.google.com/wallet/retail/gift-cards/rest/v1/giftcardclass
GiftCardClass giftCardClass =
GiftCardClass newClass =
new GiftCardClass()
.setId(String.format("%s.%s", issuerId, classSuffix))
.setIssuerName("Issuer name")
.setReviewStatus("UNDER_REVIEW");
try {
GiftCardClass response = service.giftcardclass().insert(giftCardClass).execute();
GiftCardClass response = service.giftcardclass().insert(newClass).execute();
System.out.println("Class insert response");
System.out.println(response.toPrettyString());
System.out.println("Class insert response");
System.out.println(response.toPrettyString());
return response.getId();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() == 409) {
System.out.println(String.format("Class %s.%s already exists", issuerId, classSuffix));
return String.format("%s.%s", issuerId, classSuffix);
}
// Something else went wrong
ex.printStackTrace();
return ex.getMessage();
}
return response.getId();
}
// [END class]
// [END createClass]
// [START object]
// [START updateClass]
/**
* Create an object via the API.
* Update a class.
*
* <p><strong>Warning:</strong> This replaces all existing class attributes!
*
* @param issuerId The issuer ID being used for this request.
* @param classSuffix Developer-defined unique ID for this pass class.
* @param userId Developer-defined user ID for this object.
* @return The pass object ID: "{issuerId}.{userId}"
* @return The pass class ID: "{issuerId}.{classSuffix}"
* @throws IOException
*/
public String CreateGiftCardObject(String issuerId, String classSuffix, String userId)
throws IOException {
// Generate the object ID
// Should only include alphanumeric characters, '.', '_', or '-'
String newUserId = userId.replaceAll("[^\\w.-]", "_");
String objectId = String.format("%s.%s", issuerId, newUserId);
public String UpdateClass(String issuerId, String classSuffix) throws IOException {
GiftCardClass updatedClass;
// Check if the class exists
try {
// Check if the object exists
GiftCardObject response = service.giftcardobject().get(objectId).execute();
System.out.println("Object get response");
System.out.println(response.toPrettyString());
return response.getId();
updatedClass =
service.giftcardclass().get(String.format("%s.%s", issuerId, classSuffix)).execute();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() != 404) {
// Something else went wrong
if (ex.getStatusCode() == 404) {
// Class does not exist
System.out.println(String.format("Class %s.%s not found!", issuerId, classSuffix));
return String.format("%s.%s", issuerId, classSuffix);
} else {
// Something else went wrong...
ex.printStackTrace();
return ex.getMessage();
return String.format("%s.%s", issuerId, classSuffix);
}
}
// Class exists
// Update the class by adding a homepage
updatedClass.setHomepageUri(
new Uri()
.setUri("https://developers.google.com/wallet")
.setDescription("Homepage description"));
// Note: reviewStatus must be 'UNDER_REVIEW' or 'DRAFT' for updates
updatedClass.setReviewStatus("UNDER_REVIEW");
GiftCardClass response =
service
.giftcardclass()
.update(String.format("%s.%s", issuerId, classSuffix), updatedClass)
.execute();
System.out.println("Class update response");
System.out.println(response.toPrettyString());
return response.getId();
}
// [END updateClass]
// [START patchClass]
/**
* Patch a class.
*
* <p>The PATCH method supports patch semantics.
*
* @param issuerId The issuer ID being used for this request.
* @param classSuffix Developer-defined unique ID for this pass class.
* @return The pass class ID: "{issuerId}.{classSuffix}"
* @throws IOException
*/
public String PatchClass(String issuerId, String classSuffix) throws IOException {
// Check if the class exists
try {
service.giftcardclass().get(String.format("%s.%s", issuerId, classSuffix)).execute();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() == 404) {
// Class does not exist
System.out.println(String.format("Class %s.%s not found!", issuerId, classSuffix));
return String.format("%s.%s", issuerId, classSuffix);
} else {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, classSuffix);
}
}
// Class exists
// Patch the class by adding a homepage
GiftCardClass patchBody =
new GiftCardClass()
.setHomepageUri(
new Uri()
.setUri("https://developers.google.com/wallet")
.setDescription("Homepage description"))
// Note: reviewStatus must be 'UNDER_REVIEW' or 'DRAFT' for updates
.setReviewStatus("UNDER_REVIEW");
GiftCardClass response =
service
.giftcardclass()
.patch(String.format("%s.%s", issuerId, classSuffix), patchBody)
.execute();
System.out.println("Class patch response");
System.out.println(response.toPrettyString());
return response.getId();
}
// [END patchClass]
// [START addMessageClass]
/**
* Add a message to a pass class.
*
* @param issuerId The issuer ID being used for this request.
* @param classSuffix Developer-defined unique ID for this pass class.
* @param header The message header.
* @param body The message body.
* @return The pass class ID: "{issuerId}.{classSuffix}"
* @throws IOException
*/
public String AddClassMessage(String issuerId, String classSuffix, String header, String body)
throws IOException {
// Check if the class exists
try {
service.giftcardclass().get(String.format("%s.%s", issuerId, classSuffix)).execute();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() == 404) {
// Class does not exist
System.out.println(String.format("Class %s.%s not found!", issuerId, classSuffix));
return String.format("%s.%s", issuerId, classSuffix);
} else {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, classSuffix);
}
}
AddMessageRequest message =
new AddMessageRequest().setMessage(new Message().setHeader(header).setBody(body));
GiftCardClassAddMessageResponse response =
service
.giftcardclass()
.addmessage(String.format("%s.%s", issuerId, classSuffix), message)
.execute();
System.out.println("Class addMessage response");
System.out.println(response.toPrettyString());
return String.format("%s.%s", issuerId, classSuffix);
}
// [END addMessageClass]
// [START createObject]
/**
* Create an object.
*
* @param issuerId The issuer ID being used for this request.
* @param classSuffix Developer-defined unique ID for this pass class.
* @param objectSuffix Developer-defined unique ID for this pass object.
* @return The pass object ID: "{issuerId}.{objectSuffix}"
* @throws IOException
*/
public String CreateObject(String issuerId, String classSuffix, String objectSuffix)
throws IOException {
// Check if the object exists
try {
service.giftcardobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute();
System.out.println(String.format("Object %s.%s already exists!", issuerId, objectSuffix));
return String.format("%s.%s", issuerId, objectSuffix);
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() != 404) {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, objectSuffix);
}
}
// Object doesn't exist, create it now
// See link below for more information on required properties
// https://developers.google.com/wallet/retail/gift-cards/rest/v1/giftcardobject
GiftCardObject giftCardObject =
GiftCardObject newObject =
new GiftCardObject()
.setId(objectId)
.setId(String.format("%s.%s", issuerId, objectSuffix))
.setClassId(String.format("%s.%s", issuerId, classSuffix))
.setState("ACTIVE")
.setHeroImage(
@@ -217,16 +364,219 @@ public class DemoGiftCard {
.setBalance(new Money().setMicros(20000000L).setCurrencyCode("USD"))
.setBalanceUpdateTime(new DateTime().setDate("2020-04-12T16:20:50.52-04:00"));
GiftCardObject response = service.giftcardobject().insert(giftCardObject).execute();
GiftCardObject response = service.giftcardobject().insert(newObject).execute();
System.out.println("Object insert response");
System.out.println(response.toPrettyString());
return response.getId();
}
// [END object]
// [END createObject]
// [START jwt]
// [START updateObject]
/**
* Update an object.
*
* <p><strong>Warning:</strong> This replaces all existing object attributes!
*
* @param issuerId The issuer ID being used for this request.
* @param objectSuffix Developer-defined unique ID for this pass object.
* @return The pass object ID: "{issuerId}.{objectSuffix}"
* @throws IOException
*/
public String UpdateObject(String issuerId, String objectSuffix) throws IOException {
GiftCardObject updatedObject;
// Check if the object exists
try {
updatedObject =
service.giftcardobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() == 404) {
// Object does not exist
System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix));
return String.format("%s.%s", issuerId, objectSuffix);
} else {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, objectSuffix);
}
}
// Object exists
// Update the object by adding a link
Uri newLink =
new Uri()
.setUri("https://developers.google.com/wallet")
.setDescription("New link description");
if (updatedObject.getLinksModuleData() == null) {
// LinksModuleData was not set on the original object
updatedObject.setLinksModuleData(new LinksModuleData().setUris(Arrays.asList(newLink)));
} else {
updatedObject.getLinksModuleData().getUris().add(newLink);
}
GiftCardObject response =
service
.giftcardobject()
.update(String.format("%s.%s", issuerId, objectSuffix), updatedObject)
.execute();
System.out.println("Object update response");
System.out.println(response.toPrettyString());
return response.getId();
}
// [END updateObject]
// [START patchObject]
/**
* Patch an object.
*
* @param issuerId The issuer ID being used for this request.
* @param objectSuffix Developer-defined unique ID for this pass object.
* @return The pass object ID: "{issuerId}.{objectSuffix}"
* @throws IOException
*/
public String PatchObject(String issuerId, String objectSuffix) throws IOException {
GiftCardObject existingObject;
// Check if the object exists
try {
existingObject =
service.giftcardobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() == 404) {
// Object does not exist
System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix));
return String.format("%s.%s", issuerId, objectSuffix);
} else {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, objectSuffix);
}
}
// Object exists
// Patch the object by adding a link
Uri newLink =
new Uri()
.setUri("https://developers.google.com/wallet")
.setDescription("New link description");
GiftCardObject patchBody = new GiftCardObject();
if (existingObject.getLinksModuleData() == null) {
// LinksModuleData was not set on the original object
patchBody.setLinksModuleData(new LinksModuleData().setUris(new ArrayList<Uri>()));
} else {
patchBody.setLinksModuleData(existingObject.getLinksModuleData());
}
patchBody.getLinksModuleData().getUris().add(newLink);
GiftCardObject response =
service
.giftcardobject()
.patch(String.format("%s.%s", issuerId, objectSuffix), patchBody)
.execute();
System.out.println("Object patch response");
System.out.println(response.toPrettyString());
return response.getId();
}
// [END patchObject]
// [START expireObject]
/**
* Expire an object.
*
* <p>Sets the object's state to Expired. If the valid time interval is already set, the pass will
* expire automatically up to 24 hours after.
*
* @param issuerId The issuer ID being used for this request.
* @param objectSuffix Developer-defined unique ID for this pass object.
* @return The pass object ID: "{issuerId}.{objectSuffix}"
* @throws IOException
*/
public String ExpireObject(String issuerId, String objectSuffix) throws IOException {
// Check if the object exists
try {
service.giftcardobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() == 404) {
// Object does not exist
System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix));
return String.format("%s.%s", issuerId, objectSuffix);
} else {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, objectSuffix);
}
}
// Patch the object, setting the pass as expired
GiftCardObject patchBody = new GiftCardObject().setState("EXPIRED");
GiftCardObject response =
service
.giftcardobject()
.patch(String.format("%s.%s", issuerId, objectSuffix), patchBody)
.execute();
System.out.println("Object expiration response");
System.out.println(response.toPrettyString());
return response.getId();
}
// [END expireObject]
// [START addMessageObject]
/**
* Add a message to a pass object.
*
* @param issuerId The issuer ID being used for this request.
* @param objectSuffix Developer-defined unique ID for this pass object.
* @param header The message header.
* @param body The message body.
* @return The pass object ID: "{issuerId}.{objectSuffix}"
* @throws IOException
*/
public String AddObjectMessage(String issuerId, String objectSuffix, String header, String body)
throws IOException {
// Check if the object exists
try {
service.giftcardobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() == 404) {
// Object does not exist
System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix));
return String.format("%s.%s", issuerId, objectSuffix);
} else {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, objectSuffix);
}
}
AddMessageRequest message =
new AddMessageRequest().setMessage(new Message().setHeader(header).setBody(body));
GiftCardObjectAddMessageResponse response =
service
.giftcardobject()
.addmessage(String.format("%s.%s", issuerId, objectSuffix), message)
.execute();
System.out.println("Object addMessage response");
System.out.println(response.toPrettyString());
return String.format("%s.%s", issuerId, objectSuffix);
}
// [END addMessageObject]
// [START jwtNew]
/**
* Generate a signed JWT that creates a new pass class and object.
*
@@ -236,18 +586,13 @@ public class DemoGiftCard {
*
* @param issuerId The issuer ID being used for this request.
* @param classSuffix Developer-defined unique ID for this pass class.
* @param userId Developer-defined user ID for this object.
* @param objectSuffix Developer-defined unique ID for the pass object.
* @return An "Add to Google Wallet" link.
*/
public String CreateJWTSaveURL(String issuerId, String classSuffix, String userId) {
// Generate the object ID
// Should only include alphanumeric characters, '.', '_', or '-'
String newUserId = userId.replaceAll("[^\\w.-]", "_");
String objectId = String.format("%s.%s", issuerId, newUserId);
public String CreateJWTNewObjects(String issuerId, String classSuffix, String objectSuffix) {
// See link below for more information on required properties
// https://developers.google.com/wallet/retail/gift-cards/rest/v1/giftcardclass
GiftCardClass giftCardClass =
GiftCardClass newClass =
new GiftCardClass()
.setId(String.format("%s.%s", issuerId, classSuffix))
.setIssuerName("Issuer name")
@@ -255,9 +600,9 @@ public class DemoGiftCard {
// See link below for more information on required properties
// https://developers.google.com/wallet/retail/gift-cards/rest/v1/giftcardobject
GiftCardObject giftCardObject =
GiftCardObject newObject =
new GiftCardObject()
.setId(objectId)
.setId(String.format("%s.%s", issuerId, objectSuffix))
.setClassId(String.format("%s.%s", issuerId, classSuffix))
.setState("ACTIVE")
.setHeroImage(
@@ -326,8 +671,8 @@ public class DemoGiftCard {
// Create the Google Wallet payload and add to the JWT
HashMap<String, Object> payload = new HashMap<String, Object>();
payload.put("giftCardClasses", Arrays.asList(giftCardClass));
payload.put("giftCardObjects", Arrays.asList(giftCardObject));
payload.put("giftCardClasses", Arrays.asList(newClass));
payload.put("giftCardObjects", Arrays.asList(newObject));
claims.put("payload", payload);
// The service account credentials are used to sign the JWT
@@ -341,62 +686,105 @@ public class DemoGiftCard {
return String.format("https://pay.google.com/gp/v/save/%s", token);
}
// [END jwt]
// [END jwtNew]
// [START createIssuer]
// [START jwtExisting]
/**
* Create a new Google Wallet issuer account.
* Generate a signed JWT that references an existing pass object.
*
* @param issuerName The issuer's name.
* @param issuerEmail The issuer's email address.
* @throws IOException
*/
public void CreateIssuerAccount(String issuerName, String issuerEmail) throws IOException {
// New issuer information
Issuer issuer =
new Issuer()
.setName(issuerName)
.setContactInfo(new IssuerContactInfo().setEmail(issuerEmail));
Issuer response = service.issuer().insert(issuer).execute();
System.out.println("Issuer insert response");
System.out.println(response.toPrettyString());
}
// [END createIssuer]
// [START updatePermissions]
/**
* Update permissions for an existing Google Wallet issuer account. <strong>Warning:</strong> This
* operation overwrites all existing permissions!
* <p>When the user opens the "Add to Google Wallet" URL and saves the pass to their wallet, the
* pass objects defined in the JWT are added to the user's Google Wallet app. This allows the user
* to save multiple pass objects in one API call.
*
* <p>Example permissions list argument below. Copy the add entry as needed for each email address
* that will need access. Supported values for role are: 'READER', 'WRITER', and 'OWNER'
* <p>The objects to add must follow the below format:
*
* <pre><code>
* ArrayList<Permission> permissions = new ArrayList<Permission>();
* permissions.add(new Permission().setEmailAddress("emailAddress").setRole("OWNER"));
* </code></pre>
* <p>{ 'id': 'ISSUER_ID.OBJECT_SUFFIX', 'classId': 'ISSUER_ID.CLASS_SUFFIX' }
*
* @param issuerId The issuer ID being used for this request.
* @param permissions The list of email addresses and roles to assign.
* @throws IOException
* @return An "Add to Google Wallet" link.
*/
public void UpdateIssuerAccountPermissions(String issuerId, ArrayList<Permission> permissions)
throws IOException {
public String CreateJWTExistingObjects(String issuerId) {
// Multiple pass types can be added at the same time
// At least one type must be specified in the JWT claims
// Note: Make sure to replace the placeholder class and object suffixes
HashMap<String, Object> objectsToAdd = new HashMap<String, Object>();
Permissions response =
service
.permissions()
.update(
Long.parseLong(issuerId),
new Permissions().setIssuerId(Long.parseLong(issuerId)).setPermissions(permissions))
.execute();
// Event tickets
objectsToAdd.put(
"eventTicketObjects",
Arrays.asList(
new EventTicketObject()
.setId(String.format("%s.%s", issuerId, "EVENT_OBJECT_SUFFIX"))
.setClassId(String.format("%s.%s", issuerId, "EVENT_CLASS_SUFFIX"))));
System.out.println("Issuer permissions update response");
System.out.println(response.toPrettyString());
// Boarding passes
objectsToAdd.put(
"flightObjects",
Arrays.asList(
new FlightObject()
.setId(String.format("%s.%s", issuerId, "FLIGHT_OBJECT_SUFFIX"))
.setClassId(String.format("%s.%s", issuerId, "FLIGHT_CLASS_SUFFIX"))));
// Generic passes
objectsToAdd.put(
"genericObjects",
Arrays.asList(
new GenericObject()
.setId(String.format("%s.%s", issuerId, "GENERIC_OBJECT_SUFFIX"))
.setClassId(String.format("%s.%s", issuerId, "GENERIC_CLASS_SUFFIX"))));
// Gift cards
objectsToAdd.put(
"giftCardObjects",
Arrays.asList(
new GiftCardObject()
.setId(String.format("%s.%s", issuerId, "GIFT_CARD_OBJECT_SUFFIX"))
.setClassId(String.format("%s.%s", issuerId, "GIFT_CARD_CLASS_SUFFIX"))));
// Loyalty cards
objectsToAdd.put(
"loyaltyObjects",
Arrays.asList(
new LoyaltyObject()
.setId(String.format("%s.%s", issuerId, "LOYALTY_OBJECT_SUFFIX"))
.setClassId(String.format("%s.%s", issuerId, "LOYALTY_CLASS_SUFFIX"))));
// Offers
objectsToAdd.put(
"offerObjects",
Arrays.asList(
new OfferObject()
.setId(String.format("%s.%s", issuerId, "OFFER_OBJECT_SUFFIX"))
.setClassId(String.format("%s.%s", issuerId, "OFFER_CLASS_SUFFIX"))));
// Transit passes
objectsToAdd.put(
"transitObjects",
Arrays.asList(
new TransitObject()
.setId(String.format("%s.%s", issuerId, "TRANSIT_OBJECT_SUFFIX"))
.setClassId(String.format("%s.%s", issuerId, "TRANSIT_CLASS_SUFFIX"))));
// Create the JWT as a HashMap object
HashMap<String, Object> claims = new HashMap<String, Object>();
claims.put("iss", ((ServiceAccountCredentials) credentials).getClientEmail());
claims.put("aud", "google");
claims.put("origins", Arrays.asList("www.example.com"));
claims.put("typ", "savetowallet");
claims.put("payload", objectsToAdd);
// The service account credentials are used to sign the JWT
Algorithm algorithm =
Algorithm.RSA256(
null, (RSAPrivateKey) ((ServiceAccountCredentials) credentials).getPrivateKey());
String token = JWT.create().withPayload(claims).sign(algorithm);
System.out.println("Add to Google Wallet link");
System.out.println(String.format("https://pay.google.com/gp/v/save/%s", token));
return String.format("https://pay.google.com/gp/v/save/%s", token);
}
// [END updatePermissions]
// [END jwtExisting]
// [START batch]
/**
@@ -406,7 +794,7 @@ public class DemoGiftCard {
* @param classSuffix Developer-defined unique ID for this pass class.
* @throws IOException
*/
public void BatchCreateGiftCardObjects(String issuerId, String classSuffix) throws IOException {
public void BatchCreateObjects(String issuerId, String classSuffix) throws IOException {
// Create the batch request client
BatchRequest batch = service.batch(new HttpCredentialsAdapter(credentials));
@@ -415,6 +803,7 @@ public class DemoGiftCard {
new JsonBatchCallback<GiftCardObject>() {
// Invoked if the request was successful
public void onSuccess(GiftCardObject response, HttpHeaders responseHeaders) {
System.out.println("Batch insert response");
System.out.println(response.toString());
}
@@ -426,18 +815,14 @@ public class DemoGiftCard {
// Example: Generate three new pass objects
for (int i = 0; i < 3; i++) {
// Generate a random user ID
String userId = UUID.randomUUID().toString().replaceAll("[^\\w.-]", "_");
// Generate a random object ID with the user ID
// Should only include alphanumeric characters, '.', '_', or '-'
String objectId = String.format("%s.%s", issuerId, userId);
// Generate a random object suffix
String objectSuffix = UUID.randomUUID().toString().replaceAll("[^\\w.-]", "_");
// See link below for more information on required properties
// https://developers.google.com/wallet/retail/gift-cards/rest/v1/giftcardobject
GiftCardObject giftCardObject =
GiftCardObject batchObject =
new GiftCardObject()
.setId(objectId)
.setId(String.format("%s.%s", issuerId, objectSuffix))
.setClassId(String.format("%s.%s", issuerId, classSuffix))
.setState("ACTIVE")
.setHeroImage(
@@ -497,7 +882,7 @@ public class DemoGiftCard {
.setBalance(new Money().setMicros(20000000L).setCurrencyCode("USD"))
.setBalanceUpdateTime(new DateTime().setDate("2020-04-12T16:20:50.52-04:00"));
service.giftcardobject().insert(giftCardObject).queue(batch, callback);
service.giftcardobject().insert(batchObject).queue(batch, callback);
}
// Invoke the batch API calls

View File

@@ -49,9 +49,11 @@ public class DemoLoyalty {
/** Google Wallet service client. */
public static Walletobjects service;
public DemoLoyalty() {
public DemoLoyalty() throws Exception {
keyFilePath =
System.getenv().getOrDefault("GOOGLE_APPLICATION_CREDENTIALS", "/path/to/key.json");
Auth();
}
// [END setup]
@@ -71,6 +73,7 @@ public class DemoLoyalty {
HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
// Initialize Google Wallet API service
service =
new Walletobjects.Builder(
httpTransport,
@@ -81,19 +84,33 @@ public class DemoLoyalty {
}
// [END auth]
// [START class]
// [START createClass]
/**
* Create a class via the API. This can also be done in the Google Pay and Wallet console.
* Create a class.
*
* @param issuerId The issuer ID being used for this request.
* @param classSuffix Developer-defined unique ID for this pass class.
* @return The pass class ID: "{issuerId}.{classSuffix}"
* @throws IOException
*/
public String CreateLoyaltyClass(String issuerId, String classSuffix) throws IOException {
public String CreateClass(String issuerId, String classSuffix) throws IOException {
// Check if the class exists
try {
service.loyaltyclass().get(String.format("%s.%s", issuerId, classSuffix)).execute();
System.out.println(String.format("Class %s.%s already exists!", issuerId, classSuffix));
return String.format("%s.%s", issuerId, classSuffix);
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() != 404) {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, classSuffix);
}
}
// See link below for more information on required properties
// https://developers.google.com/wallet/retail/loyalty-cards/rest/v1/loyaltyclass
LoyaltyClass loyaltyClass =
LoyaltyClass newClass =
new LoyaltyClass()
.setId(String.format("%s.%s", issuerId, classSuffix))
.setIssuerName("Issuer name")
@@ -112,65 +129,195 @@ public class DemoLoyalty {
.setLanguage("en-US")
.setValue("Logo description"))));
try {
LoyaltyClass response = service.loyaltyclass().insert(loyaltyClass).execute();
LoyaltyClass response = service.loyaltyclass().insert(newClass).execute();
System.out.println("Class insert response");
System.out.println(response.toPrettyString());
System.out.println("Class insert response");
System.out.println(response.toPrettyString());
return response.getId();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() == 409) {
System.out.println(String.format("Class %s.%s already exists", issuerId, classSuffix));
return String.format("%s.%s", issuerId, classSuffix);
}
// Something else went wrong
ex.printStackTrace();
return ex.getMessage();
}
return response.getId();
}
// [END class]
// [END createClass]
// [START object]
// [START updateClass]
/**
* Create an object via the API.
* Update a class.
*
* <p><strong>Warning:</strong> This replaces all existing class attributes!
*
* @param issuerId The issuer ID being used for this request.
* @param classSuffix Developer-defined unique ID for this pass class.
* @param userId Developer-defined user ID for this object.
* @return The pass object ID: "{issuerId}.{userId}"
* @return The pass class ID: "{issuerId}.{classSuffix}"
* @throws IOException
*/
public String CreateLoyaltyObject(String issuerId, String classSuffix, String userId)
throws IOException {
// Generate the object ID
// Should only include alphanumeric characters, '.', '_', or '-'
String newUserId = userId.replaceAll("[^\\w.-]", "_");
String objectId = String.format("%s.%s", issuerId, newUserId);
public String UpdateClass(String issuerId, String classSuffix) throws IOException {
LoyaltyClass updatedClass;
// Check if the class exists
try {
// Check if the object exists
LoyaltyObject response = service.loyaltyobject().get(objectId).execute();
System.out.println("Object get response");
System.out.println(response.toPrettyString());
return response.getId();
updatedClass =
service.loyaltyclass().get(String.format("%s.%s", issuerId, classSuffix)).execute();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() != 404) {
// Something else went wrong
if (ex.getStatusCode() == 404) {
// Class does not exist
System.out.println(String.format("Class %s.%s not found!", issuerId, classSuffix));
return String.format("%s.%s", issuerId, classSuffix);
} else {
// Something else went wrong...
ex.printStackTrace();
return ex.getMessage();
return String.format("%s.%s", issuerId, classSuffix);
}
}
// Class exists
// Update the class by adding a homepage
updatedClass.setHomepageUri(
new Uri()
.setUri("https://developers.google.com/wallet")
.setDescription("Homepage description"));
// Note: reviewStatus must be 'UNDER_REVIEW' or 'DRAFT' for updates
updatedClass.setReviewStatus("UNDER_REVIEW");
LoyaltyClass response =
service
.loyaltyclass()
.update(String.format("%s.%s", issuerId, classSuffix), updatedClass)
.execute();
System.out.println("Class update response");
System.out.println(response.toPrettyString());
return response.getId();
}
// [END updateClass]
// [START patchClass]
/**
* Patch a class.
*
* <p>The PATCH method supports patch semantics.
*
* @param issuerId The issuer ID being used for this request.
* @param classSuffix Developer-defined unique ID for this pass class.
* @return The pass class ID: "{issuerId}.{classSuffix}"
* @throws IOException
*/
public String PatchClass(String issuerId, String classSuffix) throws IOException {
// Check if the class exists
try {
service.loyaltyclass().get(String.format("%s.%s", issuerId, classSuffix)).execute();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() == 404) {
// Class does not exist
System.out.println(String.format("Class %s.%s not found!", issuerId, classSuffix));
return String.format("%s.%s", issuerId, classSuffix);
} else {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, classSuffix);
}
}
// Class exists
// Patch the class by adding a homepage
LoyaltyClass patchBody =
new LoyaltyClass()
.setHomepageUri(
new Uri()
.setUri("https://developers.google.com/wallet")
.setDescription("Homepage description"))
// Note: reviewStatus must be 'UNDER_REVIEW' or 'DRAFT' for updates
.setReviewStatus("UNDER_REVIEW");
LoyaltyClass response =
service
.loyaltyclass()
.patch(String.format("%s.%s", issuerId, classSuffix), patchBody)
.execute();
System.out.println("Class patch response");
System.out.println(response.toPrettyString());
return response.getId();
}
// [END patchClass]
// [START addMessageClass]
/**
* Add a message to a pass class.
*
* @param issuerId The issuer ID being used for this request.
* @param classSuffix Developer-defined unique ID for this pass class.
* @param header The message header.
* @param body The message body.
* @return The pass class ID: "{issuerId}.{classSuffix}"
* @throws IOException
*/
public String AddClassMessage(String issuerId, String classSuffix, String header, String body)
throws IOException {
// Check if the class exists
try {
service.loyaltyclass().get(String.format("%s.%s", issuerId, classSuffix)).execute();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() == 404) {
// Class does not exist
System.out.println(String.format("Class %s.%s not found!", issuerId, classSuffix));
return String.format("%s.%s", issuerId, classSuffix);
} else {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, classSuffix);
}
}
AddMessageRequest message =
new AddMessageRequest().setMessage(new Message().setHeader(header).setBody(body));
LoyaltyClassAddMessageResponse response =
service
.loyaltyclass()
.addmessage(String.format("%s.%s", issuerId, classSuffix), message)
.execute();
System.out.println("Class addMessage response");
System.out.println(response.toPrettyString());
return String.format("%s.%s", issuerId, classSuffix);
}
// [END addMessageClass]
// [START createObject]
/**
* Create an object.
*
* @param issuerId The issuer ID being used for this request.
* @param classSuffix Developer-defined unique ID for this pass class.
* @param objectSuffix Developer-defined unique ID for this pass object.
* @return The pass object ID: "{issuerId}.{objectSuffix}"
* @throws IOException
*/
public String CreateObject(String issuerId, String classSuffix, String objectSuffix)
throws IOException {
// Check if the object exists
try {
service.loyaltyobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute();
System.out.println(String.format("Object %s.%s already exists!", issuerId, objectSuffix));
return String.format("%s.%s", issuerId, objectSuffix);
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() != 404) {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, objectSuffix);
}
}
// Object doesn't exist, create it now
// See link below for more information on required properties
// https://developers.google.com/wallet/retail/loyalty-cards/rest/v1/loyaltyobject
LoyaltyObject loyaltyObject =
LoyaltyObject newObject =
new LoyaltyObject()
.setId(objectId)
.setId(String.format("%s.%s", issuerId, objectSuffix))
.setClassId(String.format("%s.%s", issuerId, classSuffix))
.setState("ACTIVE")
.setHeroImage(
@@ -232,16 +379,219 @@ public class DemoLoyalty {
.setLabel("Points")
.setBalance(new LoyaltyPointsBalance().setInt(800)));
LoyaltyObject response = service.loyaltyobject().insert(loyaltyObject).execute();
LoyaltyObject response = service.loyaltyobject().insert(newObject).execute();
System.out.println("Object insert response");
System.out.println(response.toPrettyString());
return response.getId();
}
// [END object]
// [END createObject]
// [START jwt]
// [START updateObject]
/**
* Update an object.
*
* <p><strong>Warning:</strong> This replaces all existing object attributes!
*
* @param issuerId The issuer ID being used for this request.
* @param objectSuffix Developer-defined unique ID for this pass object.
* @return The pass object ID: "{issuerId}.{objectSuffix}"
* @throws IOException
*/
public String UpdateObject(String issuerId, String objectSuffix) throws IOException {
LoyaltyObject updatedObject;
// Check if the object exists
try {
updatedObject =
service.loyaltyobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() == 404) {
// Object does not exist
System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix));
return String.format("%s.%s", issuerId, objectSuffix);
} else {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, objectSuffix);
}
}
// Object exists
// Update the object by adding a link
Uri newLink =
new Uri()
.setUri("https://developers.google.com/wallet")
.setDescription("New link description");
if (updatedObject.getLinksModuleData() == null) {
// LinksModuleData was not set on the original object
updatedObject.setLinksModuleData(new LinksModuleData().setUris(Arrays.asList(newLink)));
} else {
updatedObject.getLinksModuleData().getUris().add(newLink);
}
LoyaltyObject response =
service
.loyaltyobject()
.update(String.format("%s.%s", issuerId, objectSuffix), updatedObject)
.execute();
System.out.println("Object update response");
System.out.println(response.toPrettyString());
return response.getId();
}
// [END updateObject]
// [START patchObject]
/**
* Patch an object.
*
* @param issuerId The issuer ID being used for this request.
* @param objectSuffix Developer-defined unique ID for this pass object.
* @return The pass object ID: "{issuerId}.{objectSuffix}"
* @throws IOException
*/
public String PatchObject(String issuerId, String objectSuffix) throws IOException {
LoyaltyObject existingObject;
// Check if the object exists
try {
existingObject =
service.loyaltyobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() == 404) {
// Object does not exist
System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix));
return String.format("%s.%s", issuerId, objectSuffix);
} else {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, objectSuffix);
}
}
// Object exists
// Patch the object by adding a link
Uri newLink =
new Uri()
.setUri("https://developers.google.com/wallet")
.setDescription("New link description");
LoyaltyObject patchBody = new LoyaltyObject();
if (existingObject.getLinksModuleData() == null) {
// LinksModuleData was not set on the original object
patchBody.setLinksModuleData(new LinksModuleData().setUris(new ArrayList<Uri>()));
} else {
patchBody.setLinksModuleData(existingObject.getLinksModuleData());
}
patchBody.getLinksModuleData().getUris().add(newLink);
LoyaltyObject response =
service
.loyaltyobject()
.patch(String.format("%s.%s", issuerId, objectSuffix), patchBody)
.execute();
System.out.println("Object patch response");
System.out.println(response.toPrettyString());
return response.getId();
}
// [END patchObject]
// [START expireObject]
/**
* Expire an object.
*
* <p>Sets the object's state to Expired. If the valid time interval is already set, the pass will
* expire automatically up to 24 hours after.
*
* @param issuerId The issuer ID being used for this request.
* @param objectSuffix Developer-defined unique ID for this pass object.
* @return The pass object ID: "{issuerId}.{objectSuffix}"
* @throws IOException
*/
public String ExpireObject(String issuerId, String objectSuffix) throws IOException {
// Check if the object exists
try {
service.loyaltyobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() == 404) {
// Object does not exist
System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix));
return String.format("%s.%s", issuerId, objectSuffix);
} else {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, objectSuffix);
}
}
// Patch the object, setting the pass as expired
LoyaltyObject patchBody = new LoyaltyObject().setState("EXPIRED");
LoyaltyObject response =
service
.loyaltyobject()
.patch(String.format("%s.%s", issuerId, objectSuffix), patchBody)
.execute();
System.out.println("Object expiration response");
System.out.println(response.toPrettyString());
return response.getId();
}
// [END expireObject]
// [START addMessageObject]
/**
* Add a message to a pass object.
*
* @param issuerId The issuer ID being used for this request.
* @param objectSuffix Developer-defined unique ID for this pass object.
* @param header The message header.
* @param body The message body.
* @return The pass object ID: "{issuerId}.{objectSuffix}"
* @throws IOException
*/
public String AddObjectMessage(String issuerId, String objectSuffix, String header, String body)
throws IOException {
// Check if the object exists
try {
service.loyaltyobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() == 404) {
// Object does not exist
System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix));
return String.format("%s.%s", issuerId, objectSuffix);
} else {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, objectSuffix);
}
}
AddMessageRequest message =
new AddMessageRequest().setMessage(new Message().setHeader(header).setBody(body));
LoyaltyObjectAddMessageResponse response =
service
.loyaltyobject()
.addmessage(String.format("%s.%s", issuerId, objectSuffix), message)
.execute();
System.out.println("Object addMessage response");
System.out.println(response.toPrettyString());
return String.format("%s.%s", issuerId, objectSuffix);
}
// [END addMessageObject]
// [START jwtNew]
/**
* Generate a signed JWT that creates a new pass class and object.
*
@@ -251,18 +601,13 @@ public class DemoLoyalty {
*
* @param issuerId The issuer ID being used for this request.
* @param classSuffix Developer-defined unique ID for this pass class.
* @param userId Developer-defined user ID for this object.
* @param objectSuffix Developer-defined unique ID for the pass object.
* @return An "Add to Google Wallet" link.
*/
public String CreateJWTSaveURL(String issuerId, String classSuffix, String userId) {
// Generate the object ID
// Should only include alphanumeric characters, '.', '_', or '-'
String newUserId = userId.replaceAll("[^\\w.-]", "_");
String objectId = String.format("%s.%s", issuerId, newUserId);
public String CreateJWTNewObjects(String issuerId, String classSuffix, String objectSuffix) {
// See link below for more information on required properties
// https://developers.google.com/wallet/retail/loyalty-cards/rest/v1/loyaltyclass
LoyaltyClass loyaltyClass =
LoyaltyClass newClass =
new LoyaltyClass()
.setId(String.format("%s.%s", issuerId, classSuffix))
.setIssuerName("Issuer name")
@@ -283,9 +628,9 @@ public class DemoLoyalty {
// See link below for more information on required properties
// https://developers.google.com/wallet/retail/loyalty-cards/rest/v1/loyaltyobject
LoyaltyObject loyaltyObject =
LoyaltyObject newObject =
new LoyaltyObject()
.setId(objectId)
.setId(String.format("%s.%s", issuerId, objectSuffix))
.setClassId(String.format("%s.%s", issuerId, classSuffix))
.setState("ACTIVE")
.setHeroImage(
@@ -356,8 +701,8 @@ public class DemoLoyalty {
// Create the Google Wallet payload and add to the JWT
HashMap<String, Object> payload = new HashMap<String, Object>();
payload.put("loyaltyClasses", Arrays.asList(loyaltyClass));
payload.put("loyaltyObjects", Arrays.asList(loyaltyObject));
payload.put("loyaltyClasses", Arrays.asList(newClass));
payload.put("loyaltyObjects", Arrays.asList(newObject));
claims.put("payload", payload);
// The service account credentials are used to sign the JWT
@@ -371,62 +716,105 @@ public class DemoLoyalty {
return String.format("https://pay.google.com/gp/v/save/%s", token);
}
// [END jwt]
// [END jwtNew]
// [START createIssuer]
// [START jwtExisting]
/**
* Create a new Google Wallet issuer account.
* Generate a signed JWT that references an existing pass object.
*
* @param issuerName The issuer's name.
* @param issuerEmail The issuer's email address.
* @throws IOException
*/
public void CreateIssuerAccount(String issuerName, String issuerEmail) throws IOException {
// New issuer information
Issuer issuer =
new Issuer()
.setName(issuerName)
.setContactInfo(new IssuerContactInfo().setEmail(issuerEmail));
Issuer response = service.issuer().insert(issuer).execute();
System.out.println("Issuer insert response");
System.out.println(response.toPrettyString());
}
// [END createIssuer]
// [START updatePermissions]
/**
* Update permissions for an existing Google Wallet issuer account. <strong>Warning:</strong> This
* operation overwrites all existing permissions!
* <p>When the user opens the "Add to Google Wallet" URL and saves the pass to their wallet, the
* pass objects defined in the JWT are added to the user's Google Wallet app. This allows the user
* to save multiple pass objects in one API call.
*
* <p>Example permissions list argument below. Copy the add entry as needed for each email address
* that will need access. Supported values for role are: 'READER', 'WRITER', and 'OWNER'
* <p>The objects to add must follow the below format:
*
* <pre><code>
* ArrayList<Permission> permissions = new ArrayList<Permission>();
* permissions.add(new Permission().setEmailAddress("emailAddress").setRole("OWNER"));
* </code></pre>
* <p>{ 'id': 'ISSUER_ID.OBJECT_SUFFIX', 'classId': 'ISSUER_ID.CLASS_SUFFIX' }
*
* @param issuerId The issuer ID being used for this request.
* @param permissions The list of email addresses and roles to assign.
* @throws IOException
* @return An "Add to Google Wallet" link.
*/
public void UpdateIssuerAccountPermissions(String issuerId, ArrayList<Permission> permissions)
throws IOException {
public String CreateJWTExistingObjects(String issuerId) {
// Multiple pass types can be added at the same time
// At least one type must be specified in the JWT claims
// Note: Make sure to replace the placeholder class and object suffixes
HashMap<String, Object> objectsToAdd = new HashMap<String, Object>();
Permissions response =
service
.permissions()
.update(
Long.parseLong(issuerId),
new Permissions().setIssuerId(Long.parseLong(issuerId)).setPermissions(permissions))
.execute();
// Event tickets
objectsToAdd.put(
"eventTicketObjects",
Arrays.asList(
new EventTicketObject()
.setId(String.format("%s.%s", issuerId, "EVENT_OBJECT_SUFFIX"))
.setClassId(String.format("%s.%s", issuerId, "EVENT_CLASS_SUFFIX"))));
System.out.println("Issuer permissions update response");
System.out.println(response.toPrettyString());
// Boarding passes
objectsToAdd.put(
"flightObjects",
Arrays.asList(
new FlightObject()
.setId(String.format("%s.%s", issuerId, "FLIGHT_OBJECT_SUFFIX"))
.setClassId(String.format("%s.%s", issuerId, "FLIGHT_CLASS_SUFFIX"))));
// Generic passes
objectsToAdd.put(
"genericObjects",
Arrays.asList(
new GenericObject()
.setId(String.format("%s.%s", issuerId, "GENERIC_OBJECT_SUFFIX"))
.setClassId(String.format("%s.%s", issuerId, "GENERIC_CLASS_SUFFIX"))));
// Gift cards
objectsToAdd.put(
"giftCardObjects",
Arrays.asList(
new GiftCardObject()
.setId(String.format("%s.%s", issuerId, "GIFT_CARD_OBJECT_SUFFIX"))
.setClassId(String.format("%s.%s", issuerId, "GIFT_CARD_CLASS_SUFFIX"))));
// Loyalty cards
objectsToAdd.put(
"loyaltyObjects",
Arrays.asList(
new LoyaltyObject()
.setId(String.format("%s.%s", issuerId, "LOYALTY_OBJECT_SUFFIX"))
.setClassId(String.format("%s.%s", issuerId, "LOYALTY_CLASS_SUFFIX"))));
// Offers
objectsToAdd.put(
"offerObjects",
Arrays.asList(
new OfferObject()
.setId(String.format("%s.%s", issuerId, "OFFER_OBJECT_SUFFIX"))
.setClassId(String.format("%s.%s", issuerId, "OFFER_CLASS_SUFFIX"))));
// Transit passes
objectsToAdd.put(
"transitObjects",
Arrays.asList(
new TransitObject()
.setId(String.format("%s.%s", issuerId, "TRANSIT_OBJECT_SUFFIX"))
.setClassId(String.format("%s.%s", issuerId, "TRANSIT_CLASS_SUFFIX"))));
// Create the JWT as a HashMap object
HashMap<String, Object> claims = new HashMap<String, Object>();
claims.put("iss", ((ServiceAccountCredentials) credentials).getClientEmail());
claims.put("aud", "google");
claims.put("origins", Arrays.asList("www.example.com"));
claims.put("typ", "savetowallet");
claims.put("payload", objectsToAdd);
// The service account credentials are used to sign the JWT
Algorithm algorithm =
Algorithm.RSA256(
null, (RSAPrivateKey) ((ServiceAccountCredentials) credentials).getPrivateKey());
String token = JWT.create().withPayload(claims).sign(algorithm);
System.out.println("Add to Google Wallet link");
System.out.println(String.format("https://pay.google.com/gp/v/save/%s", token));
return String.format("https://pay.google.com/gp/v/save/%s", token);
}
// [END updatePermissions]
// [END jwtExisting]
// [START batch]
/**
@@ -436,7 +824,7 @@ public class DemoLoyalty {
* @param classSuffix Developer-defined unique ID for this pass class.
* @throws IOException
*/
public void BatchCreateLoyaltyObjects(String issuerId, String classSuffix) throws IOException {
public void BatchCreateObjects(String issuerId, String classSuffix) throws IOException {
// Create the batch request client
BatchRequest batch = service.batch(new HttpCredentialsAdapter(credentials));
@@ -445,6 +833,7 @@ public class DemoLoyalty {
new JsonBatchCallback<LoyaltyObject>() {
// Invoked if the request was successful
public void onSuccess(LoyaltyObject response, HttpHeaders responseHeaders) {
System.out.println("Batch insert response");
System.out.println(response.toString());
}
@@ -456,18 +845,14 @@ public class DemoLoyalty {
// Example: Generate three new pass objects
for (int i = 0; i < 3; i++) {
// Generate a random user ID
String userId = UUID.randomUUID().toString().replaceAll("[^\\w.-]", "_");
// Generate a random object ID with the user ID
// Should only include alphanumeric characters, '.', '_', or '-'
String objectId = String.format("%s.%s", issuerId, userId);
// Generate a random object suffix
String objectSuffix = UUID.randomUUID().toString().replaceAll("[^\\w.-]", "_");
// See link below for more information on required properties
// https://developers.google.com/wallet/retail/loyalty-cards/rest/v1/loyaltyobject
LoyaltyObject loyaltyObject =
LoyaltyObject batchObject =
new LoyaltyObject()
.setId(objectId)
.setId(String.format("%s.%s", issuerId, objectSuffix))
.setClassId(String.format("%s.%s", issuerId, classSuffix))
.setState("ACTIVE")
.setHeroImage(
@@ -529,7 +914,7 @@ public class DemoLoyalty {
.setLabel("Points")
.setBalance(new LoyaltyPointsBalance().setInt(800)));
service.loyaltyobject().insert(loyaltyObject).queue(batch, callback);
service.loyaltyobject().insert(batchObject).queue(batch, callback);
}
// Invoke the batch API calls

View File

@@ -49,9 +49,11 @@ public class DemoOffer {
/** Google Wallet service client. */
public static Walletobjects service;
public DemoOffer() {
public DemoOffer() throws Exception {
keyFilePath =
System.getenv().getOrDefault("GOOGLE_APPLICATION_CREDENTIALS", "/path/to/key.json");
Auth();
}
// [END setup]
@@ -71,6 +73,7 @@ public class DemoOffer {
HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
// Initialize Google Wallet API service
service =
new Walletobjects.Builder(
httpTransport,
@@ -81,19 +84,33 @@ public class DemoOffer {
}
// [END auth]
// [START class]
// [START createClass]
/**
* Create a class via the API. This can also be done in the Google Pay and Wallet console.
* Create a class.
*
* @param issuerId The issuer ID being used for this request.
* @param classSuffix Developer-defined unique ID for this pass class.
* @return The pass class ID: "{issuerId}.{classSuffix}"
* @throws IOException
*/
public String CreateOfferClass(String issuerId, String classSuffix) throws IOException {
public String CreateClass(String issuerId, String classSuffix) throws IOException {
// Check if the class exists
try {
service.offerclass().get(String.format("%s.%s", issuerId, classSuffix)).execute();
System.out.println(String.format("Class %s.%s already exists!", issuerId, classSuffix));
return String.format("%s.%s", issuerId, classSuffix);
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() != 404) {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, classSuffix);
}
}
// See link below for more information on required properties
// https://developers.google.com/wallet/retail/offers/rest/v1/offerclass
OfferClass offerClass =
OfferClass newClass =
new OfferClass()
.setId(String.format("%s.%s", issuerId, classSuffix))
.setIssuerName("Issuer name")
@@ -102,65 +119,198 @@ public class DemoOffer {
.setTitle("Offer title")
.setRedemptionChannel("ONLINE");
try {
OfferClass response = service.offerclass().insert(offerClass).execute();
OfferClass response = service.offerclass().insert(newClass).execute();
System.out.println("Class insert response");
System.out.println(response.toPrettyString());
System.out.println("Class insert response");
System.out.println(response.toPrettyString());
return response.getId();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() == 409) {
System.out.println(String.format("Class %s.%s already exists", issuerId, classSuffix));
return String.format("%s.%s", issuerId, classSuffix);
}
// Something else went wrong
ex.printStackTrace();
return ex.getMessage();
}
return response.getId();
}
// [END class]
// [END createClass]
// [START object]
// [START updateClass]
/**
* Create an object via the API.
* Update a class.
*
* <p><strong>Warning:</strong> This replaces all existing class attributes!
*
* @param issuerId The issuer ID being used for this request.
* @param classSuffix Developer-defined unique ID for this pass class.
* @param userId Developer-defined user ID for this object.
* @return The pass object ID: "{issuerId}.{userId}"
* @return The pass class ID: "{issuerId}.{classSuffix}"
* @throws IOException
*/
public String CreateOfferObject(String issuerId, String classSuffix, String userId)
throws IOException {
// Generate the object ID
// Should only include alphanumeric characters, '.', '_', or '-'
String newUserId = userId.replaceAll("[^\\w.-]", "_");
String objectId = String.format("%s.%s", issuerId, newUserId);
public String UpdateClass(String issuerId, String classSuffix) throws IOException {
OfferClass updatedClass;
// Check if the class exists
try {
// Check if the object exists
OfferObject response = service.offerobject().get(objectId).execute();
System.out.println("Object get response");
System.out.println(response.toPrettyString());
return response.getId();
updatedClass =
service.offerclass().get(String.format("%s.%s", issuerId, classSuffix)).execute();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() != 404) {
// Something else went wrong
if (ex.getStatusCode() == 404) {
// Class does not exist
System.out.println(String.format("Class %s.%s not found!", issuerId, classSuffix));
return String.format("%s.%s", issuerId, classSuffix);
} else {
// Something else went wrong...
ex.printStackTrace();
return ex.getMessage();
return String.format("%s.%s", issuerId, classSuffix);
}
}
// Class exists
// Update the class by adding a homepage
updatedClass.setHomepageUri(
new Uri()
.setUri("https://developers.google.com/wallet")
.setDescription("Homepage description"));
// Note: reviewStatus must be 'UNDER_REVIEW' or 'DRAFT' for updates
updatedClass.setReviewStatus("UNDER_REVIEW");
OfferClass response =
service
.offerclass()
.update(String.format("%s.%s", issuerId, classSuffix), updatedClass)
.execute();
System.out.println("Class update response");
System.out.println(response.toPrettyString());
return response.getId();
}
// [END updateClass]
// [START patchClass]
/**
* Patch a class.
*
* <p>The PATCH method supports patch semantics.
*
* @param issuerId The issuer ID being used for this request.
* @param classSuffix Developer-defined unique ID for this pass class.
* @return The pass class ID: "{issuerId}.{classSuffix}"
* @throws IOException
*/
public String PatchClass(String issuerId, String classSuffix) throws IOException {
// Check if the class exists
try {
service.offerclass().get(String.format("%s.%s", issuerId, classSuffix)).execute();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() == 404) {
// Class does not exist
System.out.println(String.format("Class %s.%s not found!", issuerId, classSuffix));
return String.format("%s.%s", issuerId, classSuffix);
} else {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, classSuffix);
}
}
// Class exists
// Patch the class by adding a homepage
OfferClass patchBody =
new OfferClass()
.setHomepageUri(
new Uri()
.setUri("https://developers.google.com/wallet")
.setDescription("Homepage description"))
// Note: reviewStatus must be 'UNDER_REVIEW' or 'DRAFT' for updates
.setReviewStatus("UNDER_REVIEW");
OfferClass response =
service
.offerclass()
.patch(String.format("%s.%s", issuerId, classSuffix), patchBody)
.execute();
System.out.println("Class patch response");
System.out.println(response.toPrettyString());
return response.getId();
}
// [END patchClass]
// [START addMessageClass]
/**
* Add a message to a pass class.
*
* @param issuerId The issuer ID being used for this request.
* @param classSuffix Developer-defined unique ID for this pass class.
* @param header The message header.
* @param body The message body.
* @return The pass class ID: "{issuerId}.{classSuffix}"
* @throws IOException
*/
public String AddClassMessage(String issuerId, String classSuffix, String header, String body)
throws IOException {
// Check if the class exists
try {
service.offerclass().get(String.format("%s.%s", issuerId, classSuffix)).execute();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() == 404) {
// Class does not exist
System.out.println(String.format("Class %s.%s not found!", issuerId, classSuffix));
return String.format("%s.%s", issuerId, classSuffix);
} else {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, classSuffix);
}
}
AddMessageRequest message =
new AddMessageRequest().setMessage(new Message().setHeader(header).setBody(body));
OfferClassAddMessageResponse response =
service
.offerclass()
.addmessage(String.format("%s.%s", issuerId, classSuffix), message)
.execute();
System.out.println("Class addMessage response");
System.out.println(response.toPrettyString());
return String.format("%s.%s", issuerId, classSuffix);
}
// [END addMessageClass]
// [START createObject]
/**
* Create an object.
*
* @param issuerId The issuer ID being used for this request.
* @param classSuffix Developer-defined unique ID for this pass class.
* @param objectSuffix Developer-defined unique ID for this pass object.
* @return The pass object ID: "{issuerId}.{objectSuffix}"
* @throws IOException
*/
public String CreateObject(String issuerId, String classSuffix, String objectSuffix)
throws IOException {
// Check if the object exists
try {
service.offerobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute();
System.out.println(String.format("Object %s.%s already exists!", issuerId, objectSuffix));
return String.format("%s.%s", issuerId, objectSuffix);
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() == 404) {
// Object does not exist
// Do nothing
} else {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, objectSuffix);
}
}
// Object doesn't exist, create it now
// See link below for more information on required properties
// https://developers.google.com/wallet/retail/offers/rest/v1/offerobject
OfferObject offerObject =
OfferObject newObject =
new OfferObject()
.setId(objectId)
.setId(String.format("%s.%s", issuerId, objectSuffix))
.setClassId(String.format("%s.%s", issuerId, classSuffix))
.setState("ACTIVE")
.setHeroImage(
@@ -220,16 +370,219 @@ public class DemoOffer {
.setStart(new DateTime().setDate("2023-06-12T23:20:50.52Z"))
.setEnd(new DateTime().setDate("2023-12-12T23:20:50.52Z")));
OfferObject response = service.offerobject().insert(offerObject).execute();
OfferObject response = service.offerobject().insert(newObject).execute();
System.out.println("Object insert response");
System.out.println(response.toPrettyString());
return response.getId();
}
// [END object]
// [END createObject]
// [START jwt]
// [START updateObject]
/**
* Update an object.
*
* <p><strong>Warning:</strong> This replaces all existing object attributes!
*
* @param issuerId The issuer ID being used for this request.
* @param objectSuffix Developer-defined unique ID for this pass object.
* @return The pass object ID: "{issuerId}.{objectSuffix}"
* @throws IOException
*/
public String UpdateObject(String issuerId, String objectSuffix) throws IOException {
OfferObject updatedObject;
// Check if the object exists
try {
updatedObject =
service.offerobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() == 404) {
// Object does not exist
System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix));
return String.format("%s.%s", issuerId, objectSuffix);
} else {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, objectSuffix);
}
}
// Object exists
// Update the object by adding a link
Uri newLink =
new Uri()
.setUri("https://developers.google.com/wallet")
.setDescription("New link description");
if (updatedObject.getLinksModuleData() == null) {
// LinksModuleData was not set on the original object
updatedObject.setLinksModuleData(new LinksModuleData().setUris(Arrays.asList(newLink)));
} else {
updatedObject.getLinksModuleData().getUris().add(newLink);
}
OfferObject response =
service
.offerobject()
.update(String.format("%s.%s", issuerId, objectSuffix), updatedObject)
.execute();
System.out.println("Object update response");
System.out.println(response.toPrettyString());
return response.getId();
}
// [END updateObject]
// [START patchObject]
/**
* Patch an object.
*
* @param issuerId The issuer ID being used for this request.
* @param objectSuffix Developer-defined unique ID for this pass object.
* @return The pass object ID: "{issuerId}.{objectSuffix}"
* @throws IOException
*/
public String PatchObject(String issuerId, String objectSuffix) throws IOException {
OfferObject existingObject;
// Check if the object exists
try {
existingObject =
service.offerobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() == 404) {
// Object does not exist
System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix));
return String.format("%s.%s", issuerId, objectSuffix);
} else {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, objectSuffix);
}
}
// Object exists
// Patch the object by adding a link
Uri newLink =
new Uri()
.setUri("https://developers.google.com/wallet")
.setDescription("New link description");
OfferObject patchBody = new OfferObject();
if (existingObject.getLinksModuleData() == null) {
// LinksModuleData was not set on the original object
patchBody.setLinksModuleData(new LinksModuleData().setUris(new ArrayList<Uri>()));
} else {
patchBody.setLinksModuleData(existingObject.getLinksModuleData());
}
patchBody.getLinksModuleData().getUris().add(newLink);
OfferObject response =
service
.offerobject()
.patch(String.format("%s.%s", issuerId, objectSuffix), patchBody)
.execute();
System.out.println("Object patch response");
System.out.println(response.toPrettyString());
return response.getId();
}
// [END patchObject]
// [START expireObject]
/**
* Expire an object.
*
* <p>Sets the object's state to Expired. If the valid time interval is already set, the pass will
* expire automatically up to 24 hours after.
*
* @param issuerId The issuer ID being used for this request.
* @param objectSuffix Developer-defined unique ID for this pass object.
* @return The pass object ID: "{issuerId}.{objectSuffix}"
* @throws IOException
*/
public String ExpireObject(String issuerId, String objectSuffix) throws IOException {
// Check if the object exists
try {
service.offerobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() == 404) {
// Object does not exist
System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix));
return String.format("%s.%s", issuerId, objectSuffix);
} else {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, objectSuffix);
}
}
// Patch the object, setting the pass as expired
OfferObject patchBody = new OfferObject().setState("EXPIRED");
OfferObject response =
service
.offerobject()
.patch(String.format("%s.%s", issuerId, objectSuffix), patchBody)
.execute();
System.out.println("Object expiration response");
System.out.println(response.toPrettyString());
return response.getId();
}
// [END expireObject]
// [START addMessageObject]
/**
* Add a message to a pass object.
*
* @param issuerId The issuer ID being used for this request.
* @param objectSuffix Developer-defined unique ID for this pass object.
* @param header The message header.
* @param body The message body.
* @return The pass object ID: "{issuerId}.{objectSuffix}"
* @throws IOException
*/
public String AddObjectMessage(String issuerId, String objectSuffix, String header, String body)
throws IOException {
// Check if the object exists
try {
service.offerobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() == 404) {
// Object does not exist
System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix));
return String.format("%s.%s", issuerId, objectSuffix);
} else {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, objectSuffix);
}
}
AddMessageRequest message =
new AddMessageRequest().setMessage(new Message().setHeader(header).setBody(body));
OfferObjectAddMessageResponse response =
service
.offerobject()
.addmessage(String.format("%s.%s", issuerId, objectSuffix), message)
.execute();
System.out.println("Object addMessage response");
System.out.println(response.toPrettyString());
return String.format("%s.%s", issuerId, objectSuffix);
}
// [END addMessageObject]
// [START jwtNew]
/**
* Generate a signed JWT that creates a new pass class and object.
*
@@ -239,18 +592,13 @@ public class DemoOffer {
*
* @param issuerId The issuer ID being used for this request.
* @param classSuffix Developer-defined unique ID for this pass class.
* @param userId Developer-defined user ID for this object.
* @param objectSuffix Developer-defined unique ID for the pass object.
* @return An "Add to Google Wallet" link.
*/
public String CreateJWTSaveURL(String issuerId, String classSuffix, String userId) {
// Generate the object ID
// Should only include alphanumeric characters, '.', '_', or '-'
String newUserId = userId.replaceAll("[^\\w.-]", "_");
String objectId = String.format("%s.%s", issuerId, newUserId);
public String CreateJWTNewObjects(String issuerId, String classSuffix, String objectSuffix) {
// See link below for more information on required properties
// https://developers.google.com/wallet/retail/offers/rest/v1/offerclass
OfferClass offerClass =
OfferClass newClass =
new OfferClass()
.setId(String.format("%s.%s", issuerId, classSuffix))
.setIssuerName("Issuer name")
@@ -261,9 +609,9 @@ public class DemoOffer {
// See link below for more information on required properties
// https://developers.google.com/wallet/retail/offers/rest/v1/offerobject
OfferObject offerObject =
OfferObject newObject =
new OfferObject()
.setId(objectId)
.setId(String.format("%s.%s", issuerId, objectSuffix))
.setClassId(String.format("%s.%s", issuerId, classSuffix))
.setState("ACTIVE")
.setHeroImage(
@@ -332,8 +680,8 @@ public class DemoOffer {
// Create the Google Wallet payload and add to the JWT
HashMap<String, Object> payload = new HashMap<String, Object>();
payload.put("offerClasses", Arrays.asList(offerClass));
payload.put("offerObjects", Arrays.asList(offerObject));
payload.put("offerClasses", Arrays.asList(newClass));
payload.put("offerObjects", Arrays.asList(newObject));
claims.put("payload", payload);
// The service account credentials are used to sign the JWT
@@ -347,62 +695,105 @@ public class DemoOffer {
return String.format("https://pay.google.com/gp/v/save/%s", token);
}
// [END jwt]
// [END jwtNew]
// [START createIssuer]
// [START jwtExisting]
/**
* Create a new Google Wallet issuer account.
* Generate a signed JWT that references an existing pass object.
*
* @param issuerName The issuer's name.
* @param issuerEmail The issuer's email address.
* @throws IOException
*/
public void CreateIssuerAccount(String issuerName, String issuerEmail) throws IOException {
// New issuer information
Issuer issuer =
new Issuer()
.setName(issuerName)
.setContactInfo(new IssuerContactInfo().setEmail(issuerEmail));
Issuer response = service.issuer().insert(issuer).execute();
System.out.println("Issuer insert response");
System.out.println(response.toPrettyString());
}
// [END createIssuer]
// [START updatePermissions]
/**
* Update permissions for an existing Google Wallet issuer account. <strong>Warning:</strong> This
* operation overwrites all existing permissions!
* <p>When the user opens the "Add to Google Wallet" URL and saves the pass to their wallet, the
* pass objects defined in the JWT are added to the user's Google Wallet app. This allows the user
* to save multiple pass objects in one API call.
*
* <p>Example permissions list argument below. Copy the add entry as needed for each email address
* that will need access. Supported values for role are: 'READER', 'WRITER', and 'OWNER'
* <p>The objects to add must follow the below format:
*
* <pre><code>
* ArrayList<Permission> permissions = new ArrayList<Permission>();
* permissions.add(new Permission().setEmailAddress("emailAddress").setRole("OWNER"));
* </code></pre>
* <p>{ 'id': 'ISSUER_ID.OBJECT_SUFFIX', 'classId': 'ISSUER_ID.CLASS_SUFFIX' }
*
* @param issuerId The issuer ID being used for this request.
* @param permissions The list of email addresses and roles to assign.
* @throws IOException
* @return An "Add to Google Wallet" link.
*/
public void UpdateIssuerAccountPermissions(String issuerId, ArrayList<Permission> permissions)
throws IOException {
public String CreateJWTExistingObjects(String issuerId) {
// Multiple pass types can be added at the same time
// At least one type must be specified in the JWT claims
// Note: Make sure to replace the placeholder class and object suffixes
HashMap<String, Object> objectsToAdd = new HashMap<String, Object>();
Permissions response =
service
.permissions()
.update(
Long.parseLong(issuerId),
new Permissions().setIssuerId(Long.parseLong(issuerId)).setPermissions(permissions))
.execute();
// Event tickets
objectsToAdd.put(
"eventTicketObjects",
Arrays.asList(
new EventTicketObject()
.setId(String.format("%s.%s", issuerId, "EVENT_OBJECT_SUFFIX"))
.setClassId(String.format("%s.%s", issuerId, "EVENT_CLASS_SUFFIX"))));
System.out.println("Issuer permissions update response");
System.out.println(response.toPrettyString());
// Boarding passes
objectsToAdd.put(
"flightObjects",
Arrays.asList(
new FlightObject()
.setId(String.format("%s.%s", issuerId, "FLIGHT_OBJECT_SUFFIX"))
.setClassId(String.format("%s.%s", issuerId, "FLIGHT_CLASS_SUFFIX"))));
// Generic passes
objectsToAdd.put(
"genericObjects",
Arrays.asList(
new GenericObject()
.setId(String.format("%s.%s", issuerId, "GENERIC_OBJECT_SUFFIX"))
.setClassId(String.format("%s.%s", issuerId, "GENERIC_CLASS_SUFFIX"))));
// Gift cards
objectsToAdd.put(
"giftCardObjects",
Arrays.asList(
new GiftCardObject()
.setId(String.format("%s.%s", issuerId, "GIFT_CARD_OBJECT_SUFFIX"))
.setClassId(String.format("%s.%s", issuerId, "GIFT_CARD_CLASS_SUFFIX"))));
// Loyalty cards
objectsToAdd.put(
"loyaltyObjects",
Arrays.asList(
new LoyaltyObject()
.setId(String.format("%s.%s", issuerId, "LOYALTY_OBJECT_SUFFIX"))
.setClassId(String.format("%s.%s", issuerId, "LOYALTY_CLASS_SUFFIX"))));
// Offers
objectsToAdd.put(
"offerObjects",
Arrays.asList(
new OfferObject()
.setId(String.format("%s.%s", issuerId, "OFFER_OBJECT_SUFFIX"))
.setClassId(String.format("%s.%s", issuerId, "OFFER_CLASS_SUFFIX"))));
// Transit passes
objectsToAdd.put(
"transitObjects",
Arrays.asList(
new TransitObject()
.setId(String.format("%s.%s", issuerId, "TRANSIT_OBJECT_SUFFIX"))
.setClassId(String.format("%s.%s", issuerId, "TRANSIT_CLASS_SUFFIX"))));
// Create the JWT as a HashMap object
HashMap<String, Object> claims = new HashMap<String, Object>();
claims.put("iss", ((ServiceAccountCredentials) credentials).getClientEmail());
claims.put("aud", "google");
claims.put("origins", Arrays.asList("www.example.com"));
claims.put("typ", "savetowallet");
claims.put("payload", objectsToAdd);
// The service account credentials are used to sign the JWT
Algorithm algorithm =
Algorithm.RSA256(
null, (RSAPrivateKey) ((ServiceAccountCredentials) credentials).getPrivateKey());
String token = JWT.create().withPayload(claims).sign(algorithm);
System.out.println("Add to Google Wallet link");
System.out.println(String.format("https://pay.google.com/gp/v/save/%s", token));
return String.format("https://pay.google.com/gp/v/save/%s", token);
}
// [END updatePermissions]
// [END jwtExisting]
// [START batch]
/**
@@ -412,7 +803,7 @@ public class DemoOffer {
* @param classSuffix Developer-defined unique ID for this pass class.
* @throws IOException
*/
public void BatchCreateOfferObjects(String issuerId, String classSuffix) throws IOException {
public void BatchCreateObjects(String issuerId, String classSuffix) throws IOException {
// Create the batch request client
BatchRequest batch = service.batch(new HttpCredentialsAdapter(credentials));
@@ -421,6 +812,7 @@ public class DemoOffer {
new JsonBatchCallback<OfferObject>() {
// Invoked if the request was successful
public void onSuccess(OfferObject response, HttpHeaders responseHeaders) {
System.out.println("Batch insert response");
System.out.println(response.toString());
}
@@ -432,18 +824,14 @@ public class DemoOffer {
// Example: Generate three new pass objects
for (int i = 0; i < 3; i++) {
// Generate a random user ID
String userId = UUID.randomUUID().toString().replaceAll("[^\\w.-]", "_");
// Generate a random object ID with the user ID
// Should only include alphanumeric characters, '.', '_', or '-'
String objectId = String.format("%s.%s", issuerId, userId);
// Generate a random object suffix
String objectSuffix = UUID.randomUUID().toString().replaceAll("[^\\w.-]", "_");
// See link below for more information on required properties
// https://developers.google.com/wallet/retail/offers/rest/v1/offerobject
OfferObject offerObject =
OfferObject batchObject =
new OfferObject()
.setId(objectId)
.setId(String.format("%s.%s", issuerId, objectSuffix))
.setClassId(String.format("%s.%s", issuerId, classSuffix))
.setState("ACTIVE")
.setHeroImage(
@@ -503,7 +891,7 @@ public class DemoOffer {
.setStart(new DateTime().setDate("2023-06-12T23:20:50.52Z"))
.setEnd(new DateTime().setDate("2023-12-12T23:20:50.52Z")));
service.offerobject().insert(offerObject).queue(batch, callback);
service.offerobject().insert(batchObject).queue(batch, callback);
}
// Invoke the batch API calls

View File

@@ -40,17 +40,19 @@ public class DemoTransit {
* Path to service account key file from Google Cloud Console. Environment variable:
* GOOGLE_APPLICATION_CREDENTIALS.
*/
public String keyFilePath;
public static String keyFilePath;
/** Service account credentials for Google Wallet APIs. */
public GoogleCredentials credentials;
public static GoogleCredentials credentials;
/** Google Wallet service client. */
public Walletobjects service;
public static Walletobjects service;
public DemoTransit() {
public DemoTransit() throws Exception {
keyFilePath =
System.getenv().getOrDefault("GOOGLE_APPLICATION_CREDENTIALS", "/path/to/key.json");
Auth();
}
// [END setup]
@@ -70,6 +72,7 @@ public class DemoTransit {
HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
// Initialize Google Wallet API service
service =
new Walletobjects.Builder(
httpTransport,
@@ -80,19 +83,33 @@ public class DemoTransit {
}
// [END auth]
// [START class]
// [START createClass]
/**
* Create a class via the API. This can also be done in the Google Pay and Wallet console.
* Create a class.
*
* @param issuerId The issuer ID being used for this request.
* @param classSuffix Developer-defined unique ID for this pass class.
* @return The pass class ID: "{issuerId}.{classSuffix}"
* @throws IOException
*/
public String CreateTransitClass(String issuerId, String classSuffix) throws IOException {
public String CreateClass(String issuerId, String classSuffix) throws IOException {
// Check if the class exists
try {
service.transitclass().get(String.format("%s.%s", issuerId, classSuffix)).execute();
System.out.println(String.format("Class %s.%s already exists!", issuerId, classSuffix));
return String.format("%s.%s", issuerId, classSuffix);
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() != 404) {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, classSuffix);
}
}
// See link below for more information on required properties
// https://developers.google.com/wallet/tickets/transit-passes/qr-code/rest/v1/transitclass
TransitClass transitClass =
TransitClass newClass =
new TransitClass()
.setId(String.format("%s.%s", issuerId, classSuffix))
.setIssuerName("Issuer name")
@@ -111,65 +128,198 @@ public class DemoTransit {
.setValue("Logo description"))))
.setTransitType("BUS");
try {
TransitClass response = service.transitclass().insert(transitClass).execute();
TransitClass response = service.transitclass().insert(newClass).execute();
System.out.println("Class insert response");
System.out.println(response.toPrettyString());
System.out.println("Class insert response");
System.out.println(response.toPrettyString());
return response.getId();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() == 409) {
System.out.println(String.format("Class %s.%s already exists", issuerId, classSuffix));
return String.format("%s.%s", issuerId, classSuffix);
}
// Something else went wrong
ex.printStackTrace();
return ex.getMessage();
}
return response.getId();
}
// [END class]
// [END createClass]
// [START object]
// [START updateClass]
/**
* Create an object via the API.
* Update a class.
*
* <p><strong>Warning:</strong> This replaces all existing class attributes!
*
* @param issuerId The issuer ID being used for this request.
* @param classSuffix Developer-defined unique ID for this pass class.
* @param userId Developer-defined user ID for this object.
* @return The pass object ID: "{issuerId}.{userId}"
* @return The pass class ID: "{issuerId}.{classSuffix}"
* @throws IOException
*/
public String CreateTransitObject(String issuerId, String classSuffix, String userId)
throws IOException {
// Generate the object ID
// Should only include alphanumeric characters, '.', '_', or '-'
String newUserId = userId.replaceAll("[^\\w.-]", "_");
String objectId = String.format("%s.%s", issuerId, newUserId);
public String UpdateClass(String issuerId, String classSuffix) throws IOException {
TransitClass updatedClass;
// Check if the class exists
try {
// Check if the object exists
TransitObject response = service.transitobject().get(objectId).execute();
System.out.println("Object get response");
System.out.println(response.toPrettyString());
return response.getId();
updatedClass =
service.transitclass().get(String.format("%s.%s", issuerId, classSuffix)).execute();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() != 404) {
// Something else went wrong
if (ex.getStatusCode() == 404) {
// Class does not exist
System.out.println(String.format("Class %s.%s not found!", issuerId, classSuffix));
return String.format("%s.%s", issuerId, classSuffix);
} else {
// Something else went wrong...
ex.printStackTrace();
return ex.getMessage();
return String.format("%s.%s", issuerId, classSuffix);
}
}
// Class exists
// Update the class by adding a homepage
updatedClass.setHomepageUri(
new Uri()
.setUri("https://developers.google.com/wallet")
.setDescription("Homepage description"));
// Note: reviewStatus must be 'UNDER_REVIEW' or 'DRAFT' for updates
updatedClass.setReviewStatus("UNDER_REVIEW");
TransitClass response =
service
.transitclass()
.update(String.format("%s.%s", issuerId, classSuffix), updatedClass)
.execute();
System.out.println("Class update response");
System.out.println(response.toPrettyString());
return response.getId();
}
// [END updateClass]
// [START patchClass]
/**
* Patch a class.
*
* <p>The PATCH method supports patch semantics.
*
* @param issuerId The issuer ID being used for this request.
* @param classSuffix Developer-defined unique ID for this pass class.
* @return The pass class ID: "{issuerId}.{classSuffix}"
* @throws IOException
*/
public String PatchClass(String issuerId, String classSuffix) throws IOException {
// Check if the class exists
try {
service.transitclass().get(String.format("%s.%s", issuerId, classSuffix)).execute();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() == 404) {
// Class does not exist
System.out.println(String.format("Class %s.%s not found!", issuerId, classSuffix));
return String.format("%s.%s", issuerId, classSuffix);
} else {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, classSuffix);
}
}
// Class exists
// Patch the class by adding a homepage
TransitClass patchBody =
new TransitClass()
.setHomepageUri(
new Uri()
.setUri("https://developers.google.com/wallet")
.setDescription("Homepage description"))
// Note: reviewStatus must be 'UNDER_REVIEW' or 'DRAFT' for updates
.setReviewStatus("UNDER_REVIEW");
TransitClass response =
service
.transitclass()
.patch(String.format("%s.%s", issuerId, classSuffix), patchBody)
.execute();
System.out.println("Class patch response");
System.out.println(response.toPrettyString());
return response.getId();
}
// [END patchClass]
// [START addMessageClass]
/**
* Add a message to a pass class.
*
* @param issuerId The issuer ID being used for this request.
* @param classSuffix Developer-defined unique ID for this pass class.
* @param header The message header.
* @param body The message body.
* @return The pass class ID: "{issuerId}.{classSuffix}"
* @throws IOException
*/
public String AddClassMessage(String issuerId, String classSuffix, String header, String body)
throws IOException {
// Check if the class exists
try {
service.transitclass().get(String.format("%s.%s", issuerId, classSuffix)).execute();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() == 404) {
// Class does not exist
System.out.println(String.format("Class %s.%s not found!", issuerId, classSuffix));
return String.format("%s.%s", issuerId, classSuffix);
} else {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, classSuffix);
}
}
AddMessageRequest message =
new AddMessageRequest().setMessage(new Message().setHeader(header).setBody(body));
TransitClassAddMessageResponse response =
service
.transitclass()
.addmessage(String.format("%s.%s", issuerId, classSuffix), message)
.execute();
System.out.println("Class addMessage response");
System.out.println(response.toPrettyString());
return String.format("%s.%s", issuerId, classSuffix);
}
// [END addMessageClass]
// [START createObject]
/**
* Create an object.
*
* @param issuerId The issuer ID being used for this request.
* @param classSuffix Developer-defined unique ID for this pass class.
* @param objectSuffix Developer-defined unique ID for this pass object.
* @return The pass object ID: "{issuerId}.{objectSuffix}"
* @throws IOException
*/
public String CreateObject(String issuerId, String classSuffix, String objectSuffix)
throws IOException {
// Check if the object exists
try {
service.transitobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute();
System.out.println(String.format("Object %s.%s already exists!", issuerId, objectSuffix));
return String.format("%s.%s", issuerId, objectSuffix);
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() == 404) {
// Object does not exist
// Do nothing
} else {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, objectSuffix);
}
}
// Object doesn't exist, create it now
// See link below for more information on required properties
// https://developers.google.com/wallet/tickets/transit-passes/qr-code/rest/v1/transitobject
TransitObject transitObject =
TransitObject newObject =
new TransitObject()
.setId(objectId)
.setId(String.format("%s.%s", issuerId, objectSuffix))
.setClassId(String.format("%s.%s", issuerId, classSuffix))
.setState("ACTIVE")
.setHeroImage(
@@ -252,16 +402,219 @@ public class DemoTransit {
.setLanguage("en-US")
.setValue("Fare name"))));
TransitObject response = service.transitobject().insert(transitObject).execute();
TransitObject response = service.transitobject().insert(newObject).execute();
System.out.println("Object insert response");
System.out.println(response.toPrettyString());
return response.getId();
}
// [END object]
// [END createObject]
// [START jwt]
// [START updateObject]
/**
* Update an object.
*
* <p><strong>Warning:</strong> This replaces all existing object attributes!
*
* @param issuerId The issuer ID being used for this request.
* @param objectSuffix Developer-defined unique ID for this pass object.
* @return The pass object ID: "{issuerId}.{objectSuffix}"
* @throws IOException
*/
public String UpdateObject(String issuerId, String objectSuffix) throws IOException {
TransitObject updatedObject;
// Check if the object exists
try {
updatedObject =
service.transitobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() == 404) {
// Object does not exist
System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix));
return String.format("%s.%s", issuerId, objectSuffix);
} else {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, objectSuffix);
}
}
// Object exists
// Update the object by adding a link
Uri newLink =
new Uri()
.setUri("https://developers.google.com/wallet")
.setDescription("New link description");
if (updatedObject.getLinksModuleData() == null) {
// LinksModuleData was not set on the original object
updatedObject.setLinksModuleData(new LinksModuleData().setUris(Arrays.asList(newLink)));
} else {
updatedObject.getLinksModuleData().getUris().add(newLink);
}
TransitObject response =
service
.transitobject()
.update(String.format("%s.%s", issuerId, objectSuffix), updatedObject)
.execute();
System.out.println("Object update response");
System.out.println(response.toPrettyString());
return response.getId();
}
// [END updateObject]
// [START patchObject]
/**
* Patch an object.
*
* @param issuerId The issuer ID being used for this request.
* @param objectSuffix Developer-defined unique ID for this pass object.
* @return The pass object ID: "{issuerId}.{objectSuffix}"
* @throws IOException
*/
public String PatchObject(String issuerId, String objectSuffix) throws IOException {
TransitObject existingObject;
// Check if the object exists
try {
existingObject =
service.transitobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() == 404) {
// Object does not exist
System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix));
return String.format("%s.%s", issuerId, objectSuffix);
} else {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, objectSuffix);
}
}
// Object exists
// Patch the object by adding a link
Uri newLink =
new Uri()
.setUri("https://developers.google.com/wallet")
.setDescription("New link description");
TransitObject patchBody = new TransitObject();
if (existingObject.getLinksModuleData() == null) {
// LinksModuleData was not set on the original object
patchBody.setLinksModuleData(new LinksModuleData().setUris(new ArrayList<Uri>()));
} else {
patchBody.setLinksModuleData(existingObject.getLinksModuleData());
}
patchBody.getLinksModuleData().getUris().add(newLink);
TransitObject response =
service
.transitobject()
.patch(String.format("%s.%s", issuerId, objectSuffix), patchBody)
.execute();
System.out.println("Object patch response");
System.out.println(response.toPrettyString());
return response.getId();
}
// [END patchObject]
// [START expireObject]
/**
* Expire an object.
*
* <p>Sets the object's state to Expired. If the valid time interval is already set, the pass will
* expire automatically up to 24 hours after.
*
* @param issuerId The issuer ID being used for this request.
* @param objectSuffix Developer-defined unique ID for this pass object.
* @return The pass object ID: "{issuerId}.{objectSuffix}"
* @throws IOException
*/
public String ExpireObject(String issuerId, String objectSuffix) throws IOException {
// Check if the object exists
try {
service.transitobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() == 404) {
// Object does not exist
System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix));
return String.format("%s.%s", issuerId, objectSuffix);
} else {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, objectSuffix);
}
}
// Patch the object, setting the pass as expired
TransitObject patchBody = new TransitObject().setState("EXPIRED");
TransitObject response =
service
.transitobject()
.patch(String.format("%s.%s", issuerId, objectSuffix), patchBody)
.execute();
System.out.println("Object expiration response");
System.out.println(response.toPrettyString());
return response.getId();
}
// [END expireObject]
// [START addMessageObject]
/**
* Add a message to a pass object.
*
* @param issuerId The issuer ID being used for this request.
* @param objectSuffix Developer-defined unique ID for this pass object.
* @param header The message header.
* @param body The message body.
* @return The pass object ID: "{issuerId}.{objectSuffix}"
* @throws IOException
*/
public String AddObjectMessage(String issuerId, String objectSuffix, String header, String body)
throws IOException {
// Check if the object exists
try {
service.transitobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() == 404) {
// Object does not exist
System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix));
return String.format("%s.%s", issuerId, objectSuffix);
} else {
// Something else went wrong...
ex.printStackTrace();
return String.format("%s.%s", issuerId, objectSuffix);
}
}
AddMessageRequest message =
new AddMessageRequest().setMessage(new Message().setHeader(header).setBody(body));
TransitObjectAddMessageResponse response =
service
.transitobject()
.addmessage(String.format("%s.%s", issuerId, objectSuffix), message)
.execute();
System.out.println("Object addMessage response");
System.out.println(response.toPrettyString());
return String.format("%s.%s", issuerId, objectSuffix);
}
// [END addMessageObject]
// [START jwtNew]
/**
* Generate a signed JWT that creates a new pass class and object.
*
@@ -271,18 +624,13 @@ public class DemoTransit {
*
* @param issuerId The issuer ID being used for this request.
* @param classSuffix Developer-defined unique ID for this pass class.
* @param userId Developer-defined user ID for this object.
* @param objectSuffix Developer-defined unique ID for the pass object.
* @return An "Add to Google Wallet" link.
*/
public String CreateJWTSaveURL(String issuerId, String classSuffix, String userId) {
// Generate the object ID
// Should only include alphanumeric characters, '.', '_', or '-'
String newUserId = userId.replaceAll("[^\\w.-]", "_");
String objectId = String.format("%s.%s", issuerId, newUserId);
public String CreateJWTNewObjects(String issuerId, String classSuffix, String objectSuffix) {
// See link below for more information on required properties
// https://developers.google.com/wallet/tickets/transit-passes/qr-code/rest/v1/transitclass
TransitClass transitClass =
TransitClass newClass =
new TransitClass()
.setId(String.format("%s.%s", issuerId, classSuffix))
.setIssuerName("Issuer name")
@@ -303,9 +651,9 @@ public class DemoTransit {
// See link below for more information on required properties
// https://developers.google.com/wallet/tickets/transit-passes/qr-code/rest/v1/transitobject
TransitObject transitObject =
TransitObject newObject =
new TransitObject()
.setId(objectId)
.setId(String.format("%s.%s", issuerId, objectSuffix))
.setClassId(String.format("%s.%s", issuerId, classSuffix))
.setState("ACTIVE")
.setHeroImage(
@@ -397,8 +745,8 @@ public class DemoTransit {
// Create the Google Wallet payload and add to the JWT
HashMap<String, Object> payload = new HashMap<String, Object>();
payload.put("transitClasses", Arrays.asList(transitClass));
payload.put("transitObjects", Arrays.asList(transitObject));
payload.put("transitClasses", Arrays.asList(newClass));
payload.put("transitObjects", Arrays.asList(newObject));
claims.put("payload", payload);
// The service account credentials are used to sign the JWT
@@ -412,62 +760,105 @@ public class DemoTransit {
return String.format("https://pay.google.com/gp/v/save/%s", token);
}
// [END jwt]
// [END jwtNew]
// [START createIssuer]
// [START jwtExisting]
/**
* Create a new Google Wallet issuer account.
* Generate a signed JWT that references an existing pass object.
*
* @param issuerName The issuer's name.
* @param issuerEmail The issuer's email address.
* @throws IOException
*/
public void CreateIssuerAccount(String issuerName, String issuerEmail) throws IOException {
// New issuer information
Issuer issuer =
new Issuer()
.setName(issuerName)
.setContactInfo(new IssuerContactInfo().setEmail(issuerEmail));
Issuer response = service.issuer().insert(issuer).execute();
System.out.println("Issuer insert response");
System.out.println(response.toPrettyString());
}
// [END createIssuer]
// [START updatePermissions]
/**
* Update permissions for an existing Google Wallet issuer account. <strong>Warning:</strong> This
* operation overwrites all existing permissions!
* <p>When the user opens the "Add to Google Wallet" URL and saves the pass to their wallet, the
* pass objects defined in the JWT are added to the user's Google Wallet app. This allows the user
* to save multiple pass objects in one API call.
*
* <p>Example permissions list argument below. Copy the add entry as needed for each email address
* that will need access. Supported values for role are: 'READER', 'WRITER', and 'OWNER'
* <p>The objects to add must follow the below format:
*
* <pre><code>
* ArrayList<Permission> permissions = new ArrayList<Permission>();
* permissions.add(new Permission().setEmailAddress("emailAddress").setRole("OWNER"));
* </code></pre>
* <p>{ 'id': 'ISSUER_ID.OBJECT_SUFFIX', 'classId': 'ISSUER_ID.CLASS_SUFFIX' }
*
* @param issuerId The issuer ID being used for this request.
* @param permissions The list of email addresses and roles to assign.
* @throws IOException
* @return An "Add to Google Wallet" link.
*/
public void UpdateIssuerAccountPermissions(String issuerId, ArrayList<Permission> permissions)
throws IOException {
public String CreateJWTExistingObjects(String issuerId) {
// Multiple pass types can be added at the same time
// At least one type must be specified in the JWT claims
// Note: Make sure to replace the placeholder class and object suffixes
HashMap<String, Object> objectsToAdd = new HashMap<String, Object>();
Permissions response =
service
.permissions()
.update(
Long.parseLong(issuerId),
new Permissions().setIssuerId(Long.parseLong(issuerId)).setPermissions(permissions))
.execute();
// Event tickets
objectsToAdd.put(
"eventTicketObjects",
Arrays.asList(
new EventTicketObject()
.setId(String.format("%s.%s", issuerId, "EVENT_OBJECT_SUFFIX"))
.setClassId(String.format("%s.%s", issuerId, "EVENT_CLASS_SUFFIX"))));
System.out.println("Issuer permissions update response");
System.out.println(response.toPrettyString());
// Boarding passes
objectsToAdd.put(
"flightObjects",
Arrays.asList(
new FlightObject()
.setId(String.format("%s.%s", issuerId, "FLIGHT_OBJECT_SUFFIX"))
.setClassId(String.format("%s.%s", issuerId, "FLIGHT_CLASS_SUFFIX"))));
// Generic passes
objectsToAdd.put(
"genericObjects",
Arrays.asList(
new GenericObject()
.setId(String.format("%s.%s", issuerId, "GENERIC_OBJECT_SUFFIX"))
.setClassId(String.format("%s.%s", issuerId, "GENERIC_CLASS_SUFFIX"))));
// Gift cards
objectsToAdd.put(
"giftCardObjects",
Arrays.asList(
new GiftCardObject()
.setId(String.format("%s.%s", issuerId, "GIFT_CARD_OBJECT_SUFFIX"))
.setClassId(String.format("%s.%s", issuerId, "GIFT_CARD_CLASS_SUFFIX"))));
// Loyalty cards
objectsToAdd.put(
"loyaltyObjects",
Arrays.asList(
new LoyaltyObject()
.setId(String.format("%s.%s", issuerId, "LOYALTY_OBJECT_SUFFIX"))
.setClassId(String.format("%s.%s", issuerId, "LOYALTY_CLASS_SUFFIX"))));
// Offers
objectsToAdd.put(
"offerObjects",
Arrays.asList(
new OfferObject()
.setId(String.format("%s.%s", issuerId, "OFFER_OBJECT_SUFFIX"))
.setClassId(String.format("%s.%s", issuerId, "OFFER_CLASS_SUFFIX"))));
// Transit passes
objectsToAdd.put(
"transitObjects",
Arrays.asList(
new TransitObject()
.setId(String.format("%s.%s", issuerId, "TRANSIT_OBJECT_SUFFIX"))
.setClassId(String.format("%s.%s", issuerId, "TRANSIT_CLASS_SUFFIX"))));
// Create the JWT as a HashMap object
HashMap<String, Object> claims = new HashMap<String, Object>();
claims.put("iss", ((ServiceAccountCredentials) credentials).getClientEmail());
claims.put("aud", "google");
claims.put("origins", Arrays.asList("www.example.com"));
claims.put("typ", "savetowallet");
claims.put("payload", objectsToAdd);
// The service account credentials are used to sign the JWT
Algorithm algorithm =
Algorithm.RSA256(
null, (RSAPrivateKey) ((ServiceAccountCredentials) credentials).getPrivateKey());
String token = JWT.create().withPayload(claims).sign(algorithm);
System.out.println("Add to Google Wallet link");
System.out.println(String.format("https://pay.google.com/gp/v/save/%s", token));
return String.format("https://pay.google.com/gp/v/save/%s", token);
}
// [END updatePermissions]
// [END jwtExisting]
// [START batch]
/**
@@ -477,7 +868,7 @@ public class DemoTransit {
* @param classSuffix Developer-defined unique ID for this pass class.
* @throws IOException
*/
public void BatchCreateTransitObjects(String issuerId, String classSuffix) throws IOException {
public void BatchCreateObjects(String issuerId, String classSuffix) throws IOException {
// Create the batch request client
BatchRequest batch = service.batch(new HttpCredentialsAdapter(credentials));
@@ -486,6 +877,7 @@ public class DemoTransit {
new JsonBatchCallback<TransitObject>() {
// Invoked if the request was successful
public void onSuccess(TransitObject response, HttpHeaders responseHeaders) {
System.out.println("Batch insert response");
System.out.println(response.toString());
}
@@ -497,18 +889,14 @@ public class DemoTransit {
// Example: Generate three new pass objects
for (int i = 0; i < 3; i++) {
// Generate a random user ID
String userId = UUID.randomUUID().toString().replaceAll("[^\\w.-]", "_");
// Generate a random object ID with the user ID
// Should only include alphanumeric characters, '.', '_', or '-'
String objectId = String.format("%s.%s", issuerId, userId);
// Generate a random object suffix
String objectSuffix = UUID.randomUUID().toString().replaceAll("[^\\w.-]", "_");
// See link below for more information on required properties
// https://developers.google.com/wallet/tickets/transit-passes/qr-code/rest/v1/transitobject
TransitObject transitObject =
TransitObject batchObject =
new TransitObject()
.setId(objectId)
.setId(String.format("%s.%s", issuerId, objectSuffix))
.setClassId(String.format("%s.%s", issuerId, classSuffix))
.setState("ACTIVE")
.setHeroImage(
@@ -591,7 +979,7 @@ public class DemoTransit {
.setLanguage("en-US")
.setValue("Fare name"))));
service.transitobject().insert(transitObject).queue(batch, callback);
service.transitobject().insert(batchObject).queue(batch, callback);
}
// Invoke the batch API calls

View File

@@ -6,23 +6,23 @@ The files in this directory each implement a demo class for a specific Google
Wallet pass type. Each class implements methods for performing tasks such as
creating a pass class, updating issuer permissions, and more.
| Pass type | File |
|-----------|------|
| Event tickets | [demo-eventticket.js](./demo-eventticket.js) |
| Flight boarding passes | [demo-flight.js](./demo-flight.js) |
| Generic passes | [demo-generic.js](./demo-generic.js) |
| Gift cards | [demo-giftcard.js](./demo-giftcard.js) |
| Loyalty program membership | [demo-loyalty.js](./demo-loyalty.js) |
| Offers and promotions | [demo-offer.js](./demo-offer.js) |
| Transit passes | [demo-transit.js](./demo-transit.js) |
| Pass type | File |
|----------------------------|----------------------------------------------|
| Event tickets | [demo-eventticket.js](./demo-eventticket.js) |
| Flight boarding passes | [demo-flight.js](./demo-flight.js) |
| Generic passes | [demo-generic.js](./demo-generic.js) |
| Gift cards | [demo-giftcard.js](./demo-giftcard.js) |
| Loyalty program membership | [demo-loyalty.js](./demo-loyalty.js) |
| Offers and promotions | [demo-offer.js](./demo-offer.js) |
| Transit passes | [demo-transit.js](./demo-transit.js) |
## Prerequisites
* Node.js 18.x
* NPM 8.x
* Follow the steps outlined in the
[Google Wallet prerequisites](https://developers.google.com/wallet/generic/web/prerequisites)
to create the Google Wallet issuer account and Google Cloud service account
* Node.js 18.x
* NPM 8.x
* Follow the steps outlined in the
[Google Wallet prerequisites](https://developers.google.com/wallet/generic/web/prerequisites)
to create the Google Wallet issuer account and Google Cloud service account
## Environment variables
@@ -30,44 +30,63 @@ The following environment variables must be set. Alternatively, you can update
the code files to set the values directly. They can be found in the constructor
for each class file.
| Enviroment variable | Description | Example |
|---------------------|-------------|---------|
| Enviroment variable | Description | Example |
|----------------------------------|-------------------------------------------------|---------------------|
| `GOOGLE_APPLICATION_CREDENTIALS` | Path to a Google Cloud service account key file | `/path/to/key.json` |
## How to use the code samples
1. Use `npm` to install the dependencies in the [package.json](./package.json)
1. Use `npm` to install the dependencies in the [package.json](./package.json)
```bash
# This must be run from the same location as the package.json
npm install
```
2. In your Node.js code, import a demo class and call its method(s). An example
can be found below
2. In your Node.js code, import a demo class and call its method(s). An example
can be found below
```javascript
// Import the demo class
const { DemoEventTicket } = require('./demo-eventticket');
// Create a demo class instance
// Creates the authenticated HTTP client
let demo = new DemoEventTicket();
// Create the authenticated HTTP client
demo.auth();
// Create a pass class
demo.createEventTicketClass('issuer_id', 'class_suffix');
demo.createClass('issuer_id', 'class_suffix');
// Update a pass class
demo.updateClass('issuer_id', 'class_suffix');
// Patch a pass class
demo.patchClass('issuer_id', 'class_suffix');
// Add a message to a pass class
demo.addClassMessage('issuer_id', 'class_suffix', 'header', 'body');
// Create a pass object
demo.createEventTicketObject('issuer_id', 'class_suffix', 'user_id');
demo.createObject('issuer_id', 'class_suffix', 'object_suffix');
// Create an Add to Google Wallet link
demo.createJwtSaveUrl('issuer_id', 'class_suffix', 'user_id');
// Update a pass object
demo.updateObject('issuer_id', 'object_suffix');
// Create an issuer account
demo.createIssuerAccount('issuer_name', 'issuer_email');
// Patch a pass object
demo.patchObject('issuer_id', 'object_suffix');
// Add a message to a pass object
demo.addObjectMessage('issuer_id', 'object_suffix', 'header', 'body');
// Expire a pass object
demo.expireObject('issuer_id', 'object_suffix');
// Generate an Add to Google Wallet link that creates a new pass class and object
demo.createJWTNewObjects('issuer_id', 'class_suffix', 'object_suffix');
// Generate an Add to Google Wallet link that references existing pass object(s)
demo.createJWTExistingObjects('issuer_id');
// Create pass objects in batch
demo.batchCreateEventTicketObjects('issuer_id', 'class_suffix');
demo.batchCreateObjects('issuer_id', 'class_suffix');
```

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -6,25 +6,25 @@ The files in this directory each implement a demo class for a specific Google
Wallet pass type. Each class implements methods for performing tasks such as
creating a pass class, updating issuer permissions, and more.
| Pass type | File |
|-----------|------|
| Event tickets | [demo_eventticket.php](./demo_eventticket.php) |
| Flight boarding passes | [demo_flight.php](./demo_flight.php) |
| Generic passes | [demo_generic.php](./demo_generic.php) |
| Gift cards | [demo_giftcard.php](./demo_giftcard.php) |
| Loyalty program membership | [demo_loyalty.php](./demo_loyalty.php) |
| Offers and promotions | [demo_offer.php](./demo_offer.php) |
| Transit passes | [demo_transit.php](./demo_transit.php) |
| Pass type | File |
|----------------------------|--------------------------------------------------|
| Event tickets | [`demo_eventticket.php`](./demo_eventticket.php) |
| Flight boarding passes | [`demo_flight.php`](./demo_flight.php) |
| Generic passes | [`demo_generic.php`](./demo_generic.php) |
| Gift cards | [`demo_giftcard.php`](./demo_giftcard.php) |
| Loyalty program membership | [`demo_loyalty.php`](./demo_loyalty.php) |
| Offers and promotions | [`demo_offer.php`](./demo_offer.php) |
| Transit passes | [`demo_transit.php`](./demo_transit.php) |
## Prerequisites
* PHP 8.x
* Composer 2.x
* Follow the steps outlined in the
[Google Wallet prerequisites](https://developers.google.com/wallet/generic/web/prerequisites)
to create the Google Wallet issuer account and Google Cloud service account
* Download the PHP
[Google Wallet API Client library](https://developers.google.com/wallet/generic/resources/libraries#php)
* PHP 8.x
* Composer 2.x
* Follow the steps outlined in the
[Google Wallet prerequisites](https://developers.google.com/wallet/generic/web/prerequisites)
to create the Google Wallet issuer account and Google Cloud service account
* Download the PHP
[Google Wallet API Client library](https://developers.google.com/wallet/generic/resources/libraries#php)
## Environment variables
@@ -32,22 +32,22 @@ The following environment variables must be set. Alternatively, you can update
the code files to set the values directly. They can be found in the constructor
for each class file.
| Enviroment variable | Description | Example |
|---------------------|-------------|---------|
| Enviroment variable | Description | Example |
|----------------------------------|-------------------------------------------------|---------------------|
| `GOOGLE_APPLICATION_CREDENTIALS` | Path to a Google Cloud service account key file | `/path/to/key.json` |
## How to use the code samples
1. Install the dependencies listed in [composer.json](./composer.json)
1. Install the dependencies listed in [composer.json](./composer.json)
```bash
# This must be run from the same location as the composer.json
composer install
```
2. Copy the path to the Google Wallet API Client library (`Walletobjects.php`
file) you downloaded. If needed, update the path in the demo class PHP file
(line 22).
2. Copy the path to the Google Wallet API Client library (`Walletobjects.php`
file) you downloaded. If needed, update the path in the demo class PHP file
(line 22).
```php
// Download the PHP client library from the following URL
@@ -55,8 +55,8 @@ file) you downloaded. If needed, update the path in the demo class PHP file
require __DIR__ . '/lib/Walletobjects.php';
```
3. In your PHP code, import a demo class and call its method(s). An example
can be found below
3. In your PHP code, import a demo class and call its method(s). An example
can be found below
```php
// Import the demo class
@@ -65,21 +65,39 @@ can be found below
// Create a demo class instance
$demo = new DemoEventTicket();
// Create the authenticated HTTP client
$demo->auth();
// Create a pass class
$demo->createEventTicketClass('issuer_id', 'class_suffix');
$demo->createClass('issuer_id', 'class_suffix');
// Update a pass class
$demo->updateClass('issuer_id', 'class_suffix');
// Patch a pass class
$demo->patchClass('issuer_id', 'class_suffix');
// Add a message to a pass class
$demo->addClassMessage('issuer_id', 'class_suffix', 'header', 'body');
// Create a pass object
$demo->createEventTicketObject('issuer_id', 'class_suffix', 'user_id');
$demo->createObject('issuer_id', 'class_suffix', 'object_suffix');
// Create an Add to Google Wallet link
$demo->createJwtSaveUrl('issuer_id', 'class_suffix', 'user_id');
// Update a pass object
$demo->updateObject('issuer_id', 'object_suffix');
// Create an issuer account
$demo->createIssuerAccount('issuer_name', 'issuer_email');
// Patch a pass object
$demo->patchObject('issuer_id', 'object_suffix');
// Add a message to a pass object
$demo->addObjectMessage('issuer_id', 'object_suffix', 'header', 'body');
// Expire a pass object
$demo->expireObject('issuer_id', 'object_suffix');
// Generate an Add to Google Wallet link that creates a new pass class and object
$demo->createJWTNewObjects('issuer_id', 'class_suffix', 'object_suffix');
// Generate an Add to Google Wallet link that references existing pass object(s)
$demo->createJWTExistingObjects('issuer_id');
// Create pass objects in batch
$demo->batchCreateEventTicketObjects('issuer_id', 'class_suffix');
$demo->batchCreateObjects('issuer_id', 'class_suffix');
```

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -50,6 +50,8 @@ class DemoGeneric
public function __construct()
{
$this->keyFilePath = getenv('GOOGLE_APPLICATION_CREDENTIALS') ?: '/path/to/key.json';
$this->auth();
}
// [END setup]
@@ -76,276 +78,554 @@ class DemoGeneric
}
// [END auth]
// [START class]
// [START createClass]
/**
* Create a class via the API. This can also be done in the Google Pay and Wallet console.
* Create a class.
*
* @param string $issuerId The issuer ID being used for this request.
* @param string $classSuffix Developer-defined unique ID for this pass class.
*
* @return string The pass class ID: "{$issuerId}.{$classSuffix}"
*/
public function createGenericClass(string $issuerId, string $classSuffix)
public function createClass(string $issuerId, string $classSuffix)
{
// Check if the class exists
try {
$this->service->genericclass->get("{$issuerId}.{$classSuffix}");
print("Class {$issuerId}.{$classSuffix} already exists!");
return "{$issuerId}.{$classSuffix}";
} catch (Google\Service\Exception $ex) {
if (empty($ex->getErrors()) || $ex->getErrors()[0]['reason'] != 'classNotFound') {
// Something else went wrong...
print_r($ex);
return "{$issuerId}.{$classSuffix}";
}
}
// See link below for more information on required properties
// https://developers.google.com/wallet/generic/rest/v1/genericclass
$genericClass = new Google_Service_Walletobjects_GenericClass([
'id' => "{$issuerId}.{$classSuffix}",
$newClass = new Google_Service_Walletobjects_GenericClass([
'id' => "{$issuerId}.{$classSuffix}"
]);
try {
$response = $this->service->genericclass->insert($genericClass);
$response = $this->service->genericclass->insert($newClass);
print "Class insert response\n";
print_r($response);
print "Class insert response\n";
print_r($response);
return $response->id;
} catch (Google\Service\Exception $ex) {
if ($ex->getCode() == 409) {
print "Class {$issuerId}.{$classSuffix} already exists";
return;
}
// Something else went wrong
print $ex->getTraceAsString();
}
return $response->id;
}
// [END class]
// [END createClass]
// [START object]
// [START updateClass]
/**
* Create an object via the API.
* Update a class.
*
* **Warning:** This replaces all existing class attributes!
*
* @param string $issuerId The issuer ID being used for this request.
* @param string $classSuffix Developer-defined unique ID for this pass class.
* @param string $userId Developer-defined user ID for this pass object.
*
* @return string The pass class ID: "{issuerId}.{userId}"
* @return string The pass class ID: "{$issuerId}.{$classSuffix}"
*/
public function createGenericObject(string $issuerId, string $classSuffix, string $userId)
public function updateClass(string $issuerId, string $classSuffix)
{
// Generate the object ID
// Should only include alphanumeric characters, '.', '_', or '-'
$newUserId = preg_replace('/[^\w.-]/i', '_', $userId);
$objectId = "{$issuerId}.{$newUserId}";
// Check if the class exists
try {
$updatedClass = $this->service->genericclass->get("{$issuerId}.{$classSuffix}");
} catch (Google\Service\Exception $ex) {
if (!empty($ex->getErrors()) && $ex->getErrors()[0]['reason'] == 'classNotFound') {
// Class does not exist
print("Class {$issuerId}.{$classSuffix} not found!");
return "{$issuerId}.{$classSuffix}";
} else {
// Something else went wrong...
print_r($ex);
return "{$issuerId}.{$classSuffix}";
}
}
// Update the class by adding a homepage
$newLink = new Google_Service_Walletobjects_Uri([
'uri' => 'https://developers.google.com/wallet',
'description' => 'Homepage description'
]);
$linksModuleData = $updatedClass->getLinksModuleData();
if (is_null($linksModuleData)) {
// LinksModuleData was not set on the original object
$linksModuleData = new Google_Service_Walletobjects_LinksModuleData([
'uris' => []
]);
}
$uris = $linksModuleData->getUris();
array_push(
$uris,
$newLink
);
$linksModuleData->setUris($uris);
$updatedClass->setLinksModuleData($linksModuleData);
$response = $this->service->genericclass->update("{$issuerId}.{$classSuffix}", $updatedClass);
print "Class update response\n";
print_r($response);
return $response->id;
}
// [END updateClass]
// [START patchClass]
/**
* Patch a class.
*
* The PATCH method supports patch semantics.
*
* @param string $issuerId The issuer ID being used for this request.
* @param string $classSuffix Developer-defined unique ID for this pass class.
*
* @return string The pass class ID: "{$issuerId}.{$classSuffix}"
*/
public function patchClass(string $issuerId, string $classSuffix)
{
// Check if the class exists
try {
$existingClass = $this->service->genericclass->get("{$issuerId}.{$classSuffix}");
} catch (Google\Service\Exception $ex) {
if (!empty($ex->getErrors()) && $ex->getErrors()[0]['reason'] == 'classNotFound') {
// Class does not exist
print("Class {$issuerId}.{$classSuffix} not found!");
return "{$issuerId}.{$classSuffix}";
} else {
// Something else went wrong...
print_r($ex);
return "{$issuerId}.{$classSuffix}";
}
}
// Patch the class by adding a homepage
$newLink = new Google_Service_Walletobjects_Uri([
'uri' => 'https://developers.google.com/wallet',
'description' => 'Homepage description'
]);
$patchBody = new Google_Service_Walletobjects_GenericClass();
$linksModuleData = $existingClass->getLinksModuleData();
if (is_null($linksModuleData)) {
// LinksModuleData was not set on the original object
$linksModuleData = new Google_Service_Walletobjects_LinksModuleData([
'uris' => []
]);
}
$uris = $linksModuleData->getUris();
array_push(
$uris,
$newLink
);
$linksModuleData->setUris($uris);
$patchBody->setLinksModuleData($linksModuleData);
$response = $this->service->genericclass->patch("{$issuerId}.{$classSuffix}", $patchBody);
print "Class patch response\n";
print_r($response);
return $response->id;
}
// [END patchClass]
// [START createObject]
/**
* Create an object.
*
* @param string $issuerId The issuer ID being used for this request.
* @param string $classSuffix Developer-defined unique ID for this pass class.
* @param string $objectSuffix Developer-defined unique ID for this pass object.
*
* @return string The pass object ID: "{$issuerId}.{$objectSuffix}"
*/
public function createObject(string $issuerId, string $classSuffix, string $objectSuffix)
{
// Check if the object exists
try {
$this->service->eventticketobject->get("{$issuerId}.{$objectSuffix}");
print("Object {$issuerId}.{$objectSuffix} already exists!");
return "{$issuerId}.{$objectSuffix}";
} catch (Google\Service\Exception $ex) {
if (empty($ex->getErrors()) || $ex->getErrors()[0]['reason'] != 'resourceNotFound') {
// Something else went wrong...
print_r($ex);
return "{$issuerId}.{$objectSuffix}";
}
}
// See link below for more information on required properties
// https://developers.google.com/wallet/generic/rest/v1/genericobject
$genericObject = new Google_Service_Walletobjects_GenericObject([
'id' => "{$objectId}",
$newObject = new Google_Service_Walletobjects_GenericObject([
'id' => "{$issuerId}.{$objectSuffix}",
'classId' => "{$issuerId}.{$classSuffix}",
'state' => 'ACTIVE',
'heroImage' => new Google_Service_Walletobjects_Image([
'sourceUri' => new Google_Service_Walletobjects_ImageUri([
'uri' => 'https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg',
'uri' => 'https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg'
]),
'contentDescription' => new Google_Service_Walletobjects_LocalizedString([
'defaultValue' => new Google_Service_Walletobjects_TranslatedString([
'language' => 'en-US',
'value' => 'Hero image description',
]),
]),
'value' => 'Hero image description'
])
])
]),
'textModulesData' => [
new Google_Service_Walletobjects_TextModuleData([
'header' => 'Text module header',
'body' => 'Text module body',
'id' => 'TEXT_MODULE_ID',
]),
'id' => 'TEXT_MODULE_ID'
])
],
'linksModuleData' => new Google_Service_Walletobjects_LinksModuleData([
'uris' => [
new Google_Service_Walletobjects_Uri([
'uri' => 'http://maps.google.com/',
'description' => 'Link module URI description',
'id' => 'LINK_MODULE_URI_ID',
'id' => 'LINK_MODULE_URI_ID'
]),
new Google_Service_Walletobjects_Uri([
'uri' => 'tel:6505555555',
'description' => 'Link module tel description',
'id' => 'LINK_MODULE_TEL_ID',
]),
],
'id' => 'LINK_MODULE_TEL_ID'
])
]
]),
'imageModulesData' => [
new Google_Service_Walletobjects_ImageModuleData([
'mainImage' => new Google_Service_Walletobjects_Image([
'sourceUri' => new Google_Service_Walletobjects_ImageUri([
'uri' => 'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg',
'uri' => 'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg'
]),
'contentDescription' => new Google_Service_Walletobjects_LocalizedString([
'defaultValue' => new Google_Service_Walletobjects_TranslatedString([
'language' => 'en-US',
'value' => 'Image module description',
]),
]),
'value' => 'Image module description'
])
])
]),
'id' => 'IMAGE_MODULE_ID',
'id' => 'IMAGE_MODULE_ID'
])
],
'barcode' => new Google_Service_Walletobjects_Barcode([
'type' => 'QR_CODE',
'value' => 'QR code value',
'value' => 'QR code value'
]),
'cardTitle' => new Google_Service_Walletobjects_LocalizedString([
'defaultValue' => new Google_Service_Walletobjects_TranslatedString([
'language' => 'en-US',
'value' => 'Generic card title',
]),
'value' => 'Generic card title'
])
]),
'header' => new Google_Service_Walletobjects_LocalizedString([
'defaultValue' => new Google_Service_Walletobjects_TranslatedString([
'language' => 'en-US',
'value' => 'Generic header',
]),
'value' => 'Generic header'
])
]),
'hexBackgroundColor' => '#4285f4',
'logo' => new Google_Service_Walletobjects_Image([
'sourceUri' => new Google_Service_Walletobjects_ImageUri([
'uri' => 'https://storage.googleapis.com/wallet-lab-tools-codelab-artifacts-public/pass_google_logo.jpg',
'uri' => 'https://storage.googleapis.com/wallet-lab-tools-codelab-artifacts-public/pass_google_logo.jpg'
]),
'contentDescription' => new Google_Service_Walletobjects_LocalizedString([
'defaultValue' => new Google_Service_Walletobjects_TranslatedString([
'language' => 'en-US',
'value' => 'Generic card logo',
]),
]),
]),
'value' => 'Generic card logo'
])
])
])
]);
try {
$response = $this->service->genericobject->insert($genericObject);
$response = $this->service->genericobject->insert($newObject);
print "Object insert response\n";
print_r($response);
print "Object insert response\n";
print_r($response);
return $response->id;
} catch (Google\Service\Exception $ex) {
if ($ex->getCode() == 409) {
print "Object {$objectId} already exists";
return;
}
// Something else went wrong
print $ex->getTraceAsString();
}
return $response->id;
}
// [END object]
// [END createObject]
// [START jwt]
// [START updateObject]
/**
* Update an object.
*
* **Warning:** This replaces all existing object attributes!
*
* @param string $issuerId The issuer ID being used for this request.
* @param string $objectSuffix Developer-defined unique ID for this pass object.
*
* @return string The pass object ID: "{$issuerId}.{$objectSuffix}"
*/
public function updateObject(string $issuerId, string $objectSuffix)
{
// Check if the object exists
try {
$updatedObject = $this->service->genericobject->get("{$issuerId}.{$objectSuffix}");
} catch (Google\Service\Exception $ex) {
if (!empty($ex->getErrors()) && $ex->getErrors()[0]['reason'] == 'resourceNotFound') {
print("Object {$issuerId}.{$objectSuffix} not found!");
return "{$issuerId}.{$objectSuffix}";
} else {
// Something else went wrong...
print_r($ex);
return "{$issuerId}.{$objectSuffix}";
}
}
// Update the object by adding a link
$newLink = new Google_Service_Walletobjects_Uri([
'uri' => 'https://developers.google.com/wallet',
'description' => 'New link description'
]);
$linksModuleData = $updatedObject->getLinksModuleData();
if (is_null($linksModuleData)) {
// LinksModuleData was not set on the original object
$linksModuleData = new Google_Service_Walletobjects_LinksModuleData([
'uris' => []
]);
}
$uris = $linksModuleData->getUris();
array_push(
$uris,
$newLink
);
$linksModuleData->setUris($uris);
$updatedObject->setLinksModuleData($linksModuleData);
$response = $this->service->genericobject->update("{$issuerId}.{$objectSuffix}", $updatedObject);
print "Object update response\n";
print_r($response);
return $response->id;
}
// [END updateObject]
// [START patchObject]
/**
* Patch an object.
*
* @param string $issuerId The issuer ID being used for this request.
* @param string $objectSuffix Developer-defined unique ID for this pass object.
*
* @return string The pass object ID: "{$issuerId}.{$objectSuffix}"
*/
public function patchObject(string $issuerId, string $objectSuffix)
{
// Check if the object exists
try {
$existingObject = $this->service->genericobject->get("{$issuerId}.{$objectSuffix}");
} catch (Google\Service\Exception $ex) {
if (!empty($ex->getErrors()) && $ex->getErrors()[0]['reason'] == 'resourceNotFound') {
print("Object {$issuerId}.{$objectSuffix} not found!");
return "{$issuerId}.{$objectSuffix}";
} else {
// Something else went wrong...
print_r($ex);
return "{$issuerId}.{$objectSuffix}";
}
}
// Patch the object by adding a link
$newLink = new Google_Service_Walletobjects_Uri([
'uri' => 'https://developers.google.com/wallet',
'description' => 'New link description'
]);
$patchBody = new Google_Service_Walletobjects_GenericObject();
$linksModuleData = $existingObject->getLinksModuleData();
if (is_null($linksModuleData)) {
// LinksModuleData was not set on the original object
$linksModuleData = new Google_Service_Walletobjects_LinksModuleData([
'uris' => []
]);
}
$uris = $linksModuleData->getUris();
array_push(
$uris,
$newLink
);
$linksModuleData->setUris($uris);
$patchBody->setLinksModuleData($linksModuleData);
$response = $this->service->genericobject->patch("{$issuerId}.{$objectSuffix}", $patchBody);
print "Object patch response\n";
print_r($response);
return $response->id;
}
// [END patchObject]
// [START expireObject]
/**
* Expire an object.
*
* Sets the object's state to Expired. If the valid time interval is
* already set, the pass will expire automatically up to 24 hours after.
*
* @param string $issuerId The issuer ID being used for this request.
* @param string $objectSuffix Developer-defined unique ID for this pass object.
*
* @return string The pass object ID: "{$issuerId}.{$objectSuffix}"
*/
public function expireObject(string $issuerId, string $objectSuffix)
{
// Check if the object exists
try {
$this->service->genericobject->get("{$issuerId}.{$objectSuffix}");
} catch (Google\Service\Exception $ex) {
if (!empty($ex->getErrors()) && $ex->getErrors()[0]['reason'] == 'resourceNotFound') {
print("Object {$issuerId}.{$objectSuffix} not found!");
return "{$issuerId}.{$objectSuffix}";
} else {
// Something else went wrong...
print_r($ex);
return "{$issuerId}.{$objectSuffix}";
}
}
// Patch the object, setting the pass as expired
$patchBody = new Google_Service_Walletobjects_GenericObject([
'state' => 'EXPIRED'
]);
$response = $this->service->genericobject->patch("{$issuerId}.{$objectSuffix}", $patchBody);
print "Object expiration response\n";
print_r($response);
return $response->id;
}
// [END expireObject]
// [START jwtNew]
/**
* Generate a signed JWT that creates a new pass class and object.
*
* When the user opens the "Add to Google Wallet" URL and saves the pass to
* their wallet, the pass class and object defined in the JWT are
* created.This allows you to create multiple pass classes and objects in
* created. This allows you to create multiple pass classes and objects in
* one API call when the user saves the pass to their wallet.
*
* @param string $issuerId The issuer ID being used for this request.
* @param string $classSuffix Developer-defined class ID for this class.
* @param string $userId Developer-defined user ID for this object.
* @param string $classSuffix Developer-defined unique ID for the pass class.
* @param string $objectSuffix Developer-defined unique ID for the pass object.
*
* @return string An "Add to Google Wallet" link.
*/
public function createJwtSaveUrl(string $issuerId, string $classSuffix, string $userId)
public function createJwtNewObjects(string $issuerId, string $classSuffix, string $objectSuffix)
{
// Generate the object ID
// Should only include alphanumeric characters, '.', '_', or '-'
$newUserId = preg_replace('/[^\w.-]/i', '_', $userId);
$objectId = "{$issuerId}.{$newUserId}";
// See link below for more information on required properties
// https://developers.google.com/wallet/generic/rest/v1/genericclass
$genericClass = new Google_Service_Walletobjects_GenericClass([
$newClass = new Google_Service_Walletobjects_GenericClass([
'id' => "{$issuerId}.{$classSuffix}",
]);
// See link below for more information on required properties
// https://developers.google.com/wallet/generic/rest/v1/genericobject
$genericObject = new Google_Service_Walletobjects_GenericObject([
'id' => "{$objectId}",
$newObject = new Google_Service_Walletobjects_GenericObject([
'id' => "{$issuerId}.{$objectSuffix}",
'classId' => "{$issuerId}.{$classSuffix}",
'state' => 'ACTIVE',
'heroImage' => new Google_Service_Walletobjects_Image([
'sourceUri' => new Google_Service_Walletobjects_ImageUri([
'uri' => 'https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg',
'uri' => 'https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg'
]),
'contentDescription' => new Google_Service_Walletobjects_LocalizedString([
'defaultValue' => new Google_Service_Walletobjects_TranslatedString([
'language' => 'en-US',
'value' => 'Hero image description',
]),
]),
'value' => 'Hero image description'
])
])
]),
'textModulesData' => [
new Google_Service_Walletobjects_TextModuleData([
'header' => 'Text module header',
'body' => 'Text module body',
'id' => 'TEXT_MODULE_ID',
]),
'id' => 'TEXT_MODULE_ID'
])
],
'linksModuleData' => new Google_Service_Walletobjects_LinksModuleData([
'uris' => [
new Google_Service_Walletobjects_Uri([
'uri' => 'http://maps.google.com/',
'description' => 'Link module URI description',
'id' => 'LINK_MODULE_URI_ID',
'id' => 'LINK_MODULE_URI_ID'
]),
new Google_Service_Walletobjects_Uri([
'uri' => 'tel:6505555555',
'description' => 'Link module tel description',
'id' => 'LINK_MODULE_TEL_ID',
]),
],
'id' => 'LINK_MODULE_TEL_ID'
])
]
]),
'imageModulesData' => [
new Google_Service_Walletobjects_ImageModuleData([
'mainImage' => new Google_Service_Walletobjects_Image([
'sourceUri' => new Google_Service_Walletobjects_ImageUri([
'uri' => 'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg',
'uri' => 'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg'
]),
'contentDescription' => new Google_Service_Walletobjects_LocalizedString([
'defaultValue' => new Google_Service_Walletobjects_TranslatedString([
'language' => 'en-US',
'value' => 'Image module description',
]),
]),
'value' => 'Image module description'
])
])
]),
'id' => 'IMAGE_MODULE_ID',
'id' => 'IMAGE_MODULE_ID'
])
],
'barcode' => new Google_Service_Walletobjects_Barcode([
'type' => 'QR_CODE',
'value' => 'QR code value',
'value' => 'QR code value'
]),
'cardTitle' => new Google_Service_Walletobjects_LocalizedString([
'defaultValue' => new Google_Service_Walletobjects_TranslatedString([
'language' => 'en-US',
'value' => 'Generic card title',
]),
'value' => 'Generic card title'
])
]),
'header' => new Google_Service_Walletobjects_LocalizedString([
'defaultValue' => new Google_Service_Walletobjects_TranslatedString([
'language' => 'en-US',
'value' => 'Generic header',
]),
'value' => 'Generic header'
])
]),
'hexBackgroundColor' => '#4285f4',
'logo' => new Google_Service_Walletobjects_Image([
'sourceUri' => new Google_Service_Walletobjects_ImageUri([
'uri' => 'https://storage.googleapis.com/wallet-lab-tools-codelab-artifacts-public/pass_google_logo.jpg',
'uri' => 'https://storage.googleapis.com/wallet-lab-tools-codelab-artifacts-public/pass_google_logo.jpg'
]),
'contentDescription' => new Google_Service_Walletobjects_LocalizedString([
'defaultValue' => new Google_Service_Walletobjects_TranslatedString([
'language' => 'en-US',
'value' => 'Generic card logo',
]),
]),
]),
'value' => 'Generic card logo'
])
])
])
]);
// Create the JWT as an array of key/value pairs
// The service account credentials are used to sign the JWT
$serviceAccount = json_decode(file_get_contents($this->keyFilePath), true);
// Create the JWT as an array of key/value pairs
$claims = [
'iss' => $serviceAccount['client_email'],
'aud' => 'google',
@@ -353,15 +633,14 @@ class DemoGeneric
'typ' => 'savetowallet',
'payload' => [
'genericClasses' => [
$genericClass,
$newClass
],
'genericObjects' => [
$genericObject,
],
],
$newObject
]
]
];
// The service account credentials are used to sign the JWT
$token = JWT::encode(
$claims,
$serviceAccount['private_key'],
@@ -373,75 +652,124 @@ class DemoGeneric
return "https://pay.google.com/gp/v/save/{$token}";
}
// [END jwt]
// [END jwtNew]
// [START createIssuer]
// [START jwtExisting]
/**
* Create a new Google Wallet issuer account.
* Generate a signed JWT that references an existing pass object.
*
* @param string $issuerName The issuer's name.
* @param string $issuerEmail The issuer's email address.
*/
public function createIssuerAccount(string $issuerName, string $issuerEmail)
{
// New issuer information
$issuer = new Google_Service_Walletobjects_Issuer([
'name' => $issuerName,
'contactInfo' => new Google_Service_Walletobjects_IssuerContactInfo([
'email' => $issuerEmail,
]),
]);
$response = $this->service->issuer->insert($issuer);
print "Issuer insert response\n";
print_r($response);
}
// [END createIssuer]
// [START updatePermissions]
/**
* Update permissions for an existing Google Wallet issuer account.
* **Warning:** This operation overwrites all existing permissions!
* When the user opens the "Add to Google Wallet" URL and saves the pass to
* their wallet, the pass objects defined in the JWT are added to the
* user's Google Wallet app. This allows the user to save multiple pass
* objects in one API call.
*
* Example permissions list argument below. Copy the entry as
* needed for each email address that will need access. Supported
* values for role are: 'READER', 'WRITER', and 'OWNER'
* The objects to add must follow the below format:
*
* $permissions = array(
* new Google_Service_Walletobjects_Permission([
* 'emailAddress' => 'email-address',
* 'role' => 'OWNER',
* ]),
* );
* {
* 'id': 'ISSUER_ID.OBJECT_SUFFIX',
* 'classId': 'ISSUER_ID.CLASS_SUFFIX'
* }
*
* @param string $issuerId The issuer ID being used for this request.
* @param array $permissions The list of email addresses and roles to assign.
*
* @return string An "Add to Google Wallet" link.
*/
public function updateIssuerAccountPermissions(string $issuerId, array $permissions)
public function createJwtExistingObjects(string $issuerId)
{
// Make the PUT request
$response = $this->service->permissions->update(
$issuerId,
new Google_Service_Walletobjects_Permissions([
'issuerId' => $issuerId,
'permissions' => $permissions,
])
// Multiple pass types can be added at the same time
// At least one type must be specified in the JWT claims
// Note: Make sure to replace the placeholder class and object suffixes
$objectsToAdd = [
// Event tickets
'eventTicketObjects' => [
[
'id' => "{$issuerId}.EVENT_OBJECT_SUFFIX",
'classId' => "{$issuerId}.EVENT_CLASS_SUFFIX"
]
],
// Boarding passes
'flightObjects' => [
[
'id' => "{$issuerId}.FLIGHT_OBJECT_SUFFIX",
'classId' => "{$issuerId}.FLIGHT_CLASS_SUFFIX"
]
],
// Generic passes
'genericObjects' => [
[
'id' => "{$issuerId}.GENERIC_OBJECT_SUFFIX",
'classId' => "{$issuerId}.GENERIC_CLASS_SUFFIX"
]
],
// Gift cards
'giftCardObjects' => [
[
'id' => "{$issuerId}.GIFT_CARD_OBJECT_SUFFIX",
'classId' => "{$issuerId}.GIFT_CARD_CLASS_SUFFIX"
]
],
// Loyalty cards
'loyaltyObjects' => [
[
'id' => "{$issuerId}.LOYALTY_OBJECT_SUFFIX",
'classId' => "{$issuerId}.LOYALTY_CLASS_SUFFIX"
]
],
// Offers
'offerObjects' => [
[
'id' => "{$issuerId}.OFFER_OBJECT_SUFFIX",
'classId' => "{$issuerId}.OFFER_CLASS_SUFFIX"
]
],
// Tranist passes
'transitObjects' => [
[
'id' => "{$issuerId}.TRANSIT_OBJECT_SUFFIX",
'classId' => "{$issuerId}.TRANSIT_CLASS_SUFFIX"
]
]
];
// The service account credentials are used to sign the JWT
$serviceAccount = json_decode(file_get_contents($this->keyFilePath), true);
// Create the JWT as an array of key/value pairs
$claims = [
'iss' => $serviceAccount['client_email'],
'aud' => 'google',
'origins' => ['www.example.com'],
'typ' => 'savetowallet',
'payload' => $objectsToAdd
];
$token = JWT::encode(
$claims,
$serviceAccount['private_key'],
'RS256'
);
print "Permissions update response\n";
print_r($response);
print "Add to Google Wallet link\n";
print "https://pay.google.com/gp/v/save/{$token}";
return "https://pay.google.com/gp/v/save/{$token}";
}
// [END updatePermissions]
// [END jwtExisting]
// [START batch]
/**
* Batch create Google Wallet objects from an existing class.
*
* @param string $issuerId The issuer ID being used for this request.
* @param string $classSuffix Developer-defined class ID for this class.
* @param string $classSuffix Developer-defined unique ID for the pass class.
*/
public function batchCreateGenericObjects(string $issuerId, string $classSuffix)
public function batchCreateObjects(string $issuerId, string $classSuffix)
{
// Update the client to enable batch requests
$this->client->setUseBatch(true);
@@ -449,98 +777,94 @@ class DemoGeneric
// Example: Generate three new pass objects
for ($i = 0; $i < 3; $i++) {
// Generate a random user ID
$userId = preg_replace('/[^\w.-]/i', '_', uniqid());
// Generate a random object ID with the user ID
// Should only include alphanumeric characters, '.', '_', or '-'
$objectId = "{$issuerId}.{$userId}";
// Generate a random object suffix
$objectSuffix = preg_replace('/[^\w.-]/i', '_', uniqid());
// See link below for more information on required properties
// https://developers.google.com/wallet/generic/rest/v1/genericobject
$genericObject = new Google_Service_Walletobjects_GenericObject([
'id' => "{$objectId}",
$batchObject = new Google_Service_Walletobjects_GenericObject([
'id' => "{$issuerId}.{$objectSuffix}",
'classId' => "{$issuerId}.{$classSuffix}",
'state' => 'ACTIVE',
'heroImage' => new Google_Service_Walletobjects_Image([
'sourceUri' => new Google_Service_Walletobjects_ImageUri([
'uri' => 'https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg',
'uri' => 'https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg'
]),
'contentDescription' => new Google_Service_Walletobjects_LocalizedString([
'defaultValue' => new Google_Service_Walletobjects_TranslatedString([
'language' => 'en-US',
'value' => 'Hero image description',
]),
]),
'value' => 'Hero image description'
])
])
]),
'textModulesData' => [
new Google_Service_Walletobjects_TextModuleData([
'header' => 'Text module header',
'body' => 'Text module body',
'id' => 'TEXT_MODULE_ID',
]),
'id' => 'TEXT_MODULE_ID'
])
],
'linksModuleData' => new Google_Service_Walletobjects_LinksModuleData([
'uris' => [
new Google_Service_Walletobjects_Uri([
'uri' => 'http://maps.google.com/',
'description' => 'Link module URI description',
'id' => 'LINK_MODULE_URI_ID',
'id' => 'LINK_MODULE_URI_ID'
]),
new Google_Service_Walletobjects_Uri([
'uri' => 'tel:6505555555',
'description' => 'Link module tel description',
'id' => 'LINK_MODULE_TEL_ID',
]),
],
'id' => 'LINK_MODULE_TEL_ID'
])
]
]),
'imageModulesData' => [
new Google_Service_Walletobjects_ImageModuleData([
'mainImage' => new Google_Service_Walletobjects_Image([
'sourceUri' => new Google_Service_Walletobjects_ImageUri([
'uri' => 'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg',
'uri' => 'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg'
]),
'contentDescription' => new Google_Service_Walletobjects_LocalizedString([
'defaultValue' => new Google_Service_Walletobjects_TranslatedString([
'language' => 'en-US',
'value' => 'Image module description',
]),
]),
'defaultValue' => new Google_Service_Walletobjects_TranslatedString([
'language' => 'en-US',
'value' => 'Image module description'
])
])
]),
'id' => 'IMAGE_MODULE_ID',
'id' => 'IMAGE_MODULE_ID'
])
],
'barcode' => new Google_Service_Walletobjects_Barcode([
'type' => 'QR_CODE',
'value' => 'QR code value',
'value' => 'QR code value'
]),
'cardTitle' => new Google_Service_Walletobjects_LocalizedString([
'defaultValue' => new Google_Service_Walletobjects_TranslatedString([
'language' => 'en-US',
'value' => 'Generic card title',
]),
'value' => 'Generic card title'
])
]),
'header' => new Google_Service_Walletobjects_LocalizedString([
'defaultValue' => new Google_Service_Walletobjects_TranslatedString([
'language' => 'en-US',
'value' => 'Generic header',
]),
'value' => 'Generic header'
])
]),
'hexBackgroundColor' => '#4285f4',
'logo' => new Google_Service_Walletobjects_Image([
'sourceUri' => new Google_Service_Walletobjects_ImageUri([
'uri' => 'https://storage.googleapis.com/wallet-lab-tools-codelab-artifacts-public/pass_google_logo.jpg',
'uri' => 'https://storage.googleapis.com/wallet-lab-tools-codelab-artifacts-public/pass_google_logo.jpg'
]),
'contentDescription' => new Google_Service_Walletobjects_LocalizedString([
'defaultValue' => new Google_Service_Walletobjects_TranslatedString([
'language' => 'en-US',
'value' => 'Generic card logo',
]),
]),
]),
'value' => 'Generic card logo'
])
])
])
]);
$batch->add($this->service->genericobject->insert($genericObject));
$batch->add($this->service->genericobject->insert($batchObject));
}
// Make the batch request

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -6,23 +6,23 @@ The files in this directory each implement a demo class for a specific Google
Wallet pass type. Each class implements methods for performing tasks such as
creating a pass class, updating issuer permissions, and more.
| Pass type | File |
|-----------|------|
| Event tickets | [demo_eventticket.py](./demo_eventticket.py) |
| Flight boarding passes | [demo_flight.py](./demo_flight.py) |
| Generic passes | [demo_generic.py](./demo_generic.py) |
| Gift cards | [demo_giftcard.py](./demo_giftcard.py) |
| Loyalty program membership | [demo_loyalty.py](./demo_loyalty.py) |
| Offers and promotions | [demo_offer.py](./demo_offer.py) |
| Transit passes | [demo_transit.py](./demo_transit.py) |
| Pass type | File |
|----------------------------|------------------------------------------------|
| Event tickets | [`demo_eventticket.py`](./demo_eventticket.py) |
| Flight boarding passes | [`demo_flight.py`](./demo_flight.py) |
| Generic passes | [`demo_generic.py`](./demo_generic.py) |
| Gift cards | [`demo_giftcard.py`](./demo_giftcard.py) |
| Loyalty program membership | [`demo_loyalty.py`](./demo_loyalty.py) |
| Offers and promotions | [`demo_offer.py`](./demo_offer.py) |
| Transit passes | [`demo_transit.py`](./demo_transit.py) |
## Prerequisites
* Python 3.x
* The [`pipenv` library](https://pipenv.pypa.io/en/latest/install/)
* Follow the steps outlined in the
[Google Wallet prerequisites](https://developers.google.com/wallet/generic/web/prerequisites)
to create the Google Wallet issuer account and Google Cloud service account
* Python 3.x
* The [`pipenv` library](https://pipenv.pypa.io/en/latest/install/)
* Follow the steps outlined in the
[Google Wallet prerequisites](https://developers.google.com/wallet/generic/web/prerequisites)
to create the Google Wallet issuer account and Google Cloud service account
## Environment variables
@@ -30,66 +30,99 @@ The following environment variables must be set. Alternatively, you can update
the code files to set the values directly. They can be found in the constructor
for each class file.
| Enviroment variable | Description | Example |
|---------------------|-------------|---------|
| Enviroment variable | Description | Example |
|----------------------------------|-------------------------------------------------|---------------------|
| `GOOGLE_APPLICATION_CREDENTIALS` | Path to a Google Cloud service account key file | `/path/to/key.json` |
## How to use the code samples
1. Create a [virtual environment](https://docs.python.org/3/library/venv.html)
in your workspace
1. Create a [virtual environment](https://docs.python.org/3/library/venv.html)
in your workspace
```bash
# This creates a .venv directory in the current working path
python3 -m venv .venv
```
2. Activate the virtual environment
2. Activate the virtual environment
```bash
# This must be run in the same location as the .venv directory
source .venv/bin/activate
```
3. Use `pipenv` to install the dependencies in the [Pipfile](./Pipfile)
3. Use `pipenv` to install the dependencies in the [Pipfile](./Pipfile)
```bash
# This must be run from the same location as the Pipfile
pipenv install
```
4. In your Python code, import a demo class and call its method(s). An example
can be found below
4. In your Python code, import a demo class and call its method(s). An example
can be found below
```python
# Import the demo class
from .demo_eventticket import DemoEventTicket
# Create a demo class instance
# Creates the authenticated HTTP client
demo = DemoEventTicket()
# Create the authenticated HTTP client
demo.auth()
# Create a pass class
demo.create_event_ticket_class(issuer_id='issuer_id',
class_suffix='class_suffix')
demo.create_class(issuer_id='issuer_id',
class_suffix='class_suffix')
# Update a pass class
demo.update_class(issuer_id='issuer_id',
class_suffix='class_suffix')
# Patch a pass class
demo.patch_class(issuer_id='issuer_id',
class_suffix='class_suffix')
# Add a message to a pass class
demo.add_class_message(issuer_id='issuer_id',
class_suffix='class_suffix',
header='header',
body='body')
# Create a pass object
demo.create_event_ticket_object(issuer_id='issuer_id',
class_suffix='class_suffix',
user_id='user_id')
demo.create_object(issuer_id='issuer_id',
class_suffix='class_suffix',
object_suffix='object_suffix')
# Create an Add to Google Wallet link
demo.create_jwt_save_url(issuer_id='issuer_id',
class_suffix='class_suffix',
user_id='user_id')
# Update a pass object
demo.update_object(issuer_id='issuer_id',
object_suffix='object_suffix')
# Create an issuer account
demo.create_issuer_account(issuer_name='issuer_name',
issuer_email='issuer_email')
# Patch a pass object
demo.patch_object(issuer_id='issuer_id',
object_suffix='object_suffix')
# Add a message to a pass object
demo.add_object_message(issuer_id='issuer_id',
object_suffix='object_suffix',
header='header',
body='body')
# Expire a pass object
demo.expire_object(issuer_id='issuer_id',
object_suffix='object_suffix')
# Create an "Add to Google Wallet" link
# that generates a new pass class and object
demo.create_jwt_new_objects(issuer_id='issuer_id',
class_suffix='class_suffix',
object_suffix='object_suffix')
# Create an "Add to Google Wallet" link
# that references existing pass classes and objects
demo.create_jwt_existing_objects(issuer_id='issuer_id',
class_suffix='class_suffix',
object_suffix='object_suffix')
# Create pass objects in batch
demo.batch_create_event_ticket_objects(issuer_id='issuer_id',
class_suffix='class_suffix')
demo.batch_create_objects(issuer_id='issuer_id',
class_suffix='class_suffix')
```

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -19,8 +19,6 @@
# [START imports]
import json
import os
import re
from typing import List
import uuid
from google.auth.transport.requests import AuthorizedSession
@@ -42,6 +40,9 @@ class DemoGiftCard:
self.key_file_path = os.environ.get('GOOGLE_APPLICATION_CREDENTIALS',
'/path/to/key.json')
self.base_url = 'https://walletobjects.googleapis.com/walletobjects/v1'
self.batch_url = 'https://walletobjects.googleapis.com/batch'
self.class_url = f'{self.base_url}/giftCardClass'
self.object_url = f'{self.base_url}/giftCardObject'
# Set up authenticated client
self.auth()
@@ -59,11 +60,9 @@ class DemoGiftCard:
# [END auth]
# [START class]
def create_gift_card_class(self, issuer_id: str, class_suffix: str) -> str:
"""Create a class via the API.
This can also be done in the Google Pay and Wallet console.
# [START createClass]
def create_class(self, issuer_id: str, class_suffix: str) -> str:
"""Create a class.
Args:
issuer_id (str): The issuer ID being used for this request.
@@ -72,141 +71,463 @@ class DemoGiftCard:
Returns:
The pass class ID: f"{issuer_id}.{class_suffix}"
"""
class_url = f'{self.base_url}/giftCardClass'
# See below for more information on required properties
# Check if the class exists
response = self.http_client.get(
url=f'{self.class_url}/{issuer_id}.{class_suffix}')
if response.status_code == 200:
print(f'Class {issuer_id}.{class_suffix} already exists!')
return f'{issuer_id}.{class_suffix}'
elif response.status_code != 404:
# Something else went wrong...
print(response.text)
return f'{issuer_id}.{class_suffix}'
# See link below for more information on required properties
# https://developers.google.com/wallet/retail/gift-cards/rest/v1/giftcardclass
gift_card_class = {
new_class = {
'id': f'{issuer_id}.{class_suffix}',
'issuerName': 'Issuer name',
'reviewStatus': 'UNDER_REVIEW',
'reviewStatus': 'UNDER_REVIEW'
}
response = self.http_client.post(
url=class_url,
json=gift_card_class,
)
response = self.http_client.post(url=self.class_url, json=new_class)
print('Class insert response')
print(response.text)
return response.json().get('id')
# [END class]
# [END createClass]
# [START object]
def create_gift_card_object(self, issuer_id: str, class_suffix: str,
user_id: str) -> str:
"""Create an object via the API.
# [START updateClass]
def update_class(self, issuer_id: str, class_suffix: str) -> str:
"""Update a class.
**Warning:** This replaces all existing class attributes!
Args:
issuer_id (str): The issuer ID being used for this request.
class_suffix (str): Developer-defined unique ID for this pass class.
user_id (str): Developer-defined user ID for this pass object.
Returns:
The pass object ID: f"{issuer_id}.{user_id}"
The pass class ID: f"{issuer_id}.{class_suffix}"
"""
object_url = f'{self.base_url}/giftCardObject'
# Generate the object ID
# Should only include alphanumeric characters, '.', '_', or '-'
new_user_id = re.sub(r'[^\w.-]', '_', user_id)
object_id = f'{issuer_id}.{new_user_id}'
# Check if the class exists
response = self.http_client.get(
url=f'{self.class_url}/{issuer_id}.{class_suffix}')
# See below for more information on required properties
if response.status_code == 404:
print(f'Class {issuer_id}.{class_suffix} not found!')
return f'{issuer_id}.{class_suffix}'
elif response.status_code != 200:
# Something else went wrong...
print(response.text)
return f'{issuer_id}.{class_suffix}'
# Class exists
updated_class = response.json()
# Update the class by adding a homepage
updated_class['homepageUri'] = {
'uri': 'https://developers.google.com/wallet',
'description': 'Homepage description'
}
# Note: reviewStatus must be 'UNDER_REVIEW' or 'DRAFT' for updates
updated_class['reviewStatus'] = 'UNDER_REVIEW'
response = self.http_client.put(
url=f'{self.class_url}/{issuer_id}.{class_suffix}',
json=updated_class)
print('Class update response')
print(response.text)
return response.json().get('id')
# [END updateClass]
# [START patchClass]
def patch_class(self, issuer_id: str, class_suffix: str) -> str:
"""Patch a class.
The PATCH method supports patch semantics.
Args:
issuer_id (str): The issuer ID being used for this request.
class_suffix (str): Developer-defined unique ID for this pass class.
Returns:
The pass class ID: f"{issuer_id}.{class_suffix}"
"""
# Check if the class exists
response = self.http_client.get(
url=f'{self.class_url}/{issuer_id}.{class_suffix}')
if response.status_code == 404:
print(f'Class {issuer_id}.{class_suffix} not found!')
return f'{issuer_id}.{class_suffix}'
elif response.status_code != 200:
# Something else went wrong...
print(response.text)
return f'{issuer_id}.{class_suffix}'
# Patch the class by adding a homepage
patch_body = {
'homepageUri': {
'uri': 'https://developers.google.com/wallet',
'description': 'Homepage description'
},
# Note: reviewStatus must be 'UNDER_REVIEW' or 'DRAFT' for patches
'reviewStatus': 'UNDER_REVIEW'
}
response = self.http_client.patch(
url=f'{self.class_url}/{issuer_id}.{class_suffix}', json=patch_body)
print('Class patch response')
print(response.text)
return response.json().get('id')
# [END patchClass]
# [START addMessageClass]
def add_class_message(self, issuer_id: str, class_suffix: str, header: str,
body: str) -> str:
"""Add a message to a pass class.
Args:
issuer_id (str): The issuer ID being used for this request.
class_suffix (str): Developer-defined unique ID for this pass class.
header (str): The message header.
body (str): The message body.
Returns:
The pass class ID: f"{issuer_id}.{class_suffix}"
"""
# Check if the class exists
response = self.http_client.get(
url=f'{self.class_url}/{issuer_id}.{class_suffix}')
if response.status_code == 404:
print(f'Class {issuer_id}.{class_suffix} not found!')
return f'{issuer_id}.{class_suffix}'
elif response.status_code != 200:
# Something else went wrong...
print(response.text)
return f'{issuer_id}.{class_suffix}'
response = self.http_client.post(
url=f'{self.class_url}/{issuer_id}.{class_suffix}/addMessage',
json={'message': {
'header': header,
'body': body
}})
print('Class addMessage response')
print(response.text)
return response.json().get('id')
# [END addMessageClass]
# [START createObject]
def create_object(self, issuer_id: str, class_suffix: str,
object_suffix: str) -> str:
"""Create an object.
Args:
issuer_id (str): The issuer ID being used for this request.
class_suffix (str): Developer-defined unique ID for the pass class.
object_suffix (str): Developer-defined unique ID for the pass object.
Returns:
The pass object ID: f"{issuer_id}.{object_suffix}"
"""
# Check if the object exists
response = self.http_client.get(
url=f'{self.object_url}/{issuer_id}.{object_suffix}')
if response.status_code == 200:
print(f'Object {issuer_id}.{object_suffix} already exists!')
print(response.text)
return f'{issuer_id}.{object_suffix}'
elif response.status_code != 404:
# Something else went wrong...
print(response.text)
return f'{issuer_id}.{object_suffix}'
# See link below for more information on required properties
# https://developers.google.com/wallet/retail/gift-cards/rest/v1/giftcardobject
gift_card_object = {
'id': f'{object_id}',
new_object = {
'id': f'{issuer_id}.{object_suffix}',
'classId': f'{issuer_id}.{class_suffix}',
'state': 'ACTIVE',
'heroImage': {
'sourceUri': {
'uri':
'https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg',
'https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg'
},
'contentDescription': {
'defaultValue': {
'language': 'en-US',
'value': 'Hero image description',
},
},
'value': 'Hero image description'
}
}
},
'textModulesData': [{
'header': 'Text module header',
'body': 'Text module body',
'id': 'TEXT_MODULE_ID',
},],
'id': 'TEXT_MODULE_ID'
}],
'linksModuleData': {
'uris': [
{
'uri': 'http://maps.google.com/',
'description': 'Link module URI description',
'id': 'LINK_MODULE_URI_ID',
},
{
'uri': 'tel:6505555555',
'description': 'Link module tel description',
'id': 'LINK_MODULE_TEL_ID',
},
],
'uris': [{
'uri': 'http://maps.google.com/',
'description': 'Link module URI description',
'id': 'LINK_MODULE_URI_ID'
}, {
'uri': 'tel:6505555555',
'description': 'Link module tel description',
'id': 'LINK_MODULE_TEL_ID'
}]
},
'imageModulesData': [{
'mainImage': {
'sourceUri': {
'uri':
'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg',
'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg'
},
'contentDescription': {
'defaultValue': {
'language': 'en-US',
'value': 'Image module description',
},
},
'value': 'Image module description'
}
}
},
'id': 'IMAGE_MODULE_ID',
},],
'id': 'IMAGE_MODULE_ID'
}],
'barcode': {
'type': 'QR_CODE',
'value': 'QR code',
'value': 'QR code'
},
'locations': [{
'latitude': 37.424015499999996,
'longitude': -122.09259560000001,
},],
'longitude': -122.09259560000001
}],
'cardNumber': 'Card number',
'pin': '1234',
'balance': {
'micros': 20000000,
'currencyCode': 'USD',
'currencyCode': 'USD'
},
'balanceUpdateTime': {
'date': '2020-04-12T16:20:50.52-04:00',
},
'date': '2020-04-12T16:20:50.52-04:00'
}
}
response = self.http_client.get(f'{object_url}{object_id}')
if response.status_code == 404:
# Object does not yet exist
# Send POST request to create it
response = self.http_client.post(
url=object_url,
json=gift_card_object,
)
# Create the object
response = self.http_client.post(url=self.object_url, json=new_object)
print('Object insert response')
print(response.text)
else:
print('Object get response')
print(response.text)
print('Object insert response')
print(response.text)
return response.json().get('id')
# [END object]
# [END createObject]
# [START jwt]
def create_jwt_save_url(self, issuer_id: str, class_suffix: str,
user_id: str) -> str:
# [START updateObject]
def update_object(self, issuer_id: str, object_suffix: str) -> str:
"""Update an object.
**Warning:** This replaces all existing object attributes!
Args:
issuer_id (str): The issuer ID being used for this request.
object_suffix (str): Developer-defined unique ID for the pass object.
Returns:
The pass object ID: f"{issuer_id}.{object_suffix}"
"""
# Check if the object exists
response = self.http_client.get(
url=f'{self.object_url}/{issuer_id}.{object_suffix}')
if response.status_code == 404:
print(f'Object {issuer_id}.{object_suffix} not found!')
return f'{issuer_id}.{object_suffix}'
elif response.status_code != 200:
# Something else went wrong...
print(response.text)
return f'{issuer_id}.{object_suffix}'
# Object exists
updated_object = response.json()
# Update the object by adding a link
new_link = {
'uri': 'https://developers.google.com/wallet',
'description': 'New link description'
}
if not updated_object.get('linksModuleData'):
updated_object['linksModuleData'] = {'uris': []}
updated_object['linksModuleData']['uris'].append(new_link)
response = self.http_client.put(
url=f'{self.object_url}/{issuer_id}.{object_suffix}',
json=updated_object)
print('Object update response')
print(response.text)
return response.json().get('id')
# [END updateObject]
# [START patchObject]
def patch_object(self, issuer_id: str, object_suffix: str) -> str:
"""Patch an object.
Args:
issuer_id (str): The issuer ID being used for this request.
object_suffix (str): Developer-defined unique ID for the pass object.
Returns:
The pass object ID: f"{issuer_id}.{object_suffix}"
"""
# Check if the object exists
response = self.http_client.get(
url=f'{self.object_url}/{issuer_id}.{object_suffix}')
if response.status_code == 404:
print(f'Object {issuer_id}.{object_suffix} not found!')
return f'{issuer_id}.{object_suffix}'
elif response.status_code != 200:
# Something else went wrong...
print(response.text)
return f'{issuer_id}.{object_suffix}'
# Object exists
existing_object = response.json()
# Patch the object by adding a link
patch_body = {}
new_link = {
'uri': 'https://developers.google.com/wallet',
'description': 'New link description'
}
if existing_object.get('linksModuleData'):
patch_body['linksModuleData'] = existing_object['linksModuleData']
else:
patch_body['linksModuleData'] = {'uris': []}
patch_body['linksModuleData']['uris'].append(new_link)
response = self.http_client.patch(
url=f'{self.object_url}/{issuer_id}.{object_suffix}',
json=patch_body)
print('Object patch response')
print(response.text)
return response.json().get('id')
# [END patchObject]
# [START expireObject]
def expire_object(self, issuer_id: str, object_suffix: str) -> str:
"""Expire an object.
Sets the object's state to Expired. If the valid time interval is
already set, the pass will expire automatically up to 24 hours after.
Args:
issuer_id (str): The issuer ID being used for this request.
object_suffix (str): Developer-defined unique ID for the pass object.
Returns:
The pass object ID: f"{issuer_id}.{object_suffix}"
"""
# Check if the object exists
response = self.http_client.get(
url=f'{self.object_url}/{issuer_id}.{object_suffix}')
if response.status_code == 404:
print(f'Object {issuer_id}.{object_suffix} not found!')
return f'{issuer_id}.{object_suffix}'
elif response.status_code != 200:
# Something else went wrong...
print(response.text)
return f'{issuer_id}.{object_suffix}'
# Patch the object, setting the pass as expired
patch_body = {'state': 'EXPIRED'}
response = self.http_client.patch(
url=f'{self.object_url}/{issuer_id}.{object_suffix}',
json=patch_body)
print('Object expiration response')
print(response.text)
return response.json().get('id')
# [END expireObject]
# [START addMessageObject]
def add_object_message(self, issuer_id: str, object_suffix: str,
header: str, body: str) -> str:
"""Add a message to a pass object.
Args:
issuer_id (str): The issuer ID being used for this request.
object_suffix (str): Developer-defined unique ID for this pass object.
header (str): The message header.
body (str): The message body.
Returns:
The pass class ID: f"{issuer_id}.{class_suffix}"
"""
# Check if the object exists
response = self.http_client.get(
url=f'{self.object_url}/{issuer_id}.{object_suffix}')
if response.status_code == 404:
print(f'Object {issuer_id}.{object_suffix} not found!')
return f'{issuer_id}.{object_suffix}'
elif response.status_code != 200:
# Something else went wrong...
print(response.text)
return f'{issuer_id}.{object_suffix}'
response = self.http_client.post(
url=f'{self.object_url}/{issuer_id}.{object_suffix}/addMessage',
json={'message': {
'header': header,
'body': body
}})
print('Object addMessage response')
print(response.text)
return response.json().get('id')
# [END addMessageObject]
# [START jwtNew]
def create_jwt_new_objects(self, issuer_id: str, class_suffix: str,
object_suffix: str) -> str:
"""Generate a signed JWT that creates a new pass class and object.
When the user opens the "Add to Google Wallet" URL and saves the pass to
@@ -216,95 +537,87 @@ class DemoGiftCard:
Args:
issuer_id (str): The issuer ID being used for this request.
class_suffix (str): Developer-defined unique ID for this pass class.
user_id (str): Developer-defined user ID for this pass object.
class_suffix (str): Developer-defined unique ID for the pass class.
object_suffix (str): Developer-defined unique ID for the pass object.
Returns:
An "Add to Google Wallet" link
An "Add to Google Wallet" link.
"""
# Generate the object ID
# Should only include alphanumeric characters, '.', '_', or '-'
new_user_id = re.sub(r'[^\w.-]', '_', user_id)
object_id = f'{issuer_id}.{new_user_id}'
# See below for more information on required properties
# See link below for more information on required properties
# https://developers.google.com/wallet/retail/gift-cards/rest/v1/giftcardclass
gift_card_class = {
new_class = {
'id': f'{issuer_id}.{class_suffix}',
'issuerName': 'Issuer name',
'reviewStatus': 'UNDER_REVIEW',
'reviewStatus': 'UNDER_REVIEW'
}
# See below for more information on required properties
# See link below for more information on required properties
# https://developers.google.com/wallet/retail/gift-cards/rest/v1/giftcardobject
gift_card_object = {
'id': f'{object_id}',
new_object = {
'id': f'{issuer_id}.{object_suffix}',
'classId': f'{issuer_id}.{class_suffix}',
'state': 'ACTIVE',
'heroImage': {
'sourceUri': {
'uri':
'https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg',
'https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg'
},
'contentDescription': {
'defaultValue': {
'language': 'en-US',
'value': 'Hero image description',
},
},
'value': 'Hero image description'
}
}
},
'textModulesData': [{
'header': 'Text module header',
'body': 'Text module body',
'id': 'TEXT_MODULE_ID',
},],
'id': 'TEXT_MODULE_ID'
}],
'linksModuleData': {
'uris': [
{
'uri': 'http://maps.google.com/',
'description': 'Link module URI description',
'id': 'LINK_MODULE_URI_ID',
},
{
'uri': 'tel:6505555555',
'description': 'Link module tel description',
'id': 'LINK_MODULE_TEL_ID',
},
],
'uris': [{
'uri': 'http://maps.google.com/',
'description': 'Link module URI description',
'id': 'LINK_MODULE_URI_ID'
}, {
'uri': 'tel:6505555555',
'description': 'Link module tel description',
'id': 'LINK_MODULE_TEL_ID'
}]
},
'imageModulesData': [{
'mainImage': {
'sourceUri': {
'uri':
'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg',
'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg'
},
'contentDescription': {
'defaultValue': {
'language': 'en-US',
'value': 'Image module description',
},
},
'value': 'Image module description'
}
}
},
'id': 'IMAGE_MODULE_ID',
},],
'id': 'IMAGE_MODULE_ID'
}],
'barcode': {
'type': 'QR_CODE',
'value': 'QR code',
'value': 'QR code'
},
'locations': [{
'latitude': 37.424015499999996,
'longitude': -122.09259560000001,
},],
'longitude': -122.09259560000001
}],
'cardNumber': 'Card number',
'pin': '1234',
'balance': {
'micros': 20000000,
'currencyCode': 'USD',
'currencyCode': 'USD'
},
'balanceUpdateTime': {
'date': '2020-04-12T16:20:50.52-04:00',
},
'date': '2020-04-12T16:20:50.52-04:00'
}
}
# Create the JWT claims
@@ -315,8 +628,8 @@ class DemoGiftCard:
'typ': 'savetowallet',
'payload': {
# The listed classes and objects will be created
'giftCardClasses': [gift_card_class,],
'giftCardObjects': [gift_card_object,],
'giftCardClasses': [new_class],
'giftCardObjects': [new_object]
},
}
@@ -329,79 +642,100 @@ class DemoGiftCard:
return f'https://pay.google.com/gp/v/save/{token}'
# [END jwt]
# [END jwtNew]
# [START createIssuer]
def create_issuer_account(self, issuer_name: str, issuer_email: str):
"""Create a new Google Wallet issuer account.
# [START jwtExisting]
def create_jwt_existing_objects(self, issuer_id: str) -> str:
"""Generate a signed JWT that references an existing pass object.
Args:
issuer_name (str): The issuer's name.
issuer_email (str): The issuer's email address.
"""
# Issuer API endpoint
issuer_url = f'{self.base_url}/issuer'
When the user opens the "Add to Google Wallet" URL and saves the pass to
their wallet, the pass objects defined in the JWT are added to the
user's Google Wallet app. This allows the user to save multiple pass
objects in one API call.
# New issuer information
issuer = {
'name': issuer_name,
'contactInfo': {
'email': issuer_email,
},
The objects to add must follow the below format:
{
'id': 'ISSUER_ID.OBJECT_SUFFIX',
'classId': 'ISSUER_ID.CLASS_SUFFIX'
}
# Make the POST request
response = self.http_client.post(
url=issuer_url,
json=issuer,
)
print('Issuer insert response')
print(response.text)
# [END createIssuer]
# [START updatePermissions]
def update_issuer_account_permissions(self, issuer_id: str,
permissions: List):
"""Update permissions for an existing Google Wallet issuer account.
**Warning:** This operation overwrites all existing
permissions!
Example permissions list argument below. Copy the dict entry as
needed for each email address that will need access. Supported
values for role are: 'READER', 'WRITER', and 'OWNER'
permissions = [
{
'emailAddress': 'email-address',
'role': 'OWNER',
},
]
Args:
issuer_id (str): The issuer ID being used for this request.
permissions (List): The list of email addresses and roles to assign.
Returns:
An "Add to Google Wallet" link
"""
# Permissions API endpoint
permissions_url = f'{self.base_url}/permissions/{issuer_id}'
response = self.http_client.put(
url=permissions_url,
json={
'issuerId': issuer_id,
'permissions': permissions,
},
)
# Multiple pass types can be added at the same time
# At least one type must be specified in the JWT claims
# Note: Make sure to replace the placeholder class and object suffixes
objects_to_add = {
# Event tickets
'eventTicketObjects': [{
'id': f'{issuer_id}.EVENT_OBJECT_SUFFIX',
'classId': f'{issuer_id}.EVENT_CLASS_SUFFIX'
}],
print('Permissions update response')
print(response.text)
# Boarding passes
'flightObjects': [{
'id': f'{issuer_id}.FLIGHT_OBJECT_SUFFIX',
'classId': f'{issuer_id}.FLIGHT_CLASS_SUFFIX'
}],
# [END updatePermissions]
# Generic passes
'genericObjects': [{
'id': f'{issuer_id}.GENERIC_OBJECT_SUFFIX',
'classId': f'{issuer_id}.GENERIC_CLASS_SUFFIX'
}],
# Gift cards
'giftCardObjects': [{
'id': f'{issuer_id}.GIFT_CARD_OBJECT_SUFFIX',
'classId': f'{issuer_id}.GIFT_CARD_CLASS_SUFFIX'
}],
# Loyalty cards
'loyaltyObjects': [{
'id': f'{issuer_id}.LOYALTY_OBJECT_SUFFIX',
'classId': f'{issuer_id}.LOYALTY_CLASS_SUFFIX'
}],
# Offers
'offerObjects': [{
'id': f'{issuer_id}.OFFER_OBJECT_SUFFIX',
'classId': f'{issuer_id}.OFFER_CLASS_SUFFIX'
}],
# Transit passes
'transitObjects': [{
'id': f'{issuer_id}.TRANSIT_OBJECT_SUFFIX',
'classId': f'{issuer_id}.TRANSIT_CLASS_SUFFIX'
}]
}
# Create the JWT claims
claims = {
'iss': self.credentials.service_account_email,
'aud': 'google',
'origins': ['www.example.com'],
'typ': 'savetowallet',
'payload': objects_to_add
}
# The service account credentials are used to sign the JWT
signer = crypt.RSASigner.from_service_account_file(self.key_file_path)
token = jwt.encode(signer, claims).decode('utf-8')
print('Add to Google Wallet link')
print(f'https://pay.google.com/gp/v/save/{token}')
return f'https://pay.google.com/gp/v/save/{token}'
# [END jwtExisting]
# [START batch]
def batch_create_gift_card_objects(self, issuer_id: str, class_suffix: str):
def batch_create_objects(self, issuer_id: str, class_suffix: str):
"""Batch create Google Wallet objects from an existing class.
The request body will be a multiline string. See below for information.
@@ -416,89 +750,82 @@ class DemoGiftCard:
# Example: Generate three new pass objects
for _ in range(3):
# Generate a random user ID
user_id = str(uuid.uuid4()).replace('[^\\w.-]', '_')
# Generate a random object suffix
object_suffix = str(uuid.uuid4()).replace('[^\\w.-]', '_')
# Generate an object ID with the user ID
# Should only include alphanumeric characters, '.', '_', or '-'
object_id = f'{issuer_id}.{user_id}'
# See below for more information on required properties
# See link below for more information on required properties
# https://developers.google.com/wallet/retail/gift-cards/rest/v1/giftcardobject
batch_gift_card_object = {
'id': f'{object_id}',
batch_object = {
'id': f'{issuer_id}.{object_suffix}',
'classId': f'{issuer_id}.{class_suffix}',
'state': 'ACTIVE',
'heroImage': {
'sourceUri': {
'uri':
'https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg',
'https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg'
},
'contentDescription': {
'defaultValue': {
'language': 'en-US',
'value': 'Hero image description',
},
},
'value': 'Hero image description'
}
}
},
'textModulesData': [{
'header': 'Text module header',
'body': 'Text module body',
'id': 'TEXT_MODULE_ID',
},],
'id': 'TEXT_MODULE_ID'
}],
'linksModuleData': {
'uris': [
{
'uri': 'http://maps.google.com/',
'description': 'Link module URI description',
'id': 'LINK_MODULE_URI_ID',
},
{
'uri': 'tel:6505555555',
'description': 'Link module tel description',
'id': 'LINK_MODULE_TEL_ID',
},
],
'uris': [{
'uri': 'http://maps.google.com/',
'description': 'Link module URI description',
'id': 'LINK_MODULE_URI_ID'
}, {
'uri': 'tel:6505555555',
'description': 'Link module tel description',
'id': 'LINK_MODULE_TEL_ID'
}]
},
'imageModulesData': [{
'mainImage': {
'sourceUri': {
'uri':
'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg',
'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg'
},
'contentDescription': {
'defaultValue': {
'language': 'en-US',
'value': 'Image module description',
},
},
'value': 'Image module description'
}
}
},
'id': 'IMAGE_MODULE_ID',
},],
'id': 'IMAGE_MODULE_ID'
}],
'barcode': {
'type': 'QR_CODE',
'value': 'QR code',
'value': 'QR code'
},
'locations': [{
'latitude': 37.424015499999996,
'longitude': -122.09259560000001,
},],
'longitude': -122.09259560000001
}],
'cardNumber': 'Card number',
'pin': '1234',
'balance': {
'micros': 20000000,
'currencyCode': 'USD',
'currencyCode': 'USD'
},
'balanceUpdateTime': {
'date': '2020-04-12T16:20:50.52-04:00',
},
'date': '2020-04-12T16:20:50.52-04:00'
}
}
data += '--batch_createobjectbatch\n'
data += 'Content-Type: application/json\n\n'
data += 'POST /walletobjects/v1/giftCardObject/\n\n'
data += json.dumps(batch_gift_card_object) + '\n\n'
data += json.dumps(batch_object) + '\n\n'
data += '--batch_createobjectbatch--'

File diff suppressed because it is too large Load Diff

View File

@@ -19,8 +19,6 @@
# [START imports]
import json
import os
import re
from typing import List
import uuid
from google.auth.transport.requests import AuthorizedSession
@@ -42,6 +40,9 @@ class DemoOffer:
self.key_file_path = os.environ.get('GOOGLE_APPLICATION_CREDENTIALS',
'/path/to/key.json')
self.base_url = 'https://walletobjects.googleapis.com/walletobjects/v1'
self.batch_url = 'https://walletobjects.googleapis.com/batch'
self.class_url = f'{self.base_url}/offerClass'
self.object_url = f'{self.base_url}/offerObject'
# Set up authenticated client
self.auth()
@@ -59,11 +60,9 @@ class DemoOffer:
# [END auth]
# [START class]
def create_offer_class(self, issuer_id: str, class_suffix: str) -> str:
"""Create a class via the API.
This can also be done in the Google Pay and Wallet console.
# [START createClass]
def create_class(self, issuer_id: str, class_suffix: str) -> str:
"""Create a class.
Args:
issuer_id (str): The issuer ID being used for this request.
@@ -72,143 +71,465 @@ class DemoOffer:
Returns:
The pass class ID: f"{issuer_id}.{class_suffix}"
"""
class_url = f'{self.base_url}/offerClass'
# See below for more information on required properties
# Check if the class exists
response = self.http_client.get(
url=f'{self.class_url}/{issuer_id}.{class_suffix}')
if response.status_code == 200:
print(f'Class {issuer_id}.{class_suffix} already exists!')
return f'{issuer_id}.{class_suffix}'
elif response.status_code != 404:
# Something else went wrong...
print(response.text)
return f'{issuer_id}.{class_suffix}'
# See link below for more information on required properties
# https://developers.google.com/wallet/retail/offers/rest/v1/offerclass
offer_class = {
new_class = {
'id': f'{issuer_id}.{class_suffix}',
'issuerName': 'Issuer name',
'reviewStatus': 'UNDER_REVIEW',
'provider': 'Provider name',
'title': 'Offer title',
'redemptionChannel': 'ONLINE',
'redemptionChannel': 'ONLINE'
}
response = self.http_client.post(
url=class_url,
json=offer_class,
)
response = self.http_client.post(url=self.class_url, json=new_class)
print('Class insert response')
print(response.text)
return response.json().get('id')
# [END class]
# [END createClass]
# [START object]
def create_offer_object(self, issuer_id: str, class_suffix: str,
user_id: str) -> str:
"""Create an object via the API.
# [START updateClass]
def update_class(self, issuer_id: str, class_suffix: str) -> str:
"""Update a class.
**Warning:** This replaces all existing class attributes!
Args:
issuer_id (str): The issuer ID being used for this request.
class_suffix (str): Developer-defined unique ID for this pass class.
user_id (str): Developer-defined user ID for this pass object.
Returns:
The pass object ID: f"{issuer_id}.{user_id}"
The pass class ID: f"{issuer_id}.{class_suffix}"
"""
object_url = f'{self.base_url}/offerObject'
# Generate the object ID
# Should only include alphanumeric characters, '.', '_', or '-'
new_user_id = re.sub(r'[^\w.-]', '_', user_id)
object_id = f'{issuer_id}.{new_user_id}'
# Check if the class exists
response = self.http_client.get(
url=f'{self.class_url}/{issuer_id}.{class_suffix}')
# See below for more information on required properties
if response.status_code == 404:
print(f'Class {issuer_id}.{class_suffix} not found!')
return f'{issuer_id}.{class_suffix}'
elif response.status_code != 200:
# Something else went wrong...
print(response.text)
return f'{issuer_id}.{class_suffix}'
# Class exists
updated_class = response.json()
# Update the class by adding a homepage
updated_class['homepageUri'] = {
'uri': 'https://developers.google.com/wallet',
'description': 'Homepage description'
}
# Note: reviewStatus must be 'UNDER_REVIEW' or 'DRAFT' for updates
updated_class['reviewStatus'] = 'UNDER_REVIEW'
response = self.http_client.put(
url=f'{self.class_url}/{issuer_id}.{class_suffix}',
json=updated_class)
print('Class update response')
print(response.text)
return response.json().get('id')
# [END updateClass]
# [START patchClass]
def patch_class(self, issuer_id: str, class_suffix: str) -> str:
"""Patch a class.
The PATCH method supports patch semantics.
Args:
issuer_id (str): The issuer ID being used for this request.
class_suffix (str): Developer-defined unique ID for this pass class.
Returns:
The pass class ID: f"{issuer_id}.{class_suffix}"
"""
# Check if the class exists
response = self.http_client.get(
url=f'{self.class_url}/{issuer_id}.{class_suffix}')
if response.status_code == 404:
print(f'Class {issuer_id}.{class_suffix} not found!')
return f'{issuer_id}.{class_suffix}'
elif response.status_code != 200:
# Something else went wrong...
print(response.text)
return f'{issuer_id}.{class_suffix}'
# Patch the class by adding a homepage
patch_body = {
'homepageUri': {
'uri': 'https://developers.google.com/wallet',
'description': 'Homepage description'
},
# Note: reviewStatus must be 'UNDER_REVIEW' or 'DRAFT' for patches
'reviewStatus': 'UNDER_REVIEW'
}
response = self.http_client.patch(
url=f'{self.class_url}/{issuer_id}.{class_suffix}', json=patch_body)
print('Class patch response')
print(response.text)
return response.json().get('id')
# [END patchClass]
# [START addMessageClass]
def add_class_message(self, issuer_id: str, class_suffix: str, header: str,
body: str) -> str:
"""Add a message to a pass class.
Args:
issuer_id (str): The issuer ID being used for this request.
class_suffix (str): Developer-defined unique ID for this pass class.
header (str): The message header.
body (str): The message body.
Returns:
The pass class ID: f"{issuer_id}.{class_suffix}"
"""
# Check if the class exists
response = self.http_client.get(
url=f'{self.class_url}/{issuer_id}.{class_suffix}')
if response.status_code == 404:
print(f'Class {issuer_id}.{class_suffix} not found!')
return f'{issuer_id}.{class_suffix}'
elif response.status_code != 200:
# Something else went wrong...
print(response.text)
return f'{issuer_id}.{class_suffix}'
response = self.http_client.post(
url=f'{self.class_url}/{issuer_id}.{class_suffix}/addMessage',
json={'message': {
'header': header,
'body': body
}})
print('Class addMessage response')
print(response.text)
return response.json().get('id')
# [END addMessageClass]
# [START createObject]
def create_object(self, issuer_id: str, class_suffix: str,
object_suffix: str) -> str:
"""Create an object.
Args:
issuer_id (str): The issuer ID being used for this request.
class_suffix (str): Developer-defined unique ID for the pass class.
object_suffix (str): Developer-defined unique ID for the pass object.
Returns:
The pass object ID: f"{issuer_id}.{object_suffix}"
"""
# Check if the object exists
response = self.http_client.get(
url=f'{self.object_url}/{issuer_id}.{object_suffix}')
if response.status_code == 200:
print(f'Object {issuer_id}.{object_suffix} already exists!')
print(response.text)
return f'{issuer_id}.{object_suffix}'
elif response.status_code != 404:
# Something else went wrong...
print(response.text)
return f'{issuer_id}.{object_suffix}'
# See link below for more information on required properties
# https://developers.google.com/wallet/retail/offers/rest/v1/offerobject
offer_object = {
'id': f'{object_id}',
new_object = {
'id': f'{issuer_id}.{object_suffix}',
'classId': f'{issuer_id}.{class_suffix}',
'state': 'ACTIVE',
'heroImage': {
'sourceUri': {
'uri':
'https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg',
'https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg'
},
'contentDescription': {
'defaultValue': {
'language': 'en-US',
'value': 'Hero image description',
},
},
'value': 'Hero image description'
}
}
},
'textModulesData': [{
'header': 'Text module header',
'body': 'Text module body',
'id': 'TEXT_MODULE_ID',
},],
'id': 'TEXT_MODULE_ID'
}],
'linksModuleData': {
'uris': [
{
'uri': 'http://maps.google.com/',
'description': 'Link module URI description',
'id': 'LINK_MODULE_URI_ID',
},
{
'uri': 'tel:6505555555',
'description': 'Link module tel description',
'id': 'LINK_MODULE_TEL_ID',
},
],
'uris': [{
'uri': 'http://maps.google.com/',
'description': 'Link module URI description',
'id': 'LINK_MODULE_URI_ID'
}, {
'uri': 'tel:6505555555',
'description': 'Link module tel description',
'id': 'LINK_MODULE_TEL_ID'
}]
},
'imageModulesData': [{
'mainImage': {
'sourceUri': {
'uri':
'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg',
'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg'
},
'contentDescription': {
'defaultValue': {
'language': 'en-US',
'value': 'Image module description',
},
},
'value': 'Image module description'
}
}
},
'id': 'IMAGE_MODULE_ID',
},],
'id': 'IMAGE_MODULE_ID'
}],
'barcode': {
'type': 'QR_CODE',
'value': 'QR code',
'value': 'QR code'
},
'locations': [{
'latitude': 37.424015499999996,
'longitude': -122.09259560000001,
},],
'longitude': -122.09259560000001
}],
'validTimeInterval': {
'start': {
'date': '2023-06-12T23:20:50.52Z',
'date': '2023-06-12T23:20:50.52Z'
},
'end': {
'date': '2023-12-12T23:20:50.52Z',
},
},
'date': '2023-12-12T23:20:50.52Z'
}
}
}
response = self.http_client.get(f'{object_url}{object_id}')
if response.status_code == 404:
# Object does not yet exist
# Send POST request to create it
response = self.http_client.post(
url=object_url,
json=offer_object,
)
# Create the object
response = self.http_client.post(url=self.object_url, json=new_object)
print('Object insert response')
print(response.text)
else:
print('Object get response')
print(response.text)
print('Object insert response')
print(response.text)
return response.json().get('id')
# [END object]
# [END createObject]
# [START jwt]
def create_jwt_save_url(self, issuer_id: str, class_suffix: str,
user_id: str) -> str:
# [START updateObject]
def update_object(self, issuer_id: str, object_suffix: str) -> str:
"""Update an object.
**Warning:** This replaces all existing object attributes!
Args:
issuer_id (str): The issuer ID being used for this request.
object_suffix (str): Developer-defined unique ID for the pass object.
Returns:
The pass object ID: f"{issuer_id}.{object_suffix}"
"""
# Check if the object exists
response = self.http_client.get(
url=f'{self.object_url}/{issuer_id}.{object_suffix}')
if response.status_code == 404:
print(f'Object {issuer_id}.{object_suffix} not found!')
return f'{issuer_id}.{object_suffix}'
elif response.status_code != 200:
# Something else went wrong...
print(response.text)
return f'{issuer_id}.{object_suffix}'
# Object exists
updated_object = response.json()
# Update the object by adding a link
new_link = {
'uri': 'https://developers.google.com/wallet',
'description': 'New link description'
}
if not updated_object.get('linksModuleData'):
updated_object['linksModuleData'] = {'uris': []}
updated_object['linksModuleData']['uris'].append(new_link)
response = self.http_client.put(
url=f'{self.object_url}/{issuer_id}.{object_suffix}',
json=updated_object)
print('Object update response')
print(response.text)
return response.json().get('id')
# [END updateObject]
# [START patchObject]
def patch_object(self, issuer_id: str, object_suffix: str) -> str:
"""Patch an object.
Args:
issuer_id (str): The issuer ID being used for this request.
object_suffix (str): Developer-defined unique ID for the pass object.
Returns:
The pass object ID: f"{issuer_id}.{object_suffix}"
"""
# Check if the object exists
response = self.http_client.get(
url=f'{self.object_url}/{issuer_id}.{object_suffix}')
if response.status_code == 404:
print(f'Object {issuer_id}.{object_suffix} not found!')
return f'{issuer_id}.{object_suffix}'
elif response.status_code != 200:
# Something else went wrong...
print(response.text)
return f'{issuer_id}.{object_suffix}'
# Object exists
existing_object = response.json()
# Patch the object by adding a link
patch_body = {}
new_link = {
'uri': 'https://developers.google.com/wallet',
'description': 'New link description'
}
if existing_object.get('linksModuleData'):
patch_body['linksModuleData'] = existing_object['linksModuleData']
else:
patch_body['linksModuleData'] = {'uris': []}
patch_body['linksModuleData']['uris'].append(new_link)
response = self.http_client.patch(
url=f'{self.object_url}/{issuer_id}.{object_suffix}',
json=patch_body)
print('Object patch response')
print(response.text)
return response.json().get('id')
# [END patchObject]
# [START expireObject]
def expire_object(self, issuer_id: str, object_suffix: str) -> str:
"""Expire an object.
Sets the object's state to Expired. If the valid time interval is
already set, the pass will expire automatically up to 24 hours after.
Args:
issuer_id (str): The issuer ID being used for this request.
object_suffix (str): Developer-defined unique ID for the pass object.
Returns:
The pass object ID: f"{issuer_id}.{object_suffix}"
"""
# Check if the object exists
response = self.http_client.get(
url=f'{self.object_url}/{issuer_id}.{object_suffix}')
if response.status_code == 404:
print(f'Object {issuer_id}.{object_suffix} not found!')
return f'{issuer_id}.{object_suffix}'
elif response.status_code != 200:
# Something else went wrong...
print(response.text)
return f'{issuer_id}.{object_suffix}'
# Patch the object, setting the pass as expired
patch_body = {'state': 'EXPIRED'}
response = self.http_client.patch(
url=f'{self.object_url}/{issuer_id}.{object_suffix}',
json=patch_body)
print('Object expiration response')
print(response.text)
return response.json().get('id')
# [END expireObject]
# [START addMessageObject]
def add_object_message(self, issuer_id: str, object_suffix: str,
header: str, body: str) -> str:
"""Add a message to a pass object.
Args:
issuer_id (str): The issuer ID being used for this request.
object_suffix (str): Developer-defined unique ID for this pass object.
header (str): The message header.
body (str): The message body.
Returns:
The pass class ID: f"{issuer_id}.{class_suffix}"
"""
# Check if the object exists
response = self.http_client.get(
url=f'{self.object_url}/{issuer_id}.{object_suffix}')
if response.status_code == 404:
print(f'Object {issuer_id}.{object_suffix} not found!')
return f'{issuer_id}.{object_suffix}'
elif response.status_code != 200:
# Something else went wrong...
print(response.text)
return f'{issuer_id}.{object_suffix}'
response = self.http_client.post(
url=f'{self.object_url}/{issuer_id}.{object_suffix}/addMessage',
json={'message': {
'header': header,
'body': body
}})
print('Object addMessage response')
print(response.text)
return response.json().get('id')
# [END addMessageObject]
# [START jwtNew]
def create_jwt_new_objects(self, issuer_id: str, class_suffix: str,
object_suffix: str) -> str:
"""Generate a signed JWT that creates a new pass class and object.
When the user opens the "Add to Google Wallet" URL and saves the pass to
@@ -218,97 +539,89 @@ class DemoOffer:
Args:
issuer_id (str): The issuer ID being used for this request.
class_suffix (str): Developer-defined unique ID for this pass class.
user_id (str): Developer-defined user ID for this pass object.
class_suffix (str): Developer-defined unique ID for the pass class.
object_suffix (str): Developer-defined unique ID for the pass object.
Returns:
An "Add to Google Wallet" link
An "Add to Google Wallet" link.
"""
# Generate the object ID
# Should only include alphanumeric characters, '.', '_', or '-'
new_user_id = re.sub(r'[^\w.-]', '_', user_id)
object_id = f'{issuer_id}.{new_user_id}'
# See below for more information on required properties
# See link below for more information on required properties
# https://developers.google.com/wallet/retail/offers/rest/v1/offerclass
offer_class = {
new_class = {
'id': f'{issuer_id}.{class_suffix}',
'issuerName': 'Issuer name',
'reviewStatus': 'UNDER_REVIEW',
'provider': 'Provider name',
'title': 'Offer title',
'redemptionChannel': 'ONLINE',
'redemptionChannel': 'ONLINE'
}
# See below for more information on required properties
# See link below for more information on required properties
# https://developers.google.com/wallet/retail/offers/rest/v1/offerobject
offer_object = {
'id': f'{object_id}',
new_object = {
'id': f'{issuer_id}.{object_suffix}',
'classId': f'{issuer_id}.{class_suffix}',
'state': 'ACTIVE',
'heroImage': {
'sourceUri': {
'uri':
'https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg',
'https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg'
},
'contentDescription': {
'defaultValue': {
'language': 'en-US',
'value': 'Hero image description',
},
},
'value': 'Hero image description'
}
}
},
'textModulesData': [{
'header': 'Text module header',
'body': 'Text module body',
'id': 'TEXT_MODULE_ID',
},],
'id': 'TEXT_MODULE_ID'
}],
'linksModuleData': {
'uris': [
{
'uri': 'http://maps.google.com/',
'description': 'Link module URI description',
'id': 'LINK_MODULE_URI_ID',
},
{
'uri': 'tel:6505555555',
'description': 'Link module tel description',
'id': 'LINK_MODULE_TEL_ID',
},
],
'uris': [{
'uri': 'http://maps.google.com/',
'description': 'Link module URI description',
'id': 'LINK_MODULE_URI_ID'
}, {
'uri': 'tel:6505555555',
'description': 'Link module tel description',
'id': 'LINK_MODULE_TEL_ID'
}]
},
'imageModulesData': [{
'mainImage': {
'sourceUri': {
'uri':
'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg',
'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg'
},
'contentDescription': {
'defaultValue': {
'language': 'en-US',
'value': 'Image module description',
},
},
'value': 'Image module description'
}
}
},
'id': 'IMAGE_MODULE_ID',
},],
'id': 'IMAGE_MODULE_ID'
}],
'barcode': {
'type': 'QR_CODE',
'value': 'QR code',
'value': 'QR code'
},
'locations': [{
'latitude': 37.424015499999996,
'longitude': -122.09259560000001,
},],
'longitude': -122.09259560000001
}],
'validTimeInterval': {
'start': {
'date': '2023-06-12T23:20:50.52Z',
'date': '2023-06-12T23:20:50.52Z'
},
'end': {
'date': '2023-12-12T23:20:50.52Z',
},
},
'date': '2023-12-12T23:20:50.52Z'
}
}
}
# Create the JWT claims
@@ -319,9 +632,9 @@ class DemoOffer:
'typ': 'savetowallet',
'payload': {
# The listed classes and objects will be created
'offerClasses': [offer_class,],
'offerObjects': [offer_object,],
},
'offerClasses': [new_class],
'offerObjects': [new_object]
}
}
# The service account credentials are used to sign the JWT
@@ -333,79 +646,100 @@ class DemoOffer:
return f'https://pay.google.com/gp/v/save/{token}'
# [END jwt]
# [END jwtNew]
# [START createIssuer]
def create_issuer_account(self, issuer_name: str, issuer_email: str):
"""Create a new Google Wallet issuer account.
# [START jwtExisting]
def create_jwt_existing_objects(self, issuer_id: str) -> str:
"""Generate a signed JWT that references an existing pass object.
Args:
issuer_name (str): The issuer's name.
issuer_email (str): The issuer's email address.
"""
# Issuer API endpoint
issuer_url = f'{self.base_url}/issuer'
When the user opens the "Add to Google Wallet" URL and saves the pass to
their wallet, the pass objects defined in the JWT are added to the
user's Google Wallet app. This allows the user to save multiple pass
objects in one API call.
# New issuer information
issuer = {
'name': issuer_name,
'contactInfo': {
'email': issuer_email,
},
The objects to add must follow the below format:
{
'id': 'ISSUER_ID.OBJECT_SUFFIX',
'classId': 'ISSUER_ID.CLASS_SUFFIX'
}
# Make the POST request
response = self.http_client.post(
url=issuer_url,
json=issuer,
)
print('Issuer insert response')
print(response.text)
# [END createIssuer]
# [START updatePermissions]
def update_issuer_account_permissions(self, issuer_id: str,
permissions: List):
"""Update permissions for an existing Google Wallet issuer account.
**Warning:** This operation overwrites all existing
permissions!
Example permissions list argument below. Copy the dict entry as
needed for each email address that will need access. Supported
values for role are: 'READER', 'WRITER', and 'OWNER'
permissions = [
{
'emailAddress': 'email-address',
'role': 'OWNER',
},
]
Args:
issuer_id (str): The issuer ID being used for this request.
permissions (List): The list of email addresses and roles to assign.
Returns:
An "Add to Google Wallet" link
"""
# Permissions API endpoint
permissions_url = f'{self.base_url}/permissions/{issuer_id}'
response = self.http_client.put(
url=permissions_url,
json={
'issuerId': issuer_id,
'permissions': permissions,
},
)
# Multiple pass types can be added at the same time
# At least one type must be specified in the JWT claims
# Note: Make sure to replace the placeholder class and object suffixes
objects_to_add = {
# Event tickets
'eventTicketObjects': [{
'id': f'{issuer_id}.EVENT_OBJECT_SUFFIX',
'classId': f'{issuer_id}.EVENT_CLASS_SUFFIX'
}],
print('Permissions update response')
print(response.text)
# Boarding passes
'flightObjects': [{
'id': f'{issuer_id}.FLIGHT_OBJECT_SUFFIX',
'classId': f'{issuer_id}.FLIGHT_CLASS_SUFFIX'
}],
# [END updatePermissions]
# Generic passes
'genericObjects': [{
'id': f'{issuer_id}.GENERIC_OBJECT_SUFFIX',
'classId': f'{issuer_id}.GENERIC_CLASS_SUFFIX'
}],
# Gift cards
'giftCardObjects': [{
'id': f'{issuer_id}.GIFT_CARD_OBJECT_SUFFIX',
'classId': f'{issuer_id}.GIFT_CARD_CLASS_SUFFIX'
}],
# Loyalty cards
'loyaltyObjects': [{
'id': f'{issuer_id}.LOYALTY_OBJECT_SUFFIX',
'classId': f'{issuer_id}.LOYALTY_CLASS_SUFFIX'
}],
# Offers
'offerObjects': [{
'id': f'{issuer_id}.OFFER_OBJECT_SUFFIX',
'classId': f'{issuer_id}.OFFER_CLASS_SUFFIX'
}],
# Transit passes
'transitObjects': [{
'id': f'{issuer_id}.TRANSIT_OBJECT_SUFFIX',
'classId': f'{issuer_id}.TRANSIT_CLASS_SUFFIX'
}]
}
# Create the JWT claims
claims = {
'iss': self.credentials.service_account_email,
'aud': 'google',
'origins': ['www.example.com'],
'typ': 'savetowallet',
'payload': objects_to_add
}
# The service account credentials are used to sign the JWT
signer = crypt.RSASigner.from_service_account_file(self.key_file_path)
token = jwt.encode(signer, claims).decode('utf-8')
print('Add to Google Wallet link')
print(f'https://pay.google.com/gp/v/save/{token}')
return f'https://pay.google.com/gp/v/save/{token}'
# [END jwtExisting]
# [START batch]
def batch_create_offer_objects(self, issuer_id: str, class_suffix: str):
def batch_create_objects(self, issuer_id: str, class_suffix: str):
"""Batch create Google Wallet objects from an existing class.
The request body will be a multiline string. See below for information.
@@ -420,88 +754,81 @@ class DemoOffer:
# Example: Generate three new pass objects
for _ in range(3):
# Generate a random user ID
user_id = str(uuid.uuid4()).replace('[^\\w.-]', '_')
# Generate a random object suffix
object_suffix = str(uuid.uuid4()).replace('[^\\w.-]', '_')
# Generate an object ID with the user ID
# Should only include alphanumeric characters, '.', '_', or '-'
object_id = f'{issuer_id}.{user_id}'
# See below for more information on required properties
# See link below for more information on required properties
# https://developers.google.com/wallet/retail/offers/rest/v1/offerobject
batch_offer_object = {
'id': f'{object_id}',
batch_object = {
'id': f'{issuer_id}.{object_suffix}',
'classId': f'{issuer_id}.{class_suffix}',
'state': 'ACTIVE',
'heroImage': {
'sourceUri': {
'uri':
'https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg',
'https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg'
},
'contentDescription': {
'defaultValue': {
'language': 'en-US',
'value': 'Hero image description',
},
},
'value': 'Hero image description'
}
}
},
'textModulesData': [{
'header': 'Text module header',
'body': 'Text module body',
'id': 'TEXT_MODULE_ID',
},],
'id': 'TEXT_MODULE_ID'
}],
'linksModuleData': {
'uris': [
{
'uri': 'http://maps.google.com/',
'description': 'Link module URI description',
'id': 'LINK_MODULE_URI_ID',
},
{
'uri': 'tel:6505555555',
'description': 'Link module tel description',
'id': 'LINK_MODULE_TEL_ID',
},
],
'uris': [{
'uri': 'http://maps.google.com/',
'description': 'Link module URI description',
'id': 'LINK_MODULE_URI_ID'
}, {
'uri': 'tel:6505555555',
'description': 'Link module tel description',
'id': 'LINK_MODULE_TEL_ID'
}]
},
'imageModulesData': [{
'mainImage': {
'sourceUri': {
'uri':
'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg',
'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg'
},
'contentDescription': {
'defaultValue': {
'language': 'en-US',
'value': 'Image module description',
},
},
'value': 'Image module description'
}
}
},
'id': 'IMAGE_MODULE_ID',
},],
'id': 'IMAGE_MODULE_ID'
}],
'barcode': {
'type': 'QR_CODE',
'value': 'QR code',
'value': 'QR code'
},
'locations': [{
'latitude': 37.424015499999996,
'longitude': -122.09259560000001,
},],
'longitude': -122.09259560000001
}],
'validTimeInterval': {
'start': {
'date': '2023-06-12T23:20:50.52Z',
'date': '2023-06-12T23:20:50.52Z'
},
'end': {
'date': '2023-12-12T23:20:50.52Z',
},
},
'date': '2023-12-12T23:20:50.52Z'
}
}
}
data += '--batch_createobjectbatch\n'
data += 'Content-Type: application/json\n\n'
data += 'POST /walletobjects/v1/offerObject/\n\n'
data += json.dumps(batch_offer_object) + '\n\n'
data += json.dumps(batch_object) + '\n\n'
data += '--batch_createobjectbatch--'

File diff suppressed because it is too large Load Diff