Get Started with Gift Cards on the Web

The Save to Android Pay API faciliates saving and managing gift cards in Android Pay. By integrating the Save to Android Pay button on your website or in your app, you make it easy for your customers to save their gift cards to Android Pay. Once saved, these gift cards can be configured for redemption and continually updated with relevant, engaging content.

This "Get Started" guide provides the basic steps required to integrate the Save to Android Pay button on your website. For more details on other key use-cases refer to the Concepts guide.

Overview

Saving a gift card to Android Pay requires the user to explicitly click the Save to Android Pay button that you integrate. When the user clicks the button, a JSON Web Token (JWT) that represents their gift card is sent to our servers. Our servers then create a GiftCardObject resource based on this JWT and connect it to the user's account.

There are three steps to integrating the Save to Android Pay button on your website:

  1. Define a GiftCardClass that your GiftCardObjects will extend.
  2. Generate a JWT that represents the GiftCardObject.
  3. Include the Save to Android Pay button on your web page.

Note: Before continuing, make sure you have set up your project and have access to the Save to Android Pay API. If not, follow the instructions in the Basic Setup guide.

Integrating the Save to Android Pay Button

Define the GiftCardClass

The first step to integrating is to define the GiftCardClass.

Once you have defined the GiftCardClass, insert it by making a POST request to the following REST URI:

https://www.googleapis.com/walletobjects/v1/giftCardClass

Note: Add the strict=true parameter to the REST URI to enable strict error parsing and catch additional errors, such as duplicate ID fields: https://www.googleapis.com/walletobjects/v1/giftCardClass?strict=true

The following is an example of a GiftCardClass resource. Each code sample demonstrates defining the GiftCardClass resource and inserting it.

Resource

{
  "kind" : "walletobjects#giftCardClass",
  "id" : "1234567890.ExampleGCClass",
  "issuerName" : "Baconrista",
  "merchantName" : "Baconrista",
  "programLogo" : {
    "kind" : "walletobjects#image",
    "sourceUri" : {
      "kind" : "walletobjects#uri",
      "uri" : "http://farm8.staticflickr.com/7340/11177041185_a61a7f2139_o.jpg"
    }
  },
  "textModulesData" : [
    {
      "header" : "Where to Redeem",
      "body" : "All US gift cards are redeemable in any US and Puerto Rico" +
                " Baconrista retail locations, or online at Baconrista.com where" +
                " available, for merchandise or services."
    }
  ],
  "linksModuleData" : {
    "uris" : [
      {
        "kind" : "walletobjects#uri",
        "uri" : "http://www.baconrista.com/",
        "description" : "Baconrista"
      }
    ]
  },
  "locations" : [{
    "kind" : "walletobjects#latLongPoint",
    "latitude" : 37.422601,
    "longitude" : -122.085286
  }],
  "allowMultipleUsersPerObject" : true,
  "reviewStatus" : "underReview",
  "hexBackgroundColor": "#ffffff",
  "heroImage": {
    "kind": "walletobjects#image",
    "sourceUri": {
      "kind": "walletObjects#uri",
      "uri": "http://farm8.staticflickr.com/7302/11177240353_115daa5729_o.jpg"
    }
  }
}

Java

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

TextModuleData textModuleData = new TextModuleData().setHeader("Where to Redeem")
    .setBody("All US gift cards are redeemable in any US and Puerto Rico " +
           "Baconrista retail locations, or online at Baconrista.com where" +
           "available, for merchandise or services.");
textModulesData.add(textModuleData);

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

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

// Create class
GiftCardClass wobClass = new GiftCardClass()
    .setId("1234567890.ExampleGCClass")
    .setIssuerName("Baconrista")
    .setMerchantName("Baconrista")
    .setProgramLogo(
        new Image().setSourceUri(new Uri()
            .setUri("http://farm8.staticflickr.com/7340/11177041185_a61a7f2139_o.jpg")))
    .setTextModulesData(textModulesData)
    .setLinksModuleData(linksModuleData)
    .setReviewStatus("underReview").setAllowMultipleUsersPerObject(true)
    .setLocations(locations);

response = client.giftcardclass().insert(wobClass).execute();

PHP

// Define text module data.
$textModulesData = array(
    array(
        'header' => 'Where to Redeem',
        'body' => 'All US gift cards are redeemable in any US and Puerto Rico ' .
            'Baconrista retail locations, or online at Baconrista.com where ' .
            'available, for merchandise or services.'
    )
);
// Define links module data.
$linksModuleData = new Google_Service_Walletobjects_LinksModuleData();
$uris = array (
    array(
        'uri' => 'http://www.baconrista.com',
        'kind' => 'walletobjecs#uri',
        'description' => 'Baconrista'
    )
);
$linksModuleData->setUris($uris);

// A list of locations at which the Gift card Class can be used.
$locations = array(
    array(
        'kind' => 'walletobjects#latLongPoint',
        'latitude' => 37.422601,
        'longitude' => -122.085286
    )
);
// Source uri of program logo.
$uriInstance = new Google_Service_Walletobjects_Uri();
$imageInstance = new Google_Service_Walletobjects_Image();
$uriInstance->setUri(
    'http://farm8.staticflickr.com/7340/11177041185_a61a7f2139_o.jpg'
);
$imageInstance->setSourceUri($uriInstance);

// Create wallet class.
$giftCardClass = new Google_Service_Walletobjects_GiftCardClass();
$giftCardClass->setId('1234567890.ExampleGCClass');
$giftCardClass->setIssuerName('Baconrista');
$giftCardClass->setMerchantName('Baconrista');
$giftCardClass->setProgramLogo($imageInstance);
$giftCardClass->setLinksModuleData($linksModuleData);
$giftCardClass->setTextModulesData($textModulesData);
$giftCardClass->setReviewStatus('underReview');
$giftCardClass->setAllowMultipleUsersPerObject(true);
$giftCardClass->setLocations($locations);

$service->giftcardclass->insert($giftCardClass);

Python

giftcard_class = {
  'kind': 'walletobjects#giftCardClass',
  'id': '1234567890.ExampleGCClass',
  'issuerName': 'Baconrista',
  'merchantName': 'Baconrista',
  'issuerData': {
      'kind': 'walletobjects#typedValue'
  },
  'programLogo': {
      'kind': 'walletobjects#image',
      'sourceUri': {
          'kind': 'walletobjects#uri',
          'uri': 'http://farm8.staticflickr.com/7340/11177041185_a61a7f2139_o.jpg'
      }
  },
  'textModulesData': [{
    'header': 'Where to Redeem',
    'body': 'All US gift cards are redeemable in any US and Puerto Rico' +
            ' Baconrista retail locations, or online at Baconrista.com where'
            ' available, for merchandise or services.'
  }],
  'linksModuleData': {
    'uris': [
      {
        'kind': 'walletobjects#uri',
        'uri': 'http://www.baconrista.com',
        'description': 'Baconrista'
      }]
  },
  'locations': [{
      'kind': 'walletobjects#latLongPoint',
      'latitude': 37.422601,
      'longitude': -122.085286
  }],
  'allowMultipleUsersPerObject': True,
  'reviewStatus': 'underReview',
}
api_request = service.giftcardclass().insert(body=giftcard_class)
api_response = api_request.execute()

Note: For a complete list of all GiftCardClass fields see GiftCardClass reference.

Warning: You must set the reviewStatus field from draft to underReview when you believe the class is ready for review. The class will not be reviewed if you do not set the class to underReview. Unreviewed classes (classes set to draft) will not be visible to the public (only to trusted testers).

Generate the JWT for the GiftCardObject

On your server, define the GiftCardObject resource to be encoded in a JWT. Once the resource is defined, you do not need to make aPOST request.

Resource

{
  "kind" : "walletobjects#giftCardObject",
  "classId" : "1234567890.ExampleGCClass",
  "id" : "1234567890.ExampleGCObject",
  "cardNumber" : "123jkl4889",
  "pin" : "1111",
  "eventNumber" : "123456",
  "balance" : {
    "kind" : "walletobjects#money",
    "micros" : 20000000,
    "currencyCode" : "USD"
  },
  "balanceUpdateTime" : {
    "date" : '2014-01-12T23:20:50.52Z'
  },
  "barcode" : {
    "alternateText" : "12345",
    "type" : "qrCode",
    "value" : "28343E3"
  },
  "textModulesData" : [{
    "header" : "Earn double points",
    "body" : "Jane, don't forget to use your Baconrista Rewards when " +
              "paying with this gift card to earn additional points"
  }],
  "linksModuleData" : {
    "uris" : [
      {
        "kind" : "walletobjects#uri",
        "uri" : "http://www.baconrista.com/mybalance?id=1234567890",
        "description" : "My Baconrista Gift Card Purchases"
      }]
  },
  "state" : "active",
  "version" : 1
}

Java

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

Money balance = new Money();
balance.setCurrencyCode("USD");
balance.setMicros(20000000L);

DateTime balanceUpdateTime = new DateTime();
balanceUpdateTime.setDate(new com.google.api.client.util.DateTime(new Date()));

// Define Text Module Data
List<TextModuleData> textModulesData = new ArrayList<TextModuleData>();
TextModuleData textModuleData = new TextModuleData()
    .setHeader("Earn double points")
    .setBody("Jane, don't forget to use your Baconrista Rewards when " +
                "paying with this gift card to earn additional points");
textModulesData.add(textModuleData);

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

// Define Wallet Instance
GiftCardObject object = new GiftCardObject()
    .setClassId("1234567890.ExampleGCClass").setId("1234567890.ExampleGCObject")
    .setVersion(1L).setState("active").setBarcode(barcode)
    .setTextModulesData(textModulesData)
    .setLinksModuleData(linksModuleData)
    .setBalance(balance)
    .setBalanceUpdateTime(balanceUpdateTime)
    .setEventNumber("123456").setCardNumber("123jkl4889").setPin("1111");

PHP

// Define barcode type and value.
$barcode = new Google_Service_Walletobjects_Barcode();
$barcode->setAlternateText('12345');
$barcode->setType('qrCode');
$barcode->setValue('28343E3');
// Define text module data.
$textModulesData = array(
    array(
        'header' => 'Earn double points',
        'body' => 'Jane, don\'t forget to use your Baconrista Rewards when '.
                  'paying with this gift card to earn additional points'
    )
);
// Define links module data.
$linksModuleData = new Google_Service_Walletobjects_LinksModuleData();
$uris = array (
    array(
        'uri' => 'http://www.baconrista.com/mybalance?id=1234567890',
        'kind' => 'walletobjecs#uri',
        'description' => 'My Baconrista Gift Card Purchases'
    )
);
$linksModuleData->setUris($uris);

$balance = new Google_Service_Walletobjects_Money();
$balance->setKind('walletobjects#money');
$balance->setMicros(20000000);
$balance->setCurrencyCode('USD');

$balanceUpdateTime = new Google_Service_Walletobjects_DateTime();
date_default_timezone_set('UTC');
$balanceUpdateTime->setDate(date("Y-m-d\TH:i:s.u\Z"));

// Create wallet object.
$giftCardObject = new Google_Service_Walletobjects_GiftCardObject();
$giftCardObject->setClassId("1234567890.ExampleGCClass");
$giftCardObject->setId("1234567890.ExampleGCObject");
$giftCardObject->setVersion(1);
$giftCardObject->setState('active');
$giftCardObject->setBarcode($barcode);
$giftCardObject->setLinksModuleData($linksModuleData);
$giftCardObject->setTextModulesData($textModulesData);
$giftCardObject->setBalance($balance);
$giftCardObject->setBalanceUpdateTime($balanceUpdateTime);
$giftCardObject->setCardNumber('123jkl4889');
$giftCardObject->setEventNumber('123456');
$giftCardObject->setPin('1111');

Python

giftcard_object = {
    'kind' : 'walletobjects#giftCardObject',
    'classId' : '1234567890.ExampleGCClass',
    'id' : '1234567890.ExampleGCObject',
    'cardNumber' : '123jkl4889',
    'pin' : '1111',
    'eventNumber' : '123456',
    'balance' : {
      'kind' : 'walletobjects#money',
      'micros' : 20000000,
      'currencyCode' : 'USD'
    },
    'balanceUpdateTime' : {
      'date' : datetime.datetime.utcnow().isoformat("T") + "Z"
    },
    'barcode' : {
        'alternateText' : '12345',
        'type' : 'qrCode',
        'value' : '28343E3'
    },
    'textModulesData': [{
      'header': 'Earn double points',
      'body': 'Jane, don\'t forget to use your Baconrista Rewards when  ' +
              'paying with this gift card to earn additional points. '
    }],
    'linksModuleData': {
      'uris': [
        {
          'kind': 'walletobjects#uri',
          'uri': 'http://www.baconrista.com/mybalance?id=1234567890',
          'description': 'My Baconrista Gift Card Purchases'
        }]
    },
    'state': 'active',
    'version': 1
}

Using your OAuth 2.0 service account private key, encode the GiftCardObject in a JWT. The following is an unencoded JWT and sample code to generate the JWT in different languages. Refer to Save to Android Pay JWT for an explanation of all the fields in the unencoded JWT.

Protocol

  
{
  "iss": "example_service_account@developer.gserviceaccount.com",
  "aud": "google",
  "typ": "savetoandroidpay",
  "iat": 1368029586,
  "payload": {
    "loyaltyObjects": [{
      ... //Loyalty Object JSON
      }],
    "offerObjects": [{
      ... //Offer Object JSON
      }],
    "loyaltyClasses": [{
      ... //Loyalty Class JSON
      }],
    "offerClasses": [{
      ... //Offer Class 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();
}

Ruby

  
jwt = {
   "iss"=> SERVICE_ACCOUNT_EMAIL_ADDRESS,
   "aud" => "google",
   "typ" => "savetoandroidpay",
   "iat"=> Time.now.utc.to_i,
   "payload" => {
     "loyaltyObjects" => [], #Loyalty objects
     "offerObjects" => [], #Offer objects
     "loyaltyClasses" => [], #Loyalty classes
     "offerClasses" => [] #Offer classes
   },
   "origins"=> ['http://baconrista.com', 'https://baconrista.com']
}
private_key = Google::APIClient::PKCS12.load_key(SERVICE_ACCOUNT_PRIVATE_KEY, 'notasecret')
jwtEncoded = JWT.encode(jwt, private_key, "RS256")

PHP

  
$requestBody = [
  "iss"=> SERVICE_ACCOUNT_EMAIL_ADDRESS,
  "aud" => "google",
  "typ" => "savetoandroidpay",
  "iat"=> time(),
  "payload" => {
    "loyaltyObjects" => [ ],  #Loyalty objects
    "offerObjects" => [ ],  #Offer objects
    "loyaltyClasses" => [ ],  #Loyalty classes
    "offerClasses" => [ ]  #Offer classes
  },
  "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.'
    },
    'loyaltyClasses': [], # Loyalty classes
    'loyaltyObjects': [], # Loyalty objects
    'offerClasses': [], # Offer classes
    'offerObjects': []  # Offer 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)

The safe length of an encoded JWT is 1800 characters. Your JWTs should remain below this limit. Objects encoded in JWTs should be small, containing only data that is specific to the user. Try to keep most data in the object's class, creating it before making the JWT. For larger objects that do not fit the limit, consider creating the object in the S2AP API and sending only the object ID in the JWT.

Include the Save to Android Pay Button

Include the following script on the page where you want to display the Save to Android Pay button:

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

Next, insert the g:savetoandroidpay namespace tag that defines the placement and various attributes of the Save to Android Pay button. Be sure to include the JWT generated previously.

<g:savetoandroidpay jwt="{JWT generated above}" onsuccess="successHandler"
onfailure="failureHandler" size="small" theme="light" ></g:savetoandroidpay>
That's it! Now you should see the Save to Android Pay button rendered on your webpage.

Saving the gift card

When desktop visitors to your site click the Save to Android Pay button, a rollover frame will appear with a preview of their gift card. Here they can confirm the save, after which the card will appear in their Android Pay app. The user can switch which Google account to associate with their gift card by clicking on the profile picture on the top right corner of the rollover frame.

On mobile, pressing the Save to Android Pay button will take the user to the Android Pay app to complete the save, if Android Pay is installed. Otherwise, the button will take the user to a mobile web page to complete the save.

Note: If a user is not currently logged into their Google Account, they will be taken to another window to authenticate.

Viewing the saved gift card

Open Android Pay to view your saved gift cards. Remember to use the same Google Account in Android Pay that you used to save the gift card.

Learn More

To discover more about what gift cards can do, see Concepts.

References

For more detailed technical information, see the API Reference.

Send feedback about...

Save to Android Pay API