Сохранение в Google Pay

Все категории карт используются схожим образом. Чтобы узнать, как добавить карты постоянного клиента, подарочные карты, специальные предложения, билеты и посадочные талоны в приложение Google Pay, ознакомьтесь со следующими разделами:

Как добавить кнопку для сети

Чтобы пользователи могли сохранять в Google Pay любые карты, специальные предложения, билеты на мероприятия и посадочные талоны, добавьте на свой ресурс кнопку Сохранить в Google Pay.

Когда посетитель сайта нажмет кнопку, на серверы Google отправится веб-токен JSON (JWT), который представляет карту клиента. Затем серверы создадут соответствующий ресурс Object, основанный на JWT, и свяжут его с аккаунтом пользователя.

Чтобы добавить на сайт кнопку Сохранить в Google Pay, нужно выполнить три действия.

  1. Определить класс Class для ваших объектов.
  2. Создать токен JWT, который представляет объект Object.
  3. Добавить кнопку Сохранить в Google Pay на веб-страницу.

В действиях ниже используются данные карт постоянного покупателя, но таким же образом можно настроить и другие типы карт.

1. Определите класс для своих объектов

Сначала определите класс LoyaltyClass. Чтобы добавить класс LoyaltyClass, отправьте запрос POST на следующий URI REST:

https://walletobjects.googleapis.com/walletobjects/v1/loyaltyClass

Добавьте параметр strict=true в URI REST, чтобы включить строгий анализ и найти дополнительные ошибки, например повторяющиеся поля идентификаторов:

https://walletobjects.googleapis.com/walletobjects/v1/loyaltyClass?strict=true

Ниже указан пример ресурса JSON с классом LoyaltyClass. Данные JSON необходимо передавать в запросе POST. В следующих примерах кода показано, как определить и добавить класс LoyaltyClass.

Ресурс

{
  "accountIdLabel": "Member Id",
  "accountNameLabel": "Member Name",
  "id": "2945482443380251551.ExampleClass1",
  "issuerName": "Baconrista",
  "kind": "walletobjects#loyaltyClass",
  "textModulesData": [
    {
      "header": "Rewards details",
      "body": "Welcome to Baconrista rewards.  Enjoy your rewards for being a loyal customer. " +
               "10 points for every dollar spent.  Redeem your points for free coffee, bacon and more!"
    }
  ],
  "linksModuleData": {
    "uris": [
      {
        "kind": "walletobjects#uri",
        "uri": "https://maps.google.com/map?q=google",
        "description": "Nearby Locations"
      },
      {
        "kind": "walletobjects#uri",
        "uri": "tel:6505555555",
        "description": "Call Customer Service"
      }
    ]
  },
  "imageModulesData": [
    {
      "mainImage": {
        "kind": "walletobjects#image",
        "sourceUri": {
          "kind": "walletobjects#uri",
          "uri": "https://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg",
          "description": "Coffee beans"
        }
      }
    }
  ],
  "messages": [{
    "header": "Welcome to Banconrista Rewards!",
    "body": "Featuring our new bacon donuts.",
    "kind": "walletobjects#walletObjectMessage"
  }],
  "locations": [{
    "kind": "walletobjects#latLongPoint",
    "latitude": 37.424015499999996,
    "longitude": -122.09259560000001
    },{
    "kind": "walletobjects#latLongPoint",
    "latitude": 37.424354,
    "longitude": -122.09508869999999
    },{
    "kind": "walletobjects#latLongPoint",
    "latitude": 37.7901435,
    "longitude": -122.39026709999997
    },{
    "kind": "walletobjects#latLongPoint",
    "latitude": 40.7406578,
    "longitude": -74.00208940000002
  }],
  "programLogo": {
    "kind": "walletobjects#image",
    "sourceUri": {
      "kind": "walletobjects#uri",
      "uri": "https://farm8.staticflickr.com/7340/11177041185_a61a7f2139_o.jpg"
    }
  },
  "programName": "Baconrista Rewards",
  "rewardsTier": "Gold",
  "rewardsTierLabel": "Tier",
  "reviewStatus": "underReview",
  "hexBackgroundColor": "#ffffff",
  "heroImage": {
   "kind": "walletobjects#image",
   "sourceUri": {
     "kind": "walletobjects#uri",
     "uri": "https://farm8.staticflickr.com/7302/11177240353_115daa5729_o.jpg"
   }
  }
}

Java

// Define the Image Module Data
List<ImageModuleData> imageModuleData = new ArrayList<ImageModuleData>();

ImageModuleData image = new ImageModuleData().setMainImage(
    new Image().setSourceUri(
        new ImageUri().setUri("http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg")));

imageModuleData.add(image);

// Define Text Module Data
List<TextModuleData> textModulesData = new ArrayList<TextModuleData>();

TextModuleData textModuleData = new TextModuleData().setHeader("Rewards details")
    .setBody(
        "Welcome to Baconrista rewards.  Enjoy your rewards for being a loyal customer.  10 points for ever dollar spent.  Redeem your points for free coffee, bacon and more!");
textModulesData.add(textModuleData);

// Define Links Module Data
List<Uri> uris = new ArrayList<Uri>();
Uri uri1 = new Uri().setDescription("Nearby Locations").setUri("http://maps.google.com/?q=google");
Uri uri2 = new Uri().setDescription("Call Customer Service").setUri("tel:6505555555");

uris.add(uri1);
uris.add(uri2);

LinksModuleData linksModuleData = new LinksModuleData().setUris(uris);

// Define general messages
List<Message> messages = new ArrayList<Message>();
Message message = new Message()
    .setHeader("Welcome to Baconrista")
    .setBody("Featuring our new bacon donuts.");
messages.add(message);

// Define Geofence locations
List<LatLongPoint> locations = new ArrayList<LatLongPoint>();
locations.add(new LatLongPoint().setLatitude(37.422601).setLongitude(
    -122.085286));
locations.add(new LatLongPoint().setLatitude(37.424354).setLongitude(
    -122.09508869999999));
locations.add(new LatLongPoint().setLatitude(40.7406578).setLongitude(
    -74.00208940000002));

// Create class
LoyaltyClass wobClass = new LoyaltyClass()
    .setId('2945482443380251551.ExampleClass1')
    .setIssuerName("Baconrista")
    .setProgramName("Baconrista Rewards")
    .setProgramLogo(
        new Image().setSourceUri(new ImageUri()
            .setUri("http://farm8.staticflickr.com/7340/11177041185_a61a7f2139_o.jpg")))
    .setRewardsTierLabel("Tier").setRewardsTier("Gold")
    .setImageModulesData(imageModuleData)
    .setTextModulesData(textModulesData)
    .setLinksModuleData(linksModuleData)
    .setAccountNameLabel("Member Name").setAccountIdLabel("Member Id")
    .setMessages(messages)
    .setReviewStatus("underReview").setMultipleDevicesAndHoldersAllowedStatus("multipleHolders")
    .setLocations(locations);

LoyaltyClass response = client.loyaltyclass().insert(wobClass).execute();

PHP

// Define text module data.
$textModulesData = array(
    array(
        'header' => 'Rewards details',
        'body' => 'Welcome to Baconrista rewards.  Enjoy your rewards for being a loyal customer. ' .
            '10 points for every dollar spent.  Redeem your points for free coffee, bacon and more!'
    )
);
// Define links module data.
$linksModuleData = new Google_Service_Walletobjects_LinksModuleData();
$uris = array (
    array(
        'uri' => 'http://maps.google.com/map?q=google',
        'kind' => 'walletobjecs#uri',
        'description' => 'Nearby Locations'
    ),
    array(
        'uri' => 'tel:6505555555',
        'kind' => 'walletobjecs#uri',
        'description' => 'Call Customer Service'
    )
);
$linksModuleData->setUris($uris);

$uriModuleImageInstance = new Google_Service_Walletobjects_ImageUri();
$uriModuleImageInstance->setUri(
    'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg'
);
$uriModuleImageInstance->setDescription('Coffee beans');
$imageModuleImageInstance = new Google_Service_Walletobjects_Image();
$imageModuleImageInstance->setSourceUri($uriModuleImageInstance);
$imagesModuleData = new Google_Service_Walletobjects_ImageModuleData();
$imagesModuleData->setMainImage($imageModuleImageInstance);
$imagesModuleDataArr = array ($imagesModuleData);

// Messages to be displayed to all users of Wallet Objects.
$messages = array(array(
    'header' => 'Welcome to Banconrista Rewards!',
    'body' => 'Featuring our new bacon donuts.',
    'kind' => 'walletobjects#walletObjectMessage'
));
$locations = array(
    array(
        'kind' => 'walletobjects#latLongPoint',
        'latitude' => 37.424015499999996,
        'longitude' => -122.09259560000001
    ),
    array(
        'kind' => 'walletobjects#latLongPoint',
        'latitude' => 37.424354,
        'longitude' => -122.09508869999999
    ),
    array(
        'kind' => 'walletobjects#latLongPoint',
        'latitude' => 37.7901435,
        'longitude' => -122.39026709999997
    ),
    array(
        'kind' => 'walletobjects#latLongPoint',
        'latitude' => 40.7406578,
        'longitude' => -74.00208940000002
    )
);
// Source uri of program logo.
$uriInstance = new Google_Service_Walletobjects_ImageUri();
$imageInstance = new Google_Service_Walletobjects_Image();
$uriInstance->setUri(
    'http://farm8.staticflickr.com/7340/11177041185_a61a7f2139_o.jpg'
);
$imageInstance->setSourceUri($uriInstance);
// Create wallet class.
$wobClass = new Google_Service_Walletobjects_LoyaltyClass();
$wobClass->setId('2945482443380251551.ExampleClass1');
$wobClass->setIssuerName('Baconrista');
$wobClass->setProgramName('Baconrista Rewards');
$wobClass->setProgramLogo($imageInstance);
$wobClass->setRewardsTierLabel('Tier');
$wobClass->setRewardsTier('Gold');
$wobClass->setAccountNameLabel('Member Name');
$wobClass->setAccountIdLabel('Member Id');
$wobClass->setLinksModuleData($linksModuleData);
$wobClass->setTextModulesData($textModulesData);
$wobClass->setImageModulesData($imagesModuleDataArr);
$wobClass->setMessages($messages);
$wobClass->setReviewStatus('underReview');
$wobClass->setMultipleDevicesAndHoldersAllowedStatus('multipleHolders');
$wobClass->setLocations($locations);

$service->loyaltyclass->insert($wobClass);

Python

loyalty_class = {
  'accountIdLabel': 'Member Id',
  'accountNameLabel': 'Member Name',
  'multipleDevicesAndHoldersAllowedStatus': 'multipleHolders',
  'id': '2945482443380251551.ExampleClass1',
  'issuerName': 'Baconrista',
  'kind': 'walletobjects#loyaltyClass',
  'locations': [{
      'kind': 'walletobjects#latLongPoint',
      'latitude': 37.424015499999996,
      'longitude': -122.09259560000001
      },{
      'kind': 'walletobjects#latLongPoint',
      'latitude': 37.424354,
      'longitude': -122.09508869999999
      },{
      'kind': 'walletobjects#latLongPoint',
      'latitude': 37.7901435,
      'longitude': -122.39026709999997
      },{
      'kind': 'walletobjects#latLongPoint',
      'latitude': 40.7406578,
      'longitude': -74.00208940000002
  }],
  'textModulesData': [{
    'header': 'Rewards details',
    'body': 'Welcome to Baconrista rewards.  Enjoy your rewards for being a loyal customer. ' +
            '10 points for ever dollar spent.  Redeem your points for free coffee, bacon and more! '
  }],
  'linksModuleData': {
    'uris': [
      {
        'kind': 'walletobjects#uri',
        'uri': 'http://maps.google.com/map?q=google',
        'description': 'Nearby Locations'
      },{
        'kind': 'walletobjects#uri',
        'uri': 'tel:6505555555',
        'description': 'Call Customer Service'
      }]
  },
  'imageModulesData': [
    {
      'mainImage': {
        'kind': 'walletobjects#image',
        'sourceUri': {
          'kind': 'walletobjects#uri',
          'uri':  'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg',
          'description': 'Coffee beans'
        }
      }
    }
  ],
  'messages': [{
      'header': 'Welcome to Banconrista Rewards!',
      'body': 'Featuring our new bacon donuts.',
      'kind': 'walletobjects#walletObjectMessage'
  }],
  'programLogo': {
      'kind': 'walletobjects#image',
      'sourceUri': {
          'kind': 'walletobjects#uri',
          'uri': 'http://farm8.staticflickr.com/7340/11177041185_a61a7f2139_o.jpg'
      }
  },
  'programName': 'Baconrista Rewards',
  'rewardsTier': 'Gold',
  'rewardsTierLabel': 'Tier',
  'reviewStatus': 'underReview',
}

api_request = service.loyaltyclass().insert(body=loyalty_class)
api_response = api_request.execute()

Полный список полей LoyaltyClass приведен в разделе Справочные материалы по LoyaltyClass.

2. Создайте токен JWT, который представляет объект

Сначала определите объект LoyaltyObject, как показано в нижеприведенных фрагментах кода.

Ресурс

{
  "classId": "2945482443380251551.ExampleClass1",
  "id": "2945482443380251551.ExampleObject1",
  "accountId": "1234567890",
  "accountName": "Jane Doe",
  "barcode": {
    "alternateText": "12345",
    "type": "qrCode",
    "value": "28343E3"
  },
  "textModulesData": [{
    "header": "Jane's Baconrista Rewards",
    "body": "Save more at your local Mountain View store Jane. " +
              "You get 1 bacon fat latte for every 5 coffees purchased.  " +
              "Also just for you, 10% off all pastries in the Mountain View store."
  }],
  "linksModuleData": {
    "uris": [
      {
        "kind": "walletobjects#uri",
        "uri": "https://www.baconrista.com/myaccount?id=1234567890",
        "description": "My Baconrista Account"
      }]
  },
  "infoModuleData": {
    "labelValueRows": [{
      "columns": [{
        "label": "Next Reward in",
        "value": "2 coffees"
      }, {
        "label": "Member Since",
        "value": "01/15/2013"
      }]
    }, {
      "columns": [{
        "label": "Local Store",
        "value": "Mountain View"
      }]
    }],
    "showLastUpdateTime": "true"
  },
  "loyaltyPoints": {
    "balance": {
      "string": "5000"
    },
    "label": "Points",
      "pointsType": "points"
  },
  "messages": [{
    "header": "Jane, welcome to Banconrista Rewards!",
    "body": "Thanks for joining our program. Show this message to " +
              "our barista for your first free coffee on us!"
  }],
  "state": "active"
}

Java

// Define Barcode
Barcode barcode = new Barcode().setType("qrCode")
    .setValue("28343E3")
    .setAlternateText("12345");

// Define Points
LoyaltyPoints points = new LoyaltyPoints()
    .setLabel("Points")
    .setPointsType("points")
    .setBalance(new LoyaltyPointsBalance().setString("500"));

// Define Text Module Data
List<TextModuleData> textModulesData = new ArrayList<TextModuleData>();
TextModuleData textModuleData = new TextModuleData()
    .setHeader("Jane's Baconrista Rewards")
    .setBody(
        "Save more at your local Mountain View store Jane.  You get 1 bacon fat latte for every 5 coffees purchased.  Also just for you, 10% off all pastries in the Mountain View store.");
textModulesData.add(textModuleData);

// Define Links Module Data
List<Uri> uris = new ArrayList<Uri>();
Uri uri1 = new Uri().setDescription("My Baconrista Account")
    .setUri("http://www.baconrista.com/myaccount?id=1234567890");
uris.add(uri1);
LinksModuleData linksModuleData = new LinksModuleData().setUris(uris);

// Define Info Module
List<LabelValue> row0cols = new ArrayList<LabelValue>();
LabelValue row0col0 = new LabelValue().setLabel("Next Reward in")
    .setValue("2 coffees");
LabelValue row0col1 = new LabelValue().setLabel("Member Since")
    .setValue("01/15/2013");
row0cols.add(row0col0);
row0cols.add(row0col1);

List<LabelValue> row1cols = new ArrayList<LabelValue>();
LabelValue row1col0 = new LabelValue().setLabel("Local Store")
    .setValue("Mountain View");
row1cols.add(row1col0);

List<LabelValueRow> rows = new ArrayList<LabelValueRow>();
LabelValueRow row0 = new LabelValueRow().setColumns(row0cols);
LabelValueRow row1 = new LabelValueRow().setColumns(row1cols);

rows.add(row0);
rows.add(row1);

InfoModuleData infoModuleData = new InfoModuleData()
    .setShowLastUpdateTime(true)
    .setLabelValueRows(rows);

// Define general messages
List<Message> messages = new ArrayList<Message>();
Message message = new Message()
    .setHeader("Hi Jane!")
    .setBody("Thanks for joining our program. Show this message to " +
        "our barista for your first free coffee on us!");
messages.add(message);

// Define Wallet Instance
LoyaltyObject object = new LoyaltyObject()
    .setClassId('2945482443380251551.ExampleClass1').setId('2945482443380251551.ExampleObject1')
    .setState("active").setBarcode(barcode).setInfoModuleData(infoModuleData)
    .setAccountName("Jane Doe").setTextModulesData(textModulesData)
    .setMessages(messages).setLinksModuleData(linksModuleData)
    .setAccountId("1234567890").setLoyaltyPoints(points);

PHP

$barcode = new Google_Service_Walletobjects_Barcode();
$barcode->setAlternateText('12345');
$barcode->setType('qrCode');
$barcode->setValue('28343E3');
// Define text module data.
$textModulesData = array(
    array(
        'header' => 'Janes Baconrista Rewards',
        'body' => 'Save more at your local Mountain View store Jane. ' .
                  'You get 1 bacon fat latte for every 5 coffees purchased. ' .
                  'Also just for you, 10% off all pastries in the Mountain View store.'
    )
);
// Define links module data.
$linksModuleData = new Google_Service_Walletobjects_LinksModuleData();
$uris = array (
    array(
        'uri' => 'http://www.baconrista.com/myaccount?id=1234567890',
        'kind' => 'walletobjecs#uri',
        'description' => 'My Baconrista Account'
    )
);
$linksModuleData->setUris($uris);
// Define label values.
$labelValueRows = array(
    array(
        'columns' => array(
            array(
                'label' => 'Next Reward in',
                'value' => '2 coffees'
            ), array(
                'label' => 'Member Since',
                'value' => '01/15/2013'
            )
        )
    ),
    array(
        'columns' => array(
            array(
                'label' => 'Local Store',
                'value' => 'Mountain View'
            )
        )
    )
);
// Define info module data.
$infoModuleData = new Google_Service_Walletobjects_InfoModuleData();
$infoModuleData->setShowLastUpdateTime(true);
$infoModuleData->setLabelValueRows($labelValueRows);
// Messages to be displayed.
$messages = array(array(
    'header' => 'Jane, welcome to Banconrista Rewards!',
    'body' => 'Thanks for joining our program. Show this message to '.
              'our barista for your first free coffee on us!',
    'kind' => 'walletobjects#walletObjectMessage'
));
// Reward points a user has.
$points = new Google_Service_Walletobjects_LoyaltyPoints();
$balance = new Google_Service_Walletobjects_LoyaltyPointsBalance();
$balance->setString('500');
$points->setBalance($balance);
$points->setLabel('Points');
$points->setPointsType('points');
// Create wallet object.
$wobObject = new Google_Service_Walletobjects_LoyaltyObject();
$wobObject->setClassId('2945482443380251551.ExampleClass1');
$wobObject->setId('2945482443380251551.ExampleObject1');
$wobObject->setState('active');
$wobObject->setBarcode($barcode);
$wobObject->setInfoModuleData($infoModuleData);
$wobObject->setLinksModuleData($linksModuleData);
$wobObject->setTextModulesData($textModulesData);
$wobObject->setAccountName('Jane Doe');
$wobObject->setAccountId('1234567890');
$wobObject->setLoyaltyPoints($points);
$wobObject->setMessages($messages);

Python

loyalty_object = {
  'classId' : '2945482443380251551.ExampleClass1',
  'id' : '2945482443380251551.ExampleObject1',
  'accountId': '1234567890',
  'accountName': 'Jane Doe',
  'barcode': {
      'alternateText' : '12345',
      'type' : 'qrCode',
      'value' : '28343E3'
  },
  'textModulesData': [{
    'header': 'Jane\'s Baconrista Rewards',
    'body': 'Save more at your local Mountain View store Jane. ' +
            ' You get 1 bacon fat latte for every 5 coffees purchased.  ' +
            'Also just for you, 10% off all pastries in the Mountain View store.'
  }],
  'linksModuleData': {
    'uris': [
      {
        'kind': 'walletobjects#uri',
        'uri': 'http://www.baconrista.com/myaccount?id=1234567890',
        'description': 'My Baconrista Account'
      }]
  },
  'infoModuleData': {
    'labelValueRows': [{
        'columns': [{
          'label': 'Next Reward in',
          'value': '2 coffees'
        }, {
          'label': 'Member Since',
          'value': '01/15/2013'
        }]
      },{
        'columns': [{
          'label': 'Local Store',
          'value': 'Mountain View'
        }]
    }],
    'showLastUpdateTime': 'true'
  },
  'messages': [{
      'header': 'Jane, welcome to Banconrista Rewards',
      'body': 'Thanks for joining our program. Show this message to ' +
              'our barista for your first free coffee on us!',
      'kind': 'walletobjects#walletObjectMessage'
  }],
  'loyaltyPoints': {
      'balance': {
          'string': '500'
      },
      'label': 'Points',
      'pointsType': 'points'
  },
  'state': 'active'
}

Закодируйте объект LoyaltyObject в токен JWT, используя закрытый ключ сервисного аккаунта OAuth 2.0. Ниже представлены примеры кодирования JWT на различных языках программирования. На вкладке "Протокол" токен JWT представлен в незакодированном виде. Более подробную информацию о полях токена можно найти в разделе "JWT для Google Pay API for Passes".

Протокол

{
  "iss": "example_service_account@developer.gserviceaccount.com",
  "aud": "google",
  "typ": "savetoandroidpay",
  "iat": 1368029586,
  "payload": {
    "eventTicketClasses": [{
      ... //Event ticket Class JSON
    }],
    "eventTicketObjects": [{
      ... //Event ticket Object JSON
    }],
    "flightClasses": [{
      ... //Flight Class JSON
    }],
    "flightObjects": [{
      ... //Flight Object JSON
    }],
    "giftCardClasses": [{
      ... //Gift card Class JSON
    }],
    "giftCardObjects": [{
      ... //Gift card Object JSON
    }],
    "loyaltyClasses": [{
      ... //Loyalty Class JSON
    }],
    "loyaltyObjects": [{
      ... //Loyalty Object JSON
    }],
    "offerClasses": [{
      ... //Offer Class JSON
    }],
    "offerObjects": [{
      ... //Offer Object JSON
    }],
    "transitClasses": [{
      ... //Transit Class JSON
    }],
    "transitObjects": [{
      ... //Transit Object JSON
    }]
  },
  "origins": ["http://baconrista.com", "https://baconrista.com"]
}

Java

WobCredentials credentials = null;
WobUtils utils = null;

// Instantiate the WobUtils class which contains handy functions
// Wob utils can be found in the quickstart sample
try {
  credentials = new WobCredentials(
    ServiceAccountEmailAddress,
    ServiceAccountPrivateKeyPath,
    ApplicationName,
    IssuerId);
  utils = new WobUtils(credentials);
} catch (GeneralSecurityException e) {
  e.printStackTrace();
} catch (IOException e) {
  e.printStackTrace();
}

// Add valid domains for the Save to Wallet button
List<String> origins = new ArrayList<String>();
origins.add("http://baconrista.com");
origins.add("https://baconrista.com");
origins.add(req.getScheme() + "://" + req.getServerName() + ":" + req.getLocalPort());

//Generate Objects and Classes here
//........

WobPayload payload = new WobPayload();
payload.addObject({WalletObject/WalletClass});

// Convert the object into a Save to Android Pay Jwt
String jwt = null;
try {
  jwt = utils.generateSaveJwt(payload, origins);
} catch (SignatureException e) {
  e.printStackTrace();
}

PHP

$requestBody = [
  "iss"=> SERVICE_ACCOUNT_EMAIL_ADDRESS,
  "aud" => "google",
  "typ" => "savetoandroidpay",
  "iat"=> time(),
  "payload" => {
    "eventTicketClasses" => [ ], # Event ticket classes
    "eventTicketObjects" => [ ], # Event ticket objects
    "flightClasses" => [ ],      # Flight classes
    "flightObjects" => [ ],      # Flight objects
    "giftCardClasses" => [ ],    # Gift card classes
    "giftCardObjects" => [ ],    # Gift card objects
    "loyaltyClasses" => [ ],     # Loyalty classes
    "loyaltyObjects" => [ ],     # Loyalty objects
    "offerClasses" => [ ],       # Offer classes
    "offerObjects" => [ ],       # Offer objects
    "transitClasses" => [ ],     # Transit classes
    "transitObjects" => [ ]      # Transit objects
  },
  "origins" => ["http://baconrista.com", "https://baconrista.com"]
]
// Generate the Save to Android Pay Jwt
echo $jwt = $assertObj->makeSignedJwt($requestBody, $client);

Python

jwt = {
  'iss': config.SERVICE_ACCOUNT_EMAIL_ADDRESS,
  'aud': 'google',
  'typ': 'savetoandroidpay',
  'iat':  int(time.time()),
  'payload': {
    'webserviceResponse': {
      'result': 'approved',
      'message': 'Success.'
    },
    'eventTicketClasses': [], # Event ticket classes
    'eventTicketObjects': [], # Event ticket objects
    'flightClasses': [],      # Flight classes
    'flightObjects': [],      # Flight objects
    'giftCardClasses': [],    # Gift card classes
    'giftCardObjects': [],    # Gift card objects
    'loyaltyClasses': [],     # Loyalty classes
    'loyaltyObjects': [],     # Loyalty objects
    'offerClasses': [],       # Offer classes
    'offerObjects': [],       # Offer objects
    'transitClasses': [],     # Transit classes
    'transitObjects': []      # Transit objects
  },
  'origins' : ['http://baconrista.com', 'https://baconrista.com']
}

// Generate the Save to Android Pay Jwt
signer = crypt.Signer.from_string(app_key)
signed_jwt = crypt.make_signed_jwt(signer, jwt)
response = webapp2.Response(signed_jwt)

Безопасная длина токена JSON – 1800 символов. Важно не превышать этот лимит. Иначе могут возникать ошибки при сохранении из-за усечения данных в браузерах. Объекты в токенах JWT должны содержать только важные для пользователя данные. Постарайтесь сохранить большую часть данных в классе, создав его раньше токена. Используйте REST API, если нужно сформировать крупный объект, и отправьте в JWT только его идентификатор.

3. Добавьте кнопку "Сохранить в Google Pay"

Скопируйте указанный ниже скрипт на то место страницы, где хотите разместить кнопку Сохранить в Google Pay.

<script src="https://apis.google.com/js/platform.js" type="text/javascript"></script>

Далее добавьте тег пространства имен g:savetoandroidpay, который определяет место размещения и атрибуты кнопки Сохранить в Google Pay. Добавьте ранее созданный токен JWT.

<g:savetoandroidpay jwt="{jwt_generated}" onsuccess="successHandler"
onfailure="failureHandler" size="small" theme="light" ></g:savetoandroidpay>

Теперь кнопка Сохранить в Google Pay должна отобразиться на странице.

Узнать больше о кнопке JavaScript можно в разделе Справочные материалы по Google Pay API for Passes для сетевых ресурсов.

Чтобы пользователи могли сохранить карту в Google Pay через электронную почту, добавьте в письмо кнопку со ссылкой на контент.

Для добавления кнопки Сохранить в Google Pay в электронное письмо или SMS выполните указанные ниже действия.

  1. Определите класс Class для создания ваших объектов.
  2. Создайте токен JWT, который представляет объект Object.
  3. Добавьте кнопку Сохранить в Google Pay в электронное письмо или SMS.

В действиях ниже используются данные карт постоянного покупателя, но таким же образом можно настроить и другие типы карт.

1. Определите класс для своих объектов

Сначала определите класс LoyaltyClass. Чтобы добавить класс LoyaltyClass, отправьте запрос POST на следующий URI REST:

https://walletobjects.googleapis.com/walletobjects/v1/loyaltyClass

Добавьте параметр strict=true в URI REST, чтобы включить строгий анализ и найти дополнительные ошибки, например повторяющиеся поля идентификаторов:

https://walletobjects.googleapis.com/walletobjects/v1/loyaltyClass?strict=true

Ниже указан пример ресурса JSON с классом LoyaltyClass. Данные JSON необходимо передавать в запросе POST. В следующих примерах кода показано, как определить и добавить класс LoyaltyClass.

Ресурс

{
  "accountIdLabel": "Member Id",
  "accountNameLabel": "Member Name",
  "id": "2945482443380251551.ExampleClass1",
  "issuerName": "Baconrista",
  "kind": "walletobjects#loyaltyClass",
  "textModulesData": [
    {
      "header": "Rewards details",
      "body": "Welcome to Baconrista rewards.  Enjoy your rewards for being a loyal customer. " +
               "10 points for every dollar spent.  Redeem your points for free coffee, bacon and more!"
    }
  ],
  "linksModuleData": {
    "uris": [
      {
        "kind": "walletobjects#uri",
        "uri": "https://maps.google.com/map?q=google",
        "description": "Nearby Locations"
      },
      {
        "kind": "walletobjects#uri",
        "uri": "tel:6505555555",
        "description": "Call Customer Service"
      }
    ]
  },
  "imageModulesData": [
    {
      "mainImage": {
        "kind": "walletobjects#image",
        "sourceUri": {
          "kind": "walletobjects#uri",
          "uri": "https://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg",
          "description": "Coffee beans"
        }
      }
    }
  ],
  "messages": [{
    "header": "Welcome to Banconrista Rewards!",
    "body": "Featuring our new bacon donuts.",
    "kind": "walletobjects#walletObjectMessage"
  }],
  "locations": [{
    "kind": "walletobjects#latLongPoint",
    "latitude": 37.424015499999996,
    "longitude": -122.09259560000001
    },{
    "kind": "walletobjects#latLongPoint",
    "latitude": 37.424354,
    "longitude": -122.09508869999999
    },{
    "kind": "walletobjects#latLongPoint",
    "latitude": 37.7901435,
    "longitude": -122.39026709999997
    },{
    "kind": "walletobjects#latLongPoint",
    "latitude": 40.7406578,
    "longitude": -74.00208940000002
  }],
  "programLogo": {
    "kind": "walletobjects#image",
    "sourceUri": {
      "kind": "walletobjects#uri",
      "uri": "https://farm8.staticflickr.com/7340/11177041185_a61a7f2139_o.jpg"
    }
  },
  "programName": "Baconrista Rewards",
  "rewardsTier": "Gold",
  "rewardsTierLabel": "Tier",
  "reviewStatus": "underReview",
  "hexBackgroundColor": "#ffffff",
  "heroImage": {
   "kind": "walletobjects#image",
   "sourceUri": {
     "kind": "walletobjects#uri",
     "uri": "https://farm8.staticflickr.com/7302/11177240353_115daa5729_o.jpg"
   }
  }
}

Java

// Define the Image Module Data
List<ImageModuleData> imageModuleData = new ArrayList<ImageModuleData>();

ImageModuleData image = new ImageModuleData().setMainImage(
    new Image().setSourceUri(
        new ImageUri().setUri("http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg")));

imageModuleData.add(image);

// Define Text Module Data
List<TextModuleData> textModulesData = new ArrayList<TextModuleData>();

TextModuleData textModuleData = new TextModuleData().setHeader("Rewards details")
    .setBody(
        "Welcome to Baconrista rewards.  Enjoy your rewards for being a loyal customer.  10 points for ever dollar spent.  Redeem your points for free coffee, bacon and more!");
textModulesData.add(textModuleData);

// Define Links Module Data
List<Uri> uris = new ArrayList<Uri>();
Uri uri1 = new Uri().setDescription("Nearby Locations").setUri("http://maps.google.com/?q=google");
Uri uri2 = new Uri().setDescription("Call Customer Service").setUri("tel:6505555555");

uris.add(uri1);
uris.add(uri2);

LinksModuleData linksModuleData = new LinksModuleData().setUris(uris);

// Define general messages
List<Message> messages = new ArrayList<Message>();
Message message = new Message()
    .setHeader("Welcome to Baconrista")
    .setBody("Featuring our new bacon donuts.");
messages.add(message);

// Define Geofence locations
List<LatLongPoint> locations = new ArrayList<LatLongPoint>();
locations.add(new LatLongPoint().setLatitude(37.422601).setLongitude(
    -122.085286));
locations.add(new LatLongPoint().setLatitude(37.424354).setLongitude(
    -122.09508869999999));
locations.add(new LatLongPoint().setLatitude(40.7406578).setLongitude(
    -74.00208940000002));

// Create class
LoyaltyClass wobClass = new LoyaltyClass()
    .setId('2945482443380251551.ExampleClass1')
    .setIssuerName("Baconrista")
    .setProgramName("Baconrista Rewards")
    .setProgramLogo(
        new Image().setSourceUri(new ImageUri()
            .setUri("http://farm8.staticflickr.com/7340/11177041185_a61a7f2139_o.jpg")))
    .setRewardsTierLabel("Tier").setRewardsTier("Gold")
    .setImageModulesData(imageModuleData)
    .setTextModulesData(textModulesData)
    .setLinksModuleData(linksModuleData)
    .setAccountNameLabel("Member Name").setAccountIdLabel("Member Id")
    .setMessages(messages)
    .setReviewStatus("underReview").setMultipleDevicesAndHoldersAllowedStatus("multipleHolders")
    .setLocations(locations);

LoyaltyClass response = client.loyaltyclass().insert(wobClass).execute();

PHP

// Define text module data.
$textModulesData = array(
    array(
        'header' => 'Rewards details',
        'body' => 'Welcome to Baconrista rewards.  Enjoy your rewards for being a loyal customer. ' .
            '10 points for every dollar spent.  Redeem your points for free coffee, bacon and more!'
    )
);
// Define links module data.
$linksModuleData = new Google_Service_Walletobjects_LinksModuleData();
$uris = array (
    array(
        'uri' => 'http://maps.google.com/map?q=google',
        'kind' => 'walletobjecs#uri',
        'description' => 'Nearby Locations'
    ),
    array(
        'uri' => 'tel:6505555555',
        'kind' => 'walletobjecs#uri',
        'description' => 'Call Customer Service'
    )
);
$linksModuleData->setUris($uris);

$uriModuleImageInstance = new Google_Service_Walletobjects_ImageUri();
$uriModuleImageInstance->setUri(
    'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg'
);
$uriModuleImageInstance->setDescription('Coffee beans');
$imageModuleImageInstance = new Google_Service_Walletobjects_Image();
$imageModuleImageInstance->setSourceUri($uriModuleImageInstance);
$imagesModuleData = new Google_Service_Walletobjects_ImageModuleData();
$imagesModuleData->setMainImage($imageModuleImageInstance);
$imagesModuleDataArr = array ($imagesModuleData);

// Messages to be displayed to all users of Wallet Objects.
$messages = array(array(
    'header' => 'Welcome to Banconrista Rewards!',
    'body' => 'Featuring our new bacon donuts.',
    'kind' => 'walletobjects#walletObjectMessage'
));
$locations = array(
    array(
        'kind' => 'walletobjects#latLongPoint',
        'latitude' => 37.424015499999996,
        'longitude' => -122.09259560000001
    ),
    array(
        'kind' => 'walletobjects#latLongPoint',
        'latitude' => 37.424354,
        'longitude' => -122.09508869999999
    ),
    array(
        'kind' => 'walletobjects#latLongPoint',
        'latitude' => 37.7901435,
        'longitude' => -122.39026709999997
    ),
    array(
        'kind' => 'walletobjects#latLongPoint',
        'latitude' => 40.7406578,
        'longitude' => -74.00208940000002
    )
);
// Source uri of program logo.
$uriInstance = new Google_Service_Walletobjects_ImageUri();
$imageInstance = new Google_Service_Walletobjects_Image();
$uriInstance->setUri(
    'http://farm8.staticflickr.com/7340/11177041185_a61a7f2139_o.jpg'
);
$imageInstance->setSourceUri($uriInstance);
// Create wallet class.
$wobClass = new Google_Service_Walletobjects_LoyaltyClass();
$wobClass->setId('2945482443380251551.ExampleClass1');
$wobClass->setIssuerName('Baconrista');
$wobClass->setProgramName('Baconrista Rewards');
$wobClass->setProgramLogo($imageInstance);
$wobClass->setRewardsTierLabel('Tier');
$wobClass->setRewardsTier('Gold');
$wobClass->setAccountNameLabel('Member Name');
$wobClass->setAccountIdLabel('Member Id');
$wobClass->setLinksModuleData($linksModuleData);
$wobClass->setTextModulesData($textModulesData);
$wobClass->setImageModulesData($imagesModuleDataArr);
$wobClass->setMessages($messages);
$wobClass->setReviewStatus('underReview');
$wobClass->setMultipleDevicesAndHoldersAllowedStatus('multipleHolders');
$wobClass->setLocations($locations);

$service->loyaltyclass->insert($wobClass);

Python

loyalty_class = {
  'accountIdLabel': 'Member Id',
  'accountNameLabel': 'Member Name',
  'multipleDevicesAndHoldersAllowedStatus': 'multipleHolders',
  'id': '2945482443380251551.ExampleClass1',
  'issuerName': 'Baconrista',
  'kind': 'walletobjects#loyaltyClass',
  'locations': [{
      'kind': 'walletobjects#latLongPoint',
      'latitude': 37.424015499999996,
      'longitude': -122.09259560000001
      },{
      'kind': 'walletobjects#latLongPoint',
      'latitude': 37.424354,
      'longitude': -122.09508869999999
      },{
      'kind': 'walletobjects#latLongPoint',
      'latitude': 37.7901435,
      'longitude': -122.39026709999997
      },{
      'kind': 'walletobjects#latLongPoint',
      'latitude': 40.7406578,
      'longitude': -74.00208940000002
  }],
  'textModulesData': [{
    'header': 'Rewards details',
    'body': 'Welcome to Baconrista rewards.  Enjoy your rewards for being a loyal customer. ' +
            '10 points for ever dollar spent.  Redeem your points for free coffee, bacon and more! '
  }],
  'linksModuleData': {
    'uris': [
      {
        'kind': 'walletobjects#uri',
        'uri': 'http://maps.google.com/map?q=google',
        'description': 'Nearby Locations'
      },{
        'kind': 'walletobjects#uri',
        'uri': 'tel:6505555555',
        'description': 'Call Customer Service'
      }]
  },
  'imageModulesData': [
    {
      'mainImage': {
        'kind': 'walletobjects#image',
        'sourceUri': {
          'kind': 'walletobjects#uri',
          'uri':  'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg',
          'description': 'Coffee beans'
        }
      }
    }
  ],
  'messages': [{
      'header': 'Welcome to Banconrista Rewards!',
      'body': 'Featuring our new bacon donuts.',
      'kind': 'walletobjects#walletObjectMessage'
  }],
  'programLogo': {
      'kind': 'walletobjects#image',
      'sourceUri': {
          'kind': 'walletobjects#uri',
          'uri': 'http://farm8.staticflickr.com/7340/11177041185_a61a7f2139_o.jpg'
      }
  },
  'programName': 'Baconrista Rewards',
  'rewardsTier': 'Gold',
  'rewardsTierLabel': 'Tier',
  'reviewStatus': 'underReview',
}

api_request = service.loyaltyclass().insert(body=loyalty_class)
api_response = api_request.execute()

Полный список полей LoyaltyClass приведен в разделе Справочные материалы по LoyaltyClass.

2. Создайте токен JWT, который представляет объект

Сначала определите объект LoyaltyObject, как показано в нижеприведенных фрагментах кода.

Ресурс

{
  "classId": "2945482443380251551.ExampleClass1",
  "id": "2945482443380251551.ExampleObject1",
  "accountId": "1234567890",
  "accountName": "Jane Doe",
  "barcode": {
    "alternateText": "12345",
    "type": "qrCode",
    "value": "28343E3"
  },
  "textModulesData": [{
    "header": "Jane's Baconrista Rewards",
    "body": "Save more at your local Mountain View store Jane. " +
              "You get 1 bacon fat latte for every 5 coffees purchased.  " +
              "Also just for you, 10% off all pastries in the Mountain View store."
  }],
  "linksModuleData": {
    "uris": [
      {
        "kind": "walletobjects#uri",
        "uri": "https://www.baconrista.com/myaccount?id=1234567890",
        "description": "My Baconrista Account"
      }]
  },
  "infoModuleData": {
    "labelValueRows": [{
      "columns": [{
        "label": "Next Reward in",
        "value": "2 coffees"
      }, {
        "label": "Member Since",
        "value": "01/15/2013"
      }]
    }, {
      "columns": [{
        "label": "Local Store",
        "value": "Mountain View"
      }]
    }],
    "showLastUpdateTime": "true"
  },
  "loyaltyPoints": {
    "balance": {
      "string": "5000"
    },
    "label": "Points",
      "pointsType": "points"
  },
  "messages": [{
    "header": "Jane, welcome to Banconrista Rewards!",
    "body": "Thanks for joining our program. Show this message to " +
              "our barista for your first free coffee on us!"
  }],
  "state": "active"
}

Java

// Define Barcode
Barcode barcode = new Barcode().setType("qrCode")
    .setValue("28343E3")
    .setAlternateText("12345");

// Define Points
LoyaltyPoints points = new LoyaltyPoints()
    .setLabel("Points")
    .setPointsType("points")
    .setBalance(new LoyaltyPointsBalance().setString("500"));

// Define Text Module Data
List<TextModuleData> textModulesData = new ArrayList<TextModuleData>();
TextModuleData textModuleData = new TextModuleData()
    .setHeader("Jane's Baconrista Rewards")
    .setBody(
        "Save more at your local Mountain View store Jane.  You get 1 bacon fat latte for every 5 coffees purchased.  Also just for you, 10% off all pastries in the Mountain View store.");
textModulesData.add(textModuleData);

// Define Links Module Data
List<Uri> uris = new ArrayList<Uri>();
Uri uri1 = new Uri().setDescription("My Baconrista Account")
    .setUri("http://www.baconrista.com/myaccount?id=1234567890");
uris.add(uri1);
LinksModuleData linksModuleData = new LinksModuleData().setUris(uris);

// Define Info Module
List<LabelValue> row0cols = new ArrayList<LabelValue>();
LabelValue row0col0 = new LabelValue().setLabel("Next Reward in")
    .setValue("2 coffees");
LabelValue row0col1 = new LabelValue().setLabel("Member Since")
    .setValue("01/15/2013");
row0cols.add(row0col0);
row0cols.add(row0col1);

List<LabelValue> row1cols = new ArrayList<LabelValue>();
LabelValue row1col0 = new LabelValue().setLabel("Local Store")
    .setValue("Mountain View");
row1cols.add(row1col0);

List<LabelValueRow> rows = new ArrayList<LabelValueRow>();
LabelValueRow row0 = new LabelValueRow().setColumns(row0cols);
LabelValueRow row1 = new LabelValueRow().setColumns(row1cols);

rows.add(row0);
rows.add(row1);

InfoModuleData infoModuleData = new InfoModuleData()
    .setShowLastUpdateTime(true)
    .setLabelValueRows(rows);

// Define general messages
List<Message> messages = new ArrayList<Message>();
Message message = new Message()
    .setHeader("Hi Jane!")
    .setBody("Thanks for joining our program. Show this message to " +
        "our barista for your first free coffee on us!");
messages.add(message);

// Define Wallet Instance
LoyaltyObject object = new LoyaltyObject()
    .setClassId('2945482443380251551.ExampleClass1').setId('2945482443380251551.ExampleObject1')
    .setState("active").setBarcode(barcode).setInfoModuleData(infoModuleData)
    .setAccountName("Jane Doe").setTextModulesData(textModulesData)
    .setMessages(messages).setLinksModuleData(linksModuleData)
    .setAccountId("1234567890").setLoyaltyPoints(points);

PHP

$barcode = new Google_Service_Walletobjects_Barcode();
$barcode->setAlternateText('12345');
$barcode->setType('qrCode');
$barcode->setValue('28343E3');
// Define text module data.
$textModulesData = array(
    array(
        'header' => 'Janes Baconrista Rewards',
        'body' => 'Save more at your local Mountain View store Jane. ' .
                  'You get 1 bacon fat latte for every 5 coffees purchased. ' .
                  'Also just for you, 10% off all pastries in the Mountain View store.'
    )
);
// Define links module data.
$linksModuleData = new Google_Service_Walletobjects_LinksModuleData();
$uris = array (
    array(
        'uri' => 'http://www.baconrista.com/myaccount?id=1234567890',
        'kind' => 'walletobjecs#uri',
        'description' => 'My Baconrista Account'
    )
);
$linksModuleData->setUris($uris);
// Define label values.
$labelValueRows = array(
    array(
        'columns' => array(
            array(
                'label' => 'Next Reward in',
                'value' => '2 coffees'
            ), array(
                'label' => 'Member Since',
                'value' => '01/15/2013'
            )
        )
    ),
    array(
        'columns' => array(
            array(
                'label' => 'Local Store',
                'value' => 'Mountain View'
            )
        )
    )
);
// Define info module data.
$infoModuleData = new Google_Service_Walletobjects_InfoModuleData();
$infoModuleData->setShowLastUpdateTime(true);
$infoModuleData->setLabelValueRows($labelValueRows);
// Messages to be displayed.
$messages = array(array(
    'header' => 'Jane, welcome to Banconrista Rewards!',
    'body' => 'Thanks for joining our program. Show this message to '.
              'our barista for your first free coffee on us!',
    'kind' => 'walletobjects#walletObjectMessage'
));
// Reward points a user has.
$points = new Google_Service_Walletobjects_LoyaltyPoints();
$balance = new Google_Service_Walletobjects_LoyaltyPointsBalance();
$balance->setString('500');
$points->setBalance($balance);
$points->setLabel('Points');
$points->setPointsType('points');
// Create wallet object.
$wobObject = new Google_Service_Walletobjects_LoyaltyObject();
$wobObject->setClassId('2945482443380251551.ExampleClass1');
$wobObject->setId('2945482443380251551.ExampleObject1');
$wobObject->setState('active');
$wobObject->setBarcode($barcode);
$wobObject->setInfoModuleData($infoModuleData);
$wobObject->setLinksModuleData($linksModuleData);
$wobObject->setTextModulesData($textModulesData);
$wobObject->setAccountName('Jane Doe');
$wobObject->setAccountId('1234567890');
$wobObject->setLoyaltyPoints($points);
$wobObject->setMessages($messages);

Python

loyalty_object = {
  'classId' : '2945482443380251551.ExampleClass1',
  'id' : '2945482443380251551.ExampleObject1',
  'accountId': '1234567890',
  'accountName': 'Jane Doe',
  'barcode': {
      'alternateText' : '12345',
      'type' : 'qrCode',
      'value' : '28343E3'
  },
  'textModulesData': [{
    'header': 'Jane\'s Baconrista Rewards',
    'body': 'Save more at your local Mountain View store Jane. ' +
            ' You get 1 bacon fat latte for every 5 coffees purchased.  ' +
            'Also just for you, 10% off all pastries in the Mountain View store.'
  }],
  'linksModuleData': {
    'uris': [
      {
        'kind': 'walletobjects#uri',
        'uri': 'http://www.baconrista.com/myaccount?id=1234567890',
        'description': 'My Baconrista Account'
      }]
  },
  'infoModuleData': {
    'labelValueRows': [{
        'columns': [{
          'label': 'Next Reward in',
          'value': '2 coffees'
        }, {
          'label': 'Member Since',
          'value': '01/15/2013'
        }]
      },{
        'columns': [{
          'label': 'Local Store',
          'value': 'Mountain View'
        }]
    }],
    'showLastUpdateTime': 'true'
  },
  'messages': [{
      'header': 'Jane, welcome to Banconrista Rewards',
      'body': 'Thanks for joining our program. Show this message to ' +
              'our barista for your first free coffee on us!',
      'kind': 'walletobjects#walletObjectMessage'
  }],
  'loyaltyPoints': {
      'balance': {
          'string': '500'
      },
      'label': 'Points',
      'pointsType': 'points'
  },
  'state': 'active'
}

Закодируйте объект LoyaltyObject в токен JWT, используя закрытый ключ сервисного аккаунта OAuth 2.0. Ниже представлены примеры кодирования JWT на различных языках программирования. На вкладке "Протокол" токен JWT представлен в незакодированном виде. Более подробную информацию о полях токена можно найти в разделе "JWT для Google Pay API for Passes".

Протокол

{
  "iss": "example_service_account@developer.gserviceaccount.com",
  "aud": "google",
  "typ": "savetoandroidpay",
  "iat": 1368029586,
  "payload": {
    "eventTicketClasses": [{
      ... //Event ticket Class JSON
    }],
    "eventTicketObjects": [{
      ... //Event ticket Object JSON
    }],
    "flightClasses": [{
      ... //Flight Class JSON
    }],
    "flightObjects": [{
      ... //Flight Object JSON
    }],
    "giftCardClasses": [{
      ... //Gift card Class JSON
    }],
    "giftCardObjects": [{
      ... //Gift card Object JSON
    }],
    "loyaltyClasses": [{
      ... //Loyalty Class JSON
    }],
    "loyaltyObjects": [{
      ... //Loyalty Object JSON
    }],
    "offerClasses": [{
      ... //Offer Class JSON
    }],
    "offerObjects": [{
      ... //Offer Object JSON
    }],
    "transitClasses": [{
      ... //Transit Class JSON
    }],
    "transitObjects": [{
      ... //Transit Object JSON
    }]
  },
  "origins": ["http://baconrista.com", "https://baconrista.com"]
}

Java

WobCredentials credentials = null;
WobUtils utils = null;

// Instantiate the WobUtils class which contains handy functions
// Wob utils can be found in the quickstart sample
try {
  credentials = new WobCredentials(
    ServiceAccountEmailAddress,
    ServiceAccountPrivateKeyPath,
    ApplicationName,
    IssuerId);
  utils = new WobUtils(credentials);
} catch (GeneralSecurityException e) {
  e.printStackTrace();
} catch (IOException e) {
  e.printStackTrace();
}

// Add valid domains for the Save to Wallet button
List<String> origins = new ArrayList<String>();
origins.add("http://baconrista.com");
origins.add("https://baconrista.com");
origins.add(req.getScheme() + "://" + req.getServerName() + ":" + req.getLocalPort());

//Generate Objects and Classes here
//........

WobPayload payload = new WobPayload();
payload.addObject({WalletObject/WalletClass});

// Convert the object into a Save to Android Pay Jwt
String jwt = null;
try {
  jwt = utils.generateSaveJwt(payload, origins);
} catch (SignatureException e) {
  e.printStackTrace();
}

PHP

$requestBody = [
  "iss"=> SERVICE_ACCOUNT_EMAIL_ADDRESS,
  "aud" => "google",
  "typ" => "savetoandroidpay",
  "iat"=> time(),
  "payload" => {
    "eventTicketClasses" => [ ], # Event ticket classes
    "eventTicketObjects" => [ ], # Event ticket objects
    "flightClasses" => [ ],      # Flight classes
    "flightObjects" => [ ],      # Flight objects
    "giftCardClasses" => [ ],    # Gift card classes
    "giftCardObjects" => [ ],    # Gift card objects
    "loyaltyClasses" => [ ],     # Loyalty classes
    "loyaltyObjects" => [ ],     # Loyalty objects
    "offerClasses" => [ ],       # Offer classes
    "offerObjects" => [ ],       # Offer objects
    "transitClasses" => [ ],     # Transit classes
    "transitObjects" => [ ]      # Transit objects
  },
  "origins" => ["http://baconrista.com", "https://baconrista.com"]
]
// Generate the Save to Android Pay Jwt
echo $jwt = $assertObj->makeSignedJwt($requestBody, $client);

Python

jwt = {
  'iss': config.SERVICE_ACCOUNT_EMAIL_ADDRESS,
  'aud': 'google',
  'typ': 'savetoandroidpay',
  'iat':  int(time.time()),
  'payload': {
    'webserviceResponse': {
      'result': 'approved',
      'message': 'Success.'
    },
    'eventTicketClasses': [], # Event ticket classes
    'eventTicketObjects': [], # Event ticket objects
    'flightClasses': [],      # Flight classes
    'flightObjects': [],      # Flight objects
    'giftCardClasses': [],    # Gift card classes
    'giftCardObjects': [],    # Gift card objects
    'loyaltyClasses': [],     # Loyalty classes
    'loyaltyObjects': [],     # Loyalty objects
    'offerClasses': [],       # Offer classes
    'offerObjects': [],       # Offer objects
    'transitClasses': [],     # Transit classes
    'transitObjects': []      # Transit objects
  },
  'origins' : ['http://baconrista.com', 'https://baconrista.com']
}

// Generate the Save to Android Pay Jwt
signer = crypt.Signer.from_string(app_key)
signed_jwt = crypt.make_signed_jwt(signer, jwt)
response = webapp2.Response(signed_jwt)

Безопасная длина токена JSON – 1800 символов. Важно не превышать этот лимит. Иначе могут возникать ошибки при сохранении из-за усечения данных в браузерах. Объекты в токенах JWT должны содержать только важные для пользователя данные. Постарайтесь сохранить большую часть данных в классе, создав его раньше токена. Используйте REST API, если нужно сформировать крупный объект, и отправьте в JWT только его идентификатор.

Введите созданный JWT и идентификатор класса:

https://pay.google.com/gp/v/save/{jwt_generated}

Поставьте косую черту перед параметрами в URL.

Безопасная длина URL-ссылки на контент – 1800 символов. Важно не превышать этот лимит. Иначе могут возникать ошибки при сохранении из-за усечения данных в браузерах. Объекты в токенах JWT должны содержать только важные для пользователя данные. Постарайтесь сохранить большую часть данных в классе, создав его раньше токена. Используйте REST API, если нужно сформировать крупный объект, и отправьте в JWT только его идентификатор.

Чтобы загрузить и правильно разместить изображение для кнопки "Сохранить в Google Pay" и ссылки, ознакомьтесь с разделом Правила использования бренда. Дополнительная информация о ссылках на контент и кнопке "Сохранить в Google Pay" представлена в этом видео (на английском языке).

Gmail поддерживает размещение в строке темы электронного письма кнопок типа Go-To Actions. Например, вы хотите добавить к электронному письму кнопку "Сохранить в Google Pay". Разместите ее как кнопку Go-To Actions, и она появится в строке темы, а пользователи смогут сохранять специальные предложения прямо из папки "Входящие". Для этого добавьте в письмо кнопку View Action со ссылкой на контент.

Добавление кнопки в оригинальное приложение для Android

Чтобы узнать, как добавить кнопку Сохранить в Google Pay в оригинальное приложение для Android, ознакомьтесь со следующими разделами:

Чтобы настроить сохранение карт в Google Pay из приложения, воспользуйтесь приведенными ниже инструкциями.

  1. Выполните шаги, описанные в разделе Добавьте кнопку "Сохранить в Google Pay" в электронное письмо или SMS.
  2. Используйте намерение ACTION_VIEW, чтобы открыть ссылку на контент кнопки Сохранить в Google Pay.

    Убедитесь, что кнопка, которая активирует намерение, соответствует Правилам использования бренда.

Процесс выглядит следующим образом:

  1. До того, как, например, посадочный талон будет сохранен, с помощью REST API на сервере создается класс.
  2. Когда пользователь добавляет талон, сервер отправляет в приложение Android токен JWT, который представляет объект.
  3. Там же показывается кнопка Сохранить в Google Pay. Ее дизайн должен соответствовать нашим Правилам использования бренда. Если нажать кнопку, откроется намерение ACTION_VIEW, идентификатор URI которого содержит JWT. Пример:
    https://pay.google.com/gp/v/save/{jwt_generated}
    

Как использовать метод запроса POST с JWT

С помощью метода запроса POST с веб-токеном JSON (JWT) можно создавать разные категории карт для приложений Android. Такой подход удобен, если реализовать создание и добавление классов до сохранения объекта сложно. Воспользуйтесь этим методом, чтобы из вашего приложения можно было сохранять билеты на мероприятия, посадочные талоны и другие данные, для которых создается большое количество классов. Процесс выглядит следующим образом:

  1. Когда пользователь добавляет, например, посадочный талон, сервер передает в приложение Android токен JWT, который представляет как класс, так и объект.
  2. В приложении показывается кнопка Сохранить в Google Pay. Ее дизайн должен соответствовать нашим Правилам использования бренда. Если нажать кнопку, произойдет следующее:
    1. С помощью запроса POST по HTTPS токен JWT будет направлен в конечную точку.
    2. URI из тела ответа HTTP позволяет открыть намерение ACTION_VIEW.

Для метода запроса POST с JWT требуется ключ API. Это указано в параметре запроса REST API.

Создание класса

Новый класс создается на наших серверах, только когда появляется значение class.id, которое ранее не сохранялось. Таким образом, повторно отправить сведения о классе в Google через JWT теоретически возможно, однако система распознает, что он уже существует. Это значит, что новый класс не создается каждый раз, когда в приложение добавляется посадочный талон.

Обновление класса

Когда будет добавлен первый посадочный талон, объект сохранится вместе с классом. Значение class.id можно использовать с REST API для выполнения операций ADDMESSAGE, GET, LIST, PATCH и UPDATE.

Чтобы изменить информацию о классе, используйте API для его обновления. Если вы создадите класс со значением class.id=XYZ и дополнительными сведениями, а потом попробуете создать ещё один класс со значением class.id=XYZ, но с другими сведениями, то изменения сохранены не будут.

Формат JWT

Подробное описание формата JWT представлено в нашем справочном руководстве JWT Google Pay API for Passess. Через значение payload вы передаете два вхождения: первое – в виде объекта, который хотите создать, второе – с добавленным вами классом.

Запрос HTTP

Чтобы вставлять классы и объекты, указанные в JWT, можно использовать запрос INSERT.

Запрос JWT: INSERT

Если есть JWT, с помощью запроса INSERT можно вставить указанные в JWT классы и объекты. При успешном выполнении появится ответ HTTP с кодом 200.

HTTP-запрос
POST https://walletobjects.googleapis.com/walletobjects/v1/jwt/

Авторизация

Авторизация для этого запроса не требуется. Однако JWT нужно подписать с помощью RSA-SHA256. Ключ подписи создается сервисным аккаунтом OAuth.

Тело запроса

Предоставить данные нужно в виде определенной структуры:

{ “jwt” : string }

Тело ответа

Если запрос выполнен успешно, метод вернет ответ со следующей структурой:

{
    "saveUri": string,
    "resources": {
      "eventTicketClasses": [ eventTicketClass resource, ... ],
      "eventTicketObjects": [ eventTicketObject resource, ... ],
      "flightClasses": [ flightClass resource, ... ],
      "flightObjects": [ flightObject resource, ... ],
      "giftCardClasses": [ giftCardClass resource, ... ],
      "giftCardObjects": [ giftCardObject resource, ... ],
      "loyaltyClasses": [ loyaltyClass resource, ... ],
      "loyaltyObjects": [ loyaltyObject resource, ... ],
      "offerClasses": [ offerClass resource, ... ],
      "offerObjects": [ offerObject resource, ... ],
      "transitClasses": [ transitClass resource, ... ],
      "transitObjects": [ transitObject resource, ... ]
    }
}

Строка saveUri представляет собой последовательность URI, которую пользователь может открыть и применить, чтобы сохранять объекты, связанные в JWT с его аккаунтом Google. Идентификатор URI действует в течение недели со дня, когда он был возвращен.

О том, что именно можно отправлять конечной точке JWT, написано здесь.

Диаграммы процесса работы API

Посмотреть типичные диаграммы процесса работы API можно на этой странице.

Как использовать оригинальный Android SDK

Используя API Android, вы можете сохранять карты в Google Pay. Добавив в приложение кнопку Сохранить в Google Pay, вы позволите покупателям сохранять в Google Pay сведения об акциях и предложениях.

Чтобы добавить кнопку Сохранить в Google Pay для карты постоянного покупателя, нужно выполнить следующие действия.

1. Добавьте кнопку "Сохранить в Google Pay" в интерфейс

Сначала нужно добавить в приложение кнопку "Сохранить в Google Pay". Для этого воспользуйтесь Android SDK в Google Pay. Необходимые ресурсы можно найти в Правилах использования бренда.

В данном разделе содержатся соответствующие векторные изображения.

Чтобы добавить кнопку в приложение, скопируйте изображение кнопки из базы объектов в папку res вашего приложения и добавьте приведенный ниже код в файл макета Android. Обратите внимание, что для каждой кнопки нужна уникальная строка contentDescription и значение minWidth, а также верное значение src.

<ImageButton
             android:layout_width="match_parent"
             android:layout_height="48dp"
             android:minWidth="200dp"
             android:clickable="true"
             android:src="@drawable/s2ap" />

Значение layout_height для кнопки должно быть 48 dp, а значение minWidth – 200 dp.

2. Создайте класс LoyaltyClass

Класс можно создать в сервисе Google Pay API for Passes Merchant Center. Для создания класса loyaltyclass на странице "Классы" в Merchant Center выберите Создать класс. Обязательными для заполнения являются только поля, обведенные красным. Если в поле нужно ввести URL-адрес, убедитесь, что соответствующая страница находится в открытом доступе. На класс будет ссылаться объект со значениями, когда вы его создадите.

3. Создайте объект LoyaltyObject

Далее необходимо создать объект LoyaltyObject. Ниже приведен пример создания объекта с использованием шаблона builder.

// Define Points
LoyaltyPoints points = LoyaltyPoints.newBuilder()
    .setLabel("Points")
    .setType("points")
    .setBalance(LoyaltyPointsBalance.newBuilder().setString("500").build()).build();

// Define Text Module Data
List textModulesData = new ArrayList();
TextModuleData textModuleData = new TextModuleData("Jane's Baconrista Rewards", "Save more at your local Mountain View store Jane.  You get 1 bacon fat latte for every 5 coffees purchased.  Also just for you, 10% off all pastries in the Mountain View store.");
textModulesData.add(textModuleData);

// Define Links Module Data
List uris = new ArrayList();
UriData uri1 = new UriData("http://www.baconrista.com/myaccount?id=1234567890","My Baconrista Account");
uris.add(uri1);

List imageUris = new ArrayList();
UriData uri2 = new UriData("http://examplesite/images/exampleimage2.jpg", "Image Description");
imageUris.add(uri2);

// Define Info Module
List row0cols = new ArrayList();
LabelValue row0col0 = new LabelValue("Next Reward in","2 coffees");
LabelValue row0col1 = new LabelValue("Member Since", "01/15/2013");
row0cols.add(row0col0);
row0cols.add(row0col1);

List row1cols = new ArrayList();
LabelValue row1col0 = new LabelValue("Local Store", "Mountain View");
row1cols.add(row1col0);

List rows = new ArrayList();
LabelValueRow row0 = LabelValueRow.newBuilder().addColumns(row0cols).build();
LabelValueRow row1 = LabelValueRow.newBuilder().addColumns(row1cols).build();

rows.add(row0);
rows.add(row1);

// Define general messages
List messages = new ArrayList();
WalletObjectMessage message =  WalletObjectMessage.newBuilder()
    .setHeader("Hi Jane!")
    .setBody("Thanks for joining our program. Show this message to " +
        "our barista for your first free coffee on us!")
    .build();
messages.add(message);

// Define Geolocations

LatLng location = new LatLng(37.422601, -122.085286);

List locations = new ArrayList();
locations.add(location);

LoyaltyWalletObject wob = LoyaltyWalletObject
    .newBuilder()
    .setClassId("2967745143867465930.LoyaltyClass")
    .setId("2967745143867465930.LoyaltyObject")
    .setState(WalletObjectsConstants.State.ACTIVE)
    .setAccountId("1234567890")
    .setAccountName("Jane Doe")
    .setIssuerName("Baconrista")
    .setProgramName("Baconrista Rewards")
    .setBarcodeType("qrCode")
    .setBarcodeValue("28343E3")
    .setBarcodeAlternateText("12345")
    .setLoyaltyPoints(points)
    .addTextModulesData(textModulesData)
    .addLinksModuleDataUris(uris)
    .addInfoModuleDataLabelValueRows(rows)
    .addImageModuleDataMainImageUris(imageUris)
    .addMessages(messages)
    .addLocations(locations)
    .build();

Этот объект станет первым параметром для вызова createWalletObject, описанного в следующем разделе.

4. Инициализируйте запрос для сохранения LoyaltyObject

Класс walletObjectsClient служит точкой входа для функций объектов.

В приведенном ниже фрагменте кода показано, как приложение может создать экземпляр клиента для сохранения объектов в Google Pay.

CreateWalletObjectsRequest request = new CreateWalletObjectsRequest(wob);
Wallet.WalletOptions walletOptions = new Wallet.WalletOptions.Builder()
        .setTheme(WalletConstants.THEME_LIGHT)
        .setEnvironment(WalletConstants.ENVIRONMENT_PRODUCTION)
        .build();

walletObjectsClient = Wallet.getWalletObjectsClient(this, walletOptions);
Task task = walletObjectsClient.createWalletObjects(request);
AutoResolveHelper.resolveTask(task, this, SAVE_TO_ANDROID);

Для того чтобы инициализировать запрос, можно также использовать GoogleApiClient:

Wallet.WalletObjects.createWalletObjects(googleApiClient, request, SAVE_TO_ANDROID);

5. Воспользуйтесь обработчиком событий onActivityResult

Определите обработчик onActivityResult, чтобы реагировать на успешное выполнение, отмену или ошибку операции, как показано ниже.

public void onActivityResult(int requestCode, int resultCode, Intent data){
  EditText textBox = (EditText) findViewById(R.id.s2wResponse);

  switch(requestCode){
    case SAVE_TO_ANDROID:
      switch (resultCode) {
        case Activity.RESULT_OK:
          textBox.setText("saved");
          break;
        case Activity.RESULT_CANCELED:
          textBox.setText("canceled");
          break;
        default:
          int errorCode =
              data.getIntExtra(
                  WalletConstants.EXTRA_ERROR_CODE, -1);
          textBox.setText("failed error code: " + errorCode);
          break;
      }