Google Wallet for Digital Goods

Web Tutorial

This tutorial leads you through using the Google Wallet for Digital Goods API in your web app or Chrome App.

Back to top

1: Get set up as a seller

Sign up for Google Google Wallet for Digital Goods, if you haven't already. Then get your Seller Identifier and Seller Secret.

The following instructions describe how to sign up for a Google merchant account. If you already have a Google account, use that to sign in. If you already have a Google merchant account, use that to sign in and skip most of the sign-up.

Note: These instructions are intended for sandbox signups, so they encourage you to bypass a few steps that would be required in production.

  1. Start with this link: Sign up for Google Wallet for Digital Goods (sandbox)
  2. Fill out the form to create a new Google Account. Use your actual email address (it doesn't have to be Gmail).
  3. Submit the form by clicking the "Complete signup" button. You're done signing up!
  4. Go to the sandbox settings page, and get your Seller Identifier and Seller Secret.

2 (Server): Generate a JSON Web Token (JWT)

The Google Wallet for Digital Goods API uses JSON Web Tokens—or JWTs, pronounced like the English word jot—to represent each item for purchase in JSON format. To securely verify the origin of these JWTs, you'll encode and sign them with a secret key before passing them to the client.

Because you sign the JWT using a secret key (the Seller Secret), you must generate the JWT using server-side code. It's simplest if you use a library. Here are some examples of generating the JWT for an expensive virtual piece of cake. Note that these libraries have dependencies on Google Core Libraries such as Gson, Joda, and Guava.

Ruby
With the ruby-jwt library (by progium):
@cakeToken = JWT.encode(
  {
    "iss" => sellerIdentifier,
    "aud" => "Google",
    "typ" => "google/payments/inapp/item/v1",
    "exp" => (Time.now + 3600).to_i,
    "iat" => Time.now.to_i,
    "request" => {
      "name" => "Piece of Cake",
      "description" => "Virtual chocolate cake to fill your virtual tummy",
      "price" => "10.50",
      "currencyCode" => "USD",
      "sellerData" => "user_id:1224245,offer_code:3098576987,affiliate:aksdfbovu9j"
    }
  },
  SELLER_SECRET )
Python
With the pyjwt library (by progium):
cakeToken = jwt.encode(
  {
    "iss" : sellerIdentifier,
    "aud" : "Google",
    "typ" : "google/payments/inapp/item/v1",
    "exp" : int(time.time() + 3600),
    "iat" : int(time.time()),
    "request" :{
      "name" : "Piece of Cake",
      "description" : "Virtual chocolate cake to fill your virtual tummy",
      "price" : "10.50",
      "currencyCode" : "USD",
      "sellerData" : "user_id:1224245,offer_code:3098576987,affiliate:aksdfbovu9j"
    }
  },
  SELLER_SECRET)
Java
With the jsontoken library:
private String getJWT() throws InvalidKeyException, SignatureException {
  JsonToken token = null;
  token = createToken();
  return token.serializeAndSign();
}

private JsonToken createToken() throws InvalidKeyException{
  //Current time and signing algorithm
  Calendar cal = Calendar.getInstance();
  HmacSHA256Signer signer = new HmacSHA256Signer(ISSUER, null, SIGNING_KEY.getBytes());

  //Configure JSON token
  JsonToken token = new JsonToken(signer);
  token.setAudience("Google");
  token.setParam("typ", "google/payments/inapp/item/v1");
  token.setIssuedAt(new Instant(cal.getTimeInMillis()));
  token.setExpiration(new Instant(cal.getTimeInMillis() + 60000L));

  //Configure request object
  JsonObject request = new JsonObject();
  request.addProperty("name", "Piece of Cake");
  request.addProperty("description", "Virtual chocolate cake to fill your virtual tummy");
  request.addProperty("price", "10.50");
  request.addProperty("currencyCode", "USD");
  request.addProperty("sellerData", "user_id:1224245,offer_code:3098576987,affiliate:aksdfbovu9j");

  JsonObject payload = token.getPayloadAsJsonObject();
  payload.add("request", request);

  return token;
}
PHP
With the jwt library (by luciferous):
$payload = array(
  "iss" => $sellerIdentifier,
  "aud" => "Google",
  "typ" => "google/payments/inapp/item/v1",
  "exp" => time() + 3600,
  "iat" => time(),
  "request" => array (
    "name" => "Piece of Cake",
    "description" => "Virtual chocolate cake to fill your virtual tummy"
    "price" => "10.50",
    "currencyCode" => "USD",
    "sellerData" => "user_id:1224245,offer_code:3098576987,affiliate:aksdfbovu9j",
  )
);
$cakeToken = JWT::encode($payload, $sellerSecret);

Once you have generated JWTs, you can pass them to the client using AJAX/JSON, in-page rendering, or whatever method you prefer.

You can test the JWTs you generate by comparing them to the JWTs produced by the demo. For details on the fields and values in the JWT that you generate, see the JWT body reference documentation.

Note: Google automatically converts the billing currency to the currency of the merchant account.

Back to top

3 (Client): Load the API library

Every page that relies on the Google Wallet for Digital Goods API must load the API library. Web apps can load the library directly, but Chrome Apps use a special wrapper script — for details, see Monetize Your App > Google Wallet for Digital Goods. The example below loads the sandbox API library for a web app.

<script src="https://sandbox.google.com/checkout/inapp/lib/buy.js"></script>

Note: The old style of loading the API library using google.load() still works, but has been deprecated.

See the "Switch to the production server" section on how to load the production API library.

Back to top

4 (Client): Create callback handlers

If your app should react to the purchase flow's completion, define two callback functions in your client-side code:

A success handler
This function is called when an order is successfully confirmed.
A failure handler
This function is called when the transaction does not complete successfully, for any reason. Typical causes are the credit card authorization failing or the user deciding not to complete the order.

Note: These callback handlers are not secure. Someone could use Firebug or the Chrome Developer Tools to call one of the functions, mocking a success or failure. You should confirm the purchase on the server.

The following code shows how to declare your callback handlers and assign them to variables. If your client UI is implemented in Flash, click the Flash tab to get instructions on associating your callback handlers with ActionScript handlers.

JavaScript
Assign these functions to variables, as the following sample code shows.
//Success handler
var successHandler = function(purchaseAction){
  if (window.console != undefined) {
    console.log("Purchase completed successfully.");
    ...
  }
}

//Failure handler
var failureHandler = function(purchaseActionError){
  if (window.console != undefined) {
    console.log("Purchase did not complete.");
    ...
  }
}
Flash
Each callback function should call a ActionScript handler function in your SWF that was exposed with ExternalInterface. Here's an example of defining JavaScript callback functions that call ActionScript handler functions:
//JavaScript success handler
var successHandler = function(purchaseAction) {
  var flashContainer = document.getElementById("flash-container");
  if(flashContainer) {
    flashContainer.successHandlerInFlash();
  }
}

//JavaScript failure handler
var failureHandler = function(purchaseAction) {
  var flashContainer = document.getElementById("flash-container");
  if(flashContainer) {
    flashContainer.failureHandlerInFlash();
  }
}

Here's some ActionScript code that shows how you expose the ActionScript handler functions with ExternalInterface:

//Expose ActionScript success handler
if(ExternalInterface.available) {
  ExternalInterface.addCallback("successHandlerInFlash", function():void {
    ExternalInterface.call("console.log", "successHandlerInFlash called");
  });
}

//Expose ActionScript failure handler
if(ExternalInterface.available) {
  ExternalInterface.addCallback("failureHandlerInFlash", function():void {
    ExternalInterface.call("console.log", "failureHandlerInFlash called");
  })
}

Back to top

5 (Client): Call buy()

When a customer clicks your app's Buy button, call buy(). Calling this function initiates the purchase flow and creates the purchase flow iframe and (if necessary) popup.

JavaScript
Here's an example of calling buy() from a button's onClick handler:
function purchase(){
  ...
  google.payments.inapp.buy({
    'jwt'     : generatedJwt,
    'success' : successHandler,
    'failure' : failureHandler
  });
}

<button class="buy-button"
  id="buybutton1" name="buy" type="button"
  onClick="purchase()">
  Buy
</button>
Flash
When your app is implemented in Flash, you need to define a JavaScript function that calls buy(), as shown here:
//JavaScript:
function purchase(){
  ...
  google.payments.inapp.buy({
    'jwt'     : generatedJwt,
    'success' : successHandler,
    'failure' : failureHandler
  });
}
 

You then need to use ExternalInterface to call that JavaScript function from ActionScript code. Here's an example:

//ActionScript:
buyButton.addEventListener(MouseEvent.CLICK, function(e:MouseEvent):void {
  if(ExternalInterface.available) {
    ExternalInterface.call("purchase");
  }
});

Important: For ExternalInterface to work as described, the Flash allowScriptAccess embed attribute must be set to an acceptable value—either "always" or "sameDomain". If you see issues with the iframe drawing under your SWF content, try modifying the value of the Flash wmode embed attribute.

Once the transaction is completed, the Google Wallet for Digital Goods system calls your client-side callback handlers and notifies the server of the transaction.

Back to top

6 (Server): Acknowledge purchase notification

If you want to make sure that the buyer has paid for the item, you should specify a postback URL. If you do, Google sends an HTTP POST message to the postback URL whenever a purchase completes. Your server needs to acknowledge these POST messages, or else the transactions will be canceled.

To specify a postback URL, go to the sandbox settings page.

Once you've configured a postback URL, Google sends an HTTP POST message when a transaction completes successfully. The body of the message contains just one parameter, named jwt, that includes a copy of the JSON from the call to buy(), plus an order ID.

Here's an example of the JSON from the HTTP POST message's JWT:

JSON
{
  "iss": "Google",
  "aud": "1337133713371337",
  "typ": "google/payments/inapp/item/v1/postback/buy",
  "iat": "1309988959",
  "exp": "1409988959",
  "request": {
    "name": "Piece of Cake",
    "description": "Virtual chocolate cake to fill your virtual tummy",
    "price": "10.50",
    "currencyCode": "USD",
    "sellerData": "user_id:1224245,offer_code:3098576987,affiliate:aksdfbovu9j"
  },
  "response": {
    "orderId": "3485709183457474939449"
  }
}

Tip: If you want to see for yourself what JWTs contain, try out the interactive JWT Decoder.

To verify that the purchase is valid, your server first needs to decode the JWT in the POST. If the purchase is valid, then your server should record it and respond with a 200 OK that contains the the order ID. For details, see Handling Postbacks.

Important: The transaction is automatically canceled if your server takes longer than 10 seconds to send a 200 OK response.

Back to top

7: Switch to the production server

Up until now, all your interaction has been with the sandbox server, which lets you test your integration with Google Wallet for Digital Goods but doesn't let you really sell items. In this step, you switch from the sandbox server to the production server, so you can make some money.

Follow these steps to switch to the production server:

  1. If you didn't already create one, sign up for a production account by visiting the following URL:
    Production account setup
  2. Visit the following page:
    Production settings page

    Use it to set your postback URL for the production server, and to get the production values of your Seller Identifier and Seller Secret.

  3. In your code, change all occurrences of the Seller Identifier and Seller Secret to the production values. These might include anywhere you reference the "iss" or "aud" fields in JWTs, as well as where you specify the secret for encoding or decoding a JWT.

  4. In your client code, load the production API library instead of the sandbox API library:
    <script src="https://wallet.google.com/inapp/lib/buy.js"></script>
    

Once you've finished those changes, test thoroughly to ensure that everything is functioning correctly.

Note: You must use real credit cards to test the production server. The test cards that work in the sandbox won't work in production.

Congratulations, you've completed integration!

Your web app is now set to handle purchases through the Google Wallet for Digital Goods API.

For more information on next steps for further development, see Handling Postbacks and the other how-to guides.

Back to top

Authentication required

You need to be signed in with Google+ to do that.

Signing you in...

Google Developers needs your permission to do that.