Web API スタートガイド

Web API の使用を開始する前に、前提条件を満たしていることを確認してください。Web API を使用するには、サービス アカウントとサービス アカウント キーが必要です。また、Google Wallet API の呼び出しをサービス アカウントに許可する必要もあります。

GitHub からサンプルコードをダウンロードし、以下の手順で参照されているコード スニペットを実行してください。

認証と認可

Google Wallet API へのリクエストは認証される必要があります。これは、そのリクエストがお客様のアプリから発行されたものであることを API に確認させるためです。認証を受けるには、サービス アカウント キーを使用してアクセス トークンを取得します。

まず、必要なライブラリをインポートし、サービス アカウント JSON 用の変数と、保存する発行者、クラス、一意のユーザー、およびオブジェクトの ID を定義します。

Java

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.google.api.client.googleapis.batch.BatchRequest;
import com.google.api.client.googleapis.batch.json.JsonBatchCallback;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.googleapis.json.GoogleJsonError;
import com.google.api.client.googleapis.json.GoogleJsonResponseException;
import com.google.api.client.http.*;
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.services.walletobjects.Walletobjects;
import com.google.api.services.walletobjects.model.*;
import com.google.auth.http.HttpCredentialsAdapter;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.auth.oauth2.ServiceAccountCredentials;
import java.io.*;
import java.security.interfaces.RSAPrivateKey;
import java.util.*;

/** Demo class for creating and managing Flights in Google Wallet. */
public class DemoFlight {
  /**
   * Path to service account key file from Google Cloud Console. Environment variable:
   * GOOGLE_APPLICATION_CREDENTIALS.
   */
  public static String keyFilePath;

  /** Service account credentials for Google Wallet APIs. */
  public static GoogleCredentials credentials;

  /** Google Wallet service client. */
  public static Walletobjects service;

  public DemoFlight() throws Exception {
    keyFilePath =
        System.getenv().getOrDefault("GOOGLE_APPLICATION_CREDENTIALS", "/path/to/key.json");

    Auth();
  }

PHP

use Firebase\JWT\JWT;
use Google\Auth\Credentials\ServiceAccountCredentials;
use Google\Client as Google_Client;

/** Demo class for creating and managing Flights in Google Wallet. */
class DemoFlight
{
  /**
   * Path to service account key file from Google Cloud Console. Environment
   * variable: GOOGLE_APPLICATION_CREDENTIALS.
   */
  public string $keyFilePath;

  /**
   * Service account credentials for Google Wallet APIs.
   */
  public ServiceAccountCredentials $credentials;

  /**
   * Google Wallet service client.
   */
  public Google_Service_Walletobjects $service;

  public function __construct()
  {
    $this->keyFilePath = getenv('GOOGLE_APPLICATION_CREDENTIALS') ?: '/path/to/key.json';

    $this->auth();
  }

Python

import json
import os
import uuid

from google.auth.transport.requests import AuthorizedSession
from google.oauth2.service_account import Credentials
from google.auth import jwt, crypt


class DemoFlight:
    """Demo class for creating and managing Flights in Google Wallet.

    Attributes:
        key_file_path: Path to service account key file from Google Cloud
            Console. Environment variable: GOOGLE_APPLICATION_CREDENTIALS.
        base_url: Base URL for Google Wallet API requests.
    """

    def __init__(self):
        self.key_file_path = os.environ.get('GOOGLE_APPLICATION_CREDENTIALS',
                                            '/path/to/key.json')
        self.base_url = 'https://walletobjects.googleapis.com/walletobjects/v1'
        self.batch_url = 'https://walletobjects.googleapis.com/batch'
        self.class_url = f'{self.base_url}/flightClass'
        self.object_url = f'{self.base_url}/flightObject'

        # Set up authenticated client
        self.auth()

C#

using System.IdentityModel.Tokens.Jwt;
using System.Net.Http.Headers;
using System.Text.RegularExpressions;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Services;
using Google.Apis.Walletobjects.v1;
using Google.Apis.Walletobjects.v1.Data;
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;


/// <summary>
/// Demo class for creating and managing Flights in Google Wallet.
/// </summary>
class DemoFlight
{
  /// <summary>
  /// Path to service account key file from Google Cloud Console. Environment
  /// variable: GOOGLE_APPLICATION_CREDENTIALS.
  /// </summary>
  public static string keyFilePath;

  /// <summary>
  /// Service account credentials for Google Wallet APIs
  /// </summary>
  public static ServiceAccountCredential credentials;

  /// <summary>
  /// Google Wallet service client
  /// </summary>
  public static WalletobjectsService service;

  public DemoFlight()
  {
    keyFilePath = Environment.GetEnvironmentVariable(
        "GOOGLE_APPLICATION_CREDENTIALS") ?? "/path/to/key.json";

    Auth();
  }

Node.js

const { GoogleAuth } = require('google-auth-library');
const jwt = require('jsonwebtoken');
const { v4: uuidv4 } = require('uuid');

/**
 * Demo class for creating and managing Flights in Google Wallet.
 */
class DemoFlight {
  constructor() {
    /**
     * Path to service account key file from Google Cloud Console. Environment
     * variable: GOOGLE_APPLICATION_CREDENTIALS.
     */
    this.keyFilePath = process.env.GOOGLE_APPLICATION_CREDENTIALS || '/path/to/key.json';

    this.baseUrl = 'https://walletobjects.googleapis.com/walletobjects/v1';
    this.batchUrl = 'https://walletobjects.googleapis.com/batch';
    this.classUrl = `${this.baseUrl}/flightClass`;
    this.objectUrl = `${this.baseUrl}/flightObject`;

    this.auth();
  }

次に、いずれかのフレームワーク ライブラリを使用して、{ api_name } を呼び出すために必要な認証情報を取得します。

Java

/**
 * Create authenticated HTTP client using a service account file.
 *
 * @throws Exception
 */
public void Auth() throws Exception {
  String scope = "https://www.googleapis.com/auth/wallet_object.issuer";

  credentials =
      GoogleCredentials.fromStream(new FileInputStream(keyFilePath))
          .createScoped(Arrays.asList(scope));
  credentials.refresh();

  HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();

  // Initialize Google Wallet API service
  service =
      new Walletobjects.Builder(
              httpTransport,
              GsonFactory.getDefaultInstance(),
              new HttpCredentialsAdapter(credentials))
          .setApplicationName("APPLICATION_NAME")
          .build();
}

PHP

/**
 * Create authenticated HTTP client using a service account file.
 */
public function auth()
{
  $scope = 'https://www.googleapis.com/auth/wallet_object.issuer';

  $this->credentials = new ServiceAccountCredentials(
    $scope,
    $this->keyFilePath
  );

  // Initialize Google Wallet API service
  $this->client = new Google_Client();
  $this->client->setApplicationName('APPLICATION_NAME');
  $this->client->setScopes($scope);
  $this->client->setAuthConfig($this->keyFilePath);

  $this->service = new Google_Service_Walletobjects($this->client);
}

Python

def auth(self):
    """Create authenticated HTTP client using a service account file."""
    self.credentials = Credentials.from_service_account_file(
        self.key_file_path,
        scopes=['https://www.googleapis.com/auth/wallet_object.issuer'])

    self.http_client = AuthorizedSession(self.credentials)

C#

/// <summary>
/// Create authenticated service client using a service account file.
/// </summary>
public void Auth()
{
  credentials = (ServiceAccountCredential)GoogleCredential
      .FromFile(keyFilePath)
      .CreateScoped(new List<string>
      {
        "https://www.googleapis.com/auth/wallet_object.issuer"
      })
      .UnderlyingCredential;

  service = new WalletobjectsService(
      new BaseClientService.Initializer()
      {
        HttpClientInitializer = credentials
      });
}

Node.js

/**
 * Create authenticated HTTP client using a service account file.
 */
auth() {
  this.credentials = require(this.keyFilePath);

  this.httpClient = new GoogleAuth({
    credentials: this.credentials,
    scopes: 'https://www.googleapis.com/auth/wallet_object.issuer'
  });
}

パス オブジェクトの作成

パス オブジェクトはパスクラスのインスタンスです。パス オブジェクトを作成するには、次の属性を指定する必要があります。

  • classId: パスクラスの id
  • id: 搭乗者に固有の搭乗券 ID
  • state: 作成中の新しいパスの場合は active

また、次の属性を含めることをおすすめします。

  • passengerName: 搭乗券に表示される乗客名。
  • boardingAndSeatingInfo: 搭乗と座席に関する乗客固有の情報(BoardingAndSeatingInfo)。
  • barcode: バーコード タイプと値(Barcode

これらの属性が搭乗券でどのように表されるかについて詳しくは、レイアウト テンプレートをご覧ください。

パス オブジェクトを作成するコードサンプル:

Java

/**
 * Create an object.
 *
 * @param issuerId The issuer ID being used for this request.
 * @param classSuffix Developer-defined unique ID for this pass class.
 * @param objectSuffix Developer-defined unique ID for this pass object.
 * @return The pass object ID: "{issuerId}.{objectSuffix}"
 * @throws IOException
 */
public String CreateObject(String issuerId, String classSuffix, String objectSuffix)
    throws IOException {
  // Check if the object exists
  try {
    service.flightobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute();

    System.out.println(String.format("Object %s.%s already exists!", issuerId, objectSuffix));
    return String.format("%s.%s", issuerId, objectSuffix);
  } catch (GoogleJsonResponseException ex) {
    if (ex.getStatusCode() != 404) {
      // Something else went wrong...
      ex.printStackTrace();
      return String.format("%s.%s", issuerId, objectSuffix);
    }
  }

  // See link below for more information on required properties
  // https://developers.google.com/wallet/tickets/boarding-passes/rest/v1/flightobject
  FlightObject newObject =
      new FlightObject()
          .setId(String.format("%s.%s", issuerId, objectSuffix))
          .setClassId(String.format("%s.%s", issuerId, classSuffix))
          .setState("ACTIVE")
          .setHeroImage(
              new Image()
                  .setSourceUri(
                      new ImageUri()
                          .setUri(
                              "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"))
                  .setContentDescription(
                      new LocalizedString()
                          .setDefaultValue(
                              new TranslatedString()
                                  .setLanguage("en-US")
                                  .setValue("Hero image description"))))
          .setTextModulesData(
              Arrays.asList(
                  new TextModuleData()
                      .setHeader("Text module header")
                      .setBody("Text module body")
                      .setId("TEXT_MODULE_ID")))
          .setLinksModuleData(
              new LinksModuleData()
                  .setUris(
                      Arrays.asList(
                          new Uri()
                              .setUri("http://maps.google.com/")
                              .setDescription("Link module URI description")
                              .setId("LINK_MODULE_URI_ID"),
                          new Uri()
                              .setUri("tel:6505555555")
                              .setDescription("Link module tel description")
                              .setId("LINK_MODULE_TEL_ID"))))
          .setImageModulesData(
              Arrays.asList(
                  new ImageModuleData()
                      .setMainImage(
                          new Image()
                              .setSourceUri(
                                  new ImageUri()
                                      .setUri(
                                          "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"))
                              .setContentDescription(
                                  new LocalizedString()
                                      .setDefaultValue(
                                          new TranslatedString()
                                              .setLanguage("en-US")
                                              .setValue("Image module description"))))
                      .setId("IMAGE_MODULE_ID")))
          .setBarcode(new Barcode().setType("QR_CODE").setValue("QR code value"))
          .setLocations(
              Arrays.asList(
                  new LatLongPoint()
                      .setLatitude(37.424015499999996)
                      .setLongitude(-122.09259560000001)))
          .setPassengerName("Passenger name")
          .setBoardingAndSeatingInfo(
              new BoardingAndSeatingInfo().setBoardingGroup("B").setSeatNumber("42"))
          .setReservationInfo(new ReservationInfo().setConfirmationCode("Confirmation code"));

  FlightObject response = service.flightobject().insert(newObject).execute();

  System.out.println("Object insert response");
  System.out.println(response.toPrettyString());

  return response.getId();
}

PHP

/**
 * Create an object.
 *
 * @param string $issuerId The issuer ID being used for this request.
 * @param string $classSuffix Developer-defined unique ID for this pass class.
 * @param string $objectSuffix Developer-defined unique ID for this pass object.
 *
 * @return string The pass object ID: "{$issuerId}.{$objectSuffix}"
 */
public function createObject(string $issuerId, string $classSuffix, string $objectSuffix)
{
  // Check if the object exists
  try {
    $this->service->flightobject->get("{$issuerId}.{$objectSuffix}");

    print("Object {$issuerId}.{$objectSuffix} already exists!");
    return "{$issuerId}.{$objectSuffix}";
  } catch (Google\Service\Exception $ex) {
    if (empty($ex->getErrors()) || $ex->getErrors()[0]['reason'] != 'resourceNotFound') {
      // Something else went wrong...
      print_r($ex);
      return "{$issuerId}.{$objectSuffix}";
    }
  }

  // See link below for more information on required properties
  // https://developers.google.com/wallet/tickets/boarding-passes/rest/v1/flightobject
  $newObject = new Google_Service_Walletobjects_FlightObject([
    'id' => "{$issuerId}.{$objectSuffix}",
    'classId' => "{$issuerId}.{$classSuffix}",
    'state' => 'ACTIVE',
    'heroImage' => new Google_Service_Walletobjects_Image([
      'sourceUri' => new Google_Service_Walletobjects_ImageUri([
        'uri' => 'https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg'
      ]),
      'contentDescription' => new Google_Service_Walletobjects_LocalizedString([
        'defaultValue' => new Google_Service_Walletobjects_TranslatedString([
          'language' => 'en-US',
          'value' => 'Hero image description'
        ])
      ])
    ]),
    'textModulesData' => [
      new Google_Service_Walletobjects_TextModuleData([
        'header' => 'Text module header',
        'body' => 'Text module body',
        'id' => 'TEXT_MODULE_ID'
      ])
    ],
    'linksModuleData' => new Google_Service_Walletobjects_LinksModuleData([
      'uris' => [
        new Google_Service_Walletobjects_Uri([
          'uri' => 'http://maps.google.com/',
          'description' => 'Link module URI description',
          'id' => 'LINK_MODULE_URI_ID'
        ]),
        new Google_Service_Walletobjects_Uri([
          'uri' => 'tel:6505555555',
          'description' => 'Link module tel description',
          'id' => 'LINK_MODULE_TEL_ID'
        ])
      ]
    ]),
    'imageModulesData' => [
      new Google_Service_Walletobjects_ImageModuleData([
        'mainImage' => new Google_Service_Walletobjects_Image([
          'sourceUri' => new Google_Service_Walletobjects_ImageUri([
            'uri' => 'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg'
          ]),
          'contentDescription' => new Google_Service_Walletobjects_LocalizedString([
            'defaultValue' => new Google_Service_Walletobjects_TranslatedString([
              'language' => 'en-US',
              'value' => 'Image module description'
            ])
          ])
        ]),
        'id' => 'IMAGE_MODULE_ID'
      ])
    ],
    'barcode' => new Google_Service_Walletobjects_Barcode([
      'type' => 'QR_CODE',
      'value' => 'QR code value'
    ]),
    'locations' => [
      new Google_Service_Walletobjects_LatLongPoint([
        'latitude' => 37.424015499999996,
        'longitude' =>  -122.09259560000001
      ])
    ],
    'passengerName' => 'Passenger name',
    'boardingAndSeatingInfo' => new Google_Service_Walletobjects_BoardingAndSeatingInfo([
      'boardingGroup' => 'B',
      'seatNumber' => '42'
    ]),
    'reservationInfo' => new Google_Service_Walletobjects_ReservationInfo([
      'confirmationCode' => 'Confirmation code'
    ])
  ]);

  $response = $this->service->flightobject->insert($newObject);

  print "Object insert response\n";
  print_r($response);

  return $response->id;
}

Python

def create_object(self, issuer_id: str, class_suffix: str,
                  object_suffix: str) -> str:
    """Create an object.

    Args:
        issuer_id (str): The issuer ID being used for this request.
        class_suffix (str): Developer-defined unique ID for the pass class.
        object_suffix (str): Developer-defined unique ID for the pass object.

    Returns:
        The pass object ID: f"{issuer_id}.{object_suffix}"
    """

    # Check if the object exists
    response = self.http_client.get(
        url=f'{self.object_url}/{issuer_id}.{object_suffix}')

    if response.status_code == 200:
        print(f'Object {issuer_id}.{object_suffix} already exists!')
        print(response.text)
        return f'{issuer_id}.{object_suffix}'
    elif response.status_code != 404:
        # Something else went wrong...
        print(response.text)
        return f'{issuer_id}.{object_suffix}'

    # See link below for more information on required properties
    # https://developers.google.com/wallet/tickets/boarding-passes/rest/v1/flightobject
    new_object = {
        'id': f'{issuer_id}.{object_suffix}',
        'classId': f'{issuer_id}.{class_suffix}',
        'state': 'ACTIVE',
        'heroImage': {
            'sourceUri': {
                'uri':
                    'https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg'
            },
            'contentDescription': {
                'defaultValue': {
                    'language': 'en-US',
                    'value': 'Hero image description'
                }
            }
        },
        'textModulesData': [{
            'header': 'Text module header',
            'body': 'Text module body',
            'id': 'TEXT_MODULE_ID'
        }],
        'linksModuleData': {
            'uris': [{
                'uri': 'http://maps.google.com/',
                'description': 'Link module URI description',
                'id': 'LINK_MODULE_URI_ID'
            }, {
                'uri': 'tel:6505555555',
                'description': 'Link module tel description',
                'id': 'LINK_MODULE_TEL_ID'
            }]
        },
        'imageModulesData': [{
            'mainImage': {
                'sourceUri': {
                    'uri':
                        'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg'
                },
                'contentDescription': {
                    'defaultValue': {
                        'language': 'en-US',
                        'value': 'Image module description'
                    }
                }
            },
            'id': 'IMAGE_MODULE_ID'
        }],
        'barcode': {
            'type': 'QR_CODE',
            'value': 'QR code'
        },
        'locations': [{
            'latitude': 37.424015499999996,
            'longitude': -122.09259560000001
        }],
        'passengerName': 'Passenger name',
        'boardingAndSeatingInfo': {
            'boardingGroup': 'B',
            'seatNumber': '42'
        },
        'reservationInfo': {
            'confirmationCode': 'Confirmation code'
        }
    }

    # Create the object
    response = self.http_client.post(url=self.object_url, json=new_object)

    print('Object insert response')
    print(response.text)

    return response.json().get('id')

C#

/// <summary>
/// Create an object.
/// </summary>
/// <param name="issuerId">The issuer ID being used for this request.</param>
/// <param name="classSuffix">Developer-defined unique ID for this pass class.</param>
/// <param name="objectSuffix">Developer-defined unique ID for this pass object.</param>
/// <returns>The pass object ID: "{issuerId}.{objectSuffix}"</returns>
public string CreateObject(string issuerId, string classSuffix, string objectSuffix)
{
  // Check if the object exists
  Stream responseStream = service.Flightobject
      .Get($"{issuerId}.{objectSuffix}")
      .ExecuteAsStream();

  StreamReader responseReader = new StreamReader(responseStream);
  JObject jsonResponse = JObject.Parse(responseReader.ReadToEnd());

  if (!jsonResponse.ContainsKey("error"))
  {
    Console.WriteLine($"Object {issuerId}.{objectSuffix} already exists!");
    return $"{issuerId}.{objectSuffix}";
  }
  else if (jsonResponse["error"].Value<int>("code") != 404)
  {
    // Something else went wrong...
    Console.WriteLine(jsonResponse.ToString());
    return $"{issuerId}.{objectSuffix}";
  }

  // See link below for more information on required properties
  // https://developers.google.com/wallet/tickets/boarding-passes/rest/v1/flightobject
  FlightObject newObject = new FlightObject
  {
    Id = $"{issuerId}.{objectSuffix}",
    ClassId = $"{issuerId}.{classSuffix}",
    State = "ACTIVE",
    HeroImage = new Image
    {
      SourceUri = new ImageUri
      {
        Uri = "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
      },
      ContentDescription = new LocalizedString
      {
        DefaultValue = new TranslatedString
        {
          Language = "en-US",
          Value = "Hero image description"
        }
      }
    },
    TextModulesData = new List<TextModuleData>
    {
      new TextModuleData
      {
        Header = "Text module header",
        Body = "Text module body",
        Id = "TEXT_MODULE_ID"
      }
    },
    LinksModuleData = new LinksModuleData
    {
      Uris = new List<Google.Apis.Walletobjects.v1.Data.Uri>
      {
        new Google.Apis.Walletobjects.v1.Data.Uri
        {
          UriValue = "http://maps.google.com/",
          Description = "Link module URI description",
          Id = "LINK_MODULE_URI_ID"
        },
        new Google.Apis.Walletobjects.v1.Data.Uri
        {
          UriValue = "tel:6505555555",
          Description = "Link module tel description",
          Id = "LINK_MODULE_TEL_ID"
        }
      }
    },
    ImageModulesData = new List<ImageModuleData>
    {
      new ImageModuleData
      {
        MainImage = new Image
        {
          SourceUri = new ImageUri
          {
            Uri = "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
          },
          ContentDescription = new LocalizedString
          {
            DefaultValue = new TranslatedString
            {
              Language = "en-US",
              Value = "Image module description"
            }
          }
        },
        Id = "IMAGE_MODULE_ID"
      }
    },
    Barcode = new Barcode
    {
      Type = "QR_CODE",
      Value = "QR code"
    },
    Locations = new List<LatLongPoint>
    {
      new LatLongPoint
      {
        Latitude = 37.424015499999996,
        Longitude = -122.09259560000001
      }
    },
    PassengerName = "Passenger name",
    BoardingAndSeatingInfo = new BoardingAndSeatingInfo
    {
      BoardingGroup = "B",
      SeatNumber = "42"
    },
    ReservationInfo = new ReservationInfo
    {
      ConfirmationCode = "Confirmation code"
    }
  };

  responseStream = service.Flightobject
      .Insert(newObject)
      .ExecuteAsStream();
  responseReader = new StreamReader(responseStream);
  jsonResponse = JObject.Parse(responseReader.ReadToEnd());

  Console.WriteLine("Object insert response");
  Console.WriteLine(jsonResponse.ToString());

  return $"{issuerId}.{objectSuffix}";
}

Node.js

/**
 * Create an object.
 *
 * @param {string} issuerId The issuer ID being used for this request.
 * @param {string} classSuffix Developer-defined unique ID for the pass class.
 * @param {string} objectSuffix Developer-defined unique ID for the pass object.
 *
 * @returns {string} The pass object ID: `${issuerId}.${objectSuffix}`
 */
async createObject(issuerId, classSuffix, objectSuffix) {
  let response;

  // Check if the object exists
  try {
    response = await this.httpClient.request({
      url: `${this.objectUrl}/${issuerId}.${objectSuffix}`,
      method: 'GET'
    });

    console.log(`Object ${issuerId}.${objectSuffix} already exists!`);

    return `${issuerId}.${objectSuffix}`;
  } catch (err) {
    if (err.response && err.response.status !== 404) {
      // Something else went wrong...
      console.log(err);
      return `${issuerId}.${objectSuffix}`;
    }
  }

  // See link below for more information on required properties
  // https://developers.google.com/wallet/tickets/boarding-passes/rest/v1/flightobject
  let newObject = {
    'id': `${issuerId}.${objectSuffix}`,
    'classId': `${issuerId}.${classSuffix}`,
    'state': 'ACTIVE',
    'heroImage': {
      'sourceUri': {
        'uri': 'https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg'
      },
      'contentDescription': {
        'defaultValue': {
          'language': 'en-US',
          'value': 'Hero image description'
        }
      }
    },
    'textModulesData': [
      {
        'header': 'Text module header',
        'body': 'Text module body',
        'id': 'TEXT_MODULE_ID'
      }
    ],
    'linksModuleData': {
      'uris': [
        {
          'uri': 'http://maps.google.com/',
          'description': 'Link module URI description',
          'id': 'LINK_MODULE_URI_ID'
        },
        {
          'uri': 'tel:6505555555',
          'description': 'Link module tel description',
          'id': 'LINK_MODULE_TEL_ID'
        }
      ]
    },
    'imageModulesData': [
      {
        'mainImage': {
          'sourceUri': {
            'uri': 'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg'
          },
          'contentDescription': {
            'defaultValue': {
              'language': 'en-US',
              'value': 'Image module description'
            }
          }
        },
        'id': 'IMAGE_MODULE_ID'
      }
    ],
    'barcode': {
      'type': 'QR_CODE',
      'value': 'QR code'
    },
    'locations': [
      {
        'latitude': 37.424015499999996,
        'longitude': -122.09259560000001
      }
    ],
    'passengerName': 'Passenger name',
    'boardingAndSeatingInfo': {
      'boardingGroup': 'B',
      'seatNumber': '42'
    },
    'reservationInfo': {
      'confirmationCode': 'Confirmation code'
    }
  };

  response = await this.httpClient.request({
    url: this.objectUrl,
    method: 'POST',
    data: newObject
  });

  console.log('Object insert response');
  console.log(response);

  return `${issuerId}.${objectSuffix}`;
}

以上が完了すると、搭乗客のパス オブジェクトがサーバーに作成されます。ただし、この段階では、作成されたパス オブジェクトは Google ユーザーまたはデバイスにリンクされていません。パスを Google ウォレット ユーザーに関連付けるには、まずパスを Google ウォレットに追加する必要があります。

Google ウォレットへの追加

パスを Google ウォレットに追加すると、パス オブジェクトが Google ユーザーにリンクされます。この追加操作は、Google ID でログインしている状況でのみ開始できます。これを行うには、[Google ウォレットに追加] の URL にユーザーを誘導します。

[Google ウォレットに追加] の URL は動的に生成される URL で、前の手順で作成したパス オブジェクト ID に関する次の情報が含まれています。この情報は、JSON Web Token(JWT)としてエンコードされます。

JSON Web Token(JWT)

この JWT には、ユーザーが保存するパス オブジェクトに関して発行者が作成したクレームが含まれています。サービス アカウントの作成手順で取得したサービス アカウント キーの private_key を使用して、この JWT に署名する必要があります。Google では、JWT の署名を確認することでこれらのクレームを検証します。

必要な JWT クレームの構造は次のとおりです。

{
  "aud": "google",
  "origins": ["https://example.com"],
  "iss": "my-service-account@my-project-id.iam.gserviceaccount.com",
  "typ": "savetowallet",
  "payload": {
    "flightObjects": [
      {
        "id": "PASSES_OBJECT_ID_1234567890"
      }
    ]
  }
}

JWT claims を作成し、サービス アカウント キーの private_key でクレームに署名して token を取得します。

Java

/**
 * Generate a signed JWT that creates a new pass class and object.
 *
 * <p>When the user opens the "Add to Google Wallet" URL and saves the pass to their wallet, the
 * pass class and object defined in the JWT are created. This allows you to create multiple pass
 * classes and objects in one API call when the user saves the pass to their wallet.
 *
 * @param issuerId The issuer ID being used for this request.
 * @param classSuffix Developer-defined unique ID for this pass class.
 * @param objectSuffix Developer-defined unique ID for the pass object.
 * @return An "Add to Google Wallet" link.
 */
public String CreateJWTNewObjects(String issuerId, String classSuffix, String objectSuffix) {
  // See link below for more information on required properties
  // https://developers.google.com/wallet/tickets/boarding-passes/rest/v1/flightclass
  FlightClass newClass =
      new FlightClass()
          .setId(String.format("%s.%s", issuerId, classSuffix))
          .setIssuerName("Issuer name")
          .setReviewStatus("UNDER_REVIEW")
          .setLocalScheduledDepartureDateTime("2023-07-02T15:30:00")
          .setFlightHeader(
              new FlightHeader()
                  .setCarrier(new FlightCarrier().setCarrierIataCode("LX"))
                  .setFlightNumber("123"))
          .setOrigin(new AirportInfo().setAirportIataCode("LAX").setTerminal("1").setGate("A2"))
          .setDestination(
              new AirportInfo().setAirportIataCode("SFO").setTerminal("2").setGate("C3"));

  // See link below for more information on required properties
  // https://developers.google.com/wallet/tickets/boarding-passes/rest/v1/flightobject
  FlightObject newObject =
      new FlightObject()
          .setId(String.format("%s.%s", issuerId, objectSuffix))
          .setClassId(String.format("%s.%s", issuerId, classSuffix))
          .setState("ACTIVE")
          .setHeroImage(
              new Image()
                  .setSourceUri(
                      new ImageUri()
                          .setUri(
                              "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"))
                  .setContentDescription(
                      new LocalizedString()
                          .setDefaultValue(
                              new TranslatedString()
                                  .setLanguage("en-US")
                                  .setValue("Hero image description"))))
          .setTextModulesData(
              Arrays.asList(
                  new TextModuleData()
                      .setHeader("Text module header")
                      .setBody("Text module body")
                      .setId("TEXT_MODULE_ID")))
          .setLinksModuleData(
              new LinksModuleData()
                  .setUris(
                      Arrays.asList(
                          new Uri()
                              .setUri("http://maps.google.com/")
                              .setDescription("Link module URI description")
                              .setId("LINK_MODULE_URI_ID"),
                          new Uri()
                              .setUri("tel:6505555555")
                              .setDescription("Link module tel description")
                              .setId("LINK_MODULE_TEL_ID"))))
          .setImageModulesData(
              Arrays.asList(
                  new ImageModuleData()
                      .setMainImage(
                          new Image()
                              .setSourceUri(
                                  new ImageUri()
                                      .setUri(
                                          "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"))
                              .setContentDescription(
                                  new LocalizedString()
                                      .setDefaultValue(
                                          new TranslatedString()
                                              .setLanguage("en-US")
                                              .setValue("Image module description"))))
                      .setId("IMAGE_MODULE_ID")))
          .setBarcode(new Barcode().setType("QR_CODE").setValue("QR code value"))
          .setLocations(
              Arrays.asList(
                  new LatLongPoint()
                      .setLatitude(37.424015499999996)
                      .setLongitude(-122.09259560000001)))
          .setPassengerName("Passenger name")
          .setBoardingAndSeatingInfo(
              new BoardingAndSeatingInfo().setBoardingGroup("B").setSeatNumber("42"))
          .setReservationInfo(new ReservationInfo().setConfirmationCode("Confirmation code"));

  // Create the JWT as a HashMap object
  HashMap<String, Object> claims = new HashMap<String, Object>();
  claims.put("iss", ((ServiceAccountCredentials) credentials).getClientEmail());
  claims.put("aud", "google");
  claims.put("origins", Arrays.asList("www.example.com"));
  claims.put("typ", "savetowallet");

  // Create the Google Wallet payload and add to the JWT
  HashMap<String, Object> payload = new HashMap<String, Object>();
  payload.put("flightClasses", Arrays.asList(newClass));
  payload.put("flightObjects", Arrays.asList(newObject));
  claims.put("payload", payload);

  // The service account credentials are used to sign the JWT
  Algorithm algorithm =
      Algorithm.RSA256(
          null, (RSAPrivateKey) ((ServiceAccountCredentials) credentials).getPrivateKey());
  String token = JWT.create().withPayload(claims).sign(algorithm);

  System.out.println("Add to Google Wallet link");
  System.out.println(String.format("https://pay.google.com/gp/v/save/%s", token));

  return String.format("https://pay.google.com/gp/v/save/%s", token);
}

PHP

/**
 * Generate a signed JWT that creates a new pass class and object.
 *
 * When the user opens the "Add to Google Wallet" URL and saves the pass to
 * their wallet, the pass class and object defined in the JWT are
 * created. This allows you to create multiple pass classes and objects in
 * one API call when the user saves the pass to their wallet.
 *
 * @param string $issuerId The issuer ID being used for this request.
 * @param string $classSuffix Developer-defined unique ID for the pass class.
 * @param string $objectSuffix Developer-defined unique ID for the pass object.
 *
 * @return string An "Add to Google Wallet" link.
 */
public function createJwtNewObjects(string $issuerId, string $classSuffix, string $objectSuffix)
{
  // See link below for more information on required properties
  // https://developers.google.com/wallet/tickets/boarding-passes/rest/v1/flightclass
  $newClass = new Google_Service_Walletobjects_FlightClass([
    'id' => "{$issuerId}.{$classSuffix}",
    'issuerName' => 'Issuer name',
    'reviewStatus' => 'UNDER_REVIEW',
    'localScheduledDepartureDateTime' => '2023-07-02T15:30:00',
    'flightHeader' => new Google_Service_Walletobjects_FlightHeader([
      'carrier' => new Google_Service_Walletobjects_FlightCarrier([
        'carrierIataCode' => 'LX'
      ]),
      'flightNumber' => '123'
    ]),
    'origin' => new Google_Service_Walletobjects_AirportInfo([
      'airportIataCode' => 'LAX',
      'terminal' => '1',
      'gate' => 'A2'
    ]),
    'destination' => new Google_Service_Walletobjects_AirportInfo([
      'airportIataCode' => 'SFO',
      'terminal' => '2',
      'gate' => 'C3'
    ])
  ]);

  // See link below for more information on required properties
  // https://developers.google.com/wallet/tickets/boarding-passes/rest/v1/flightobject
  $newObject = new Google_Service_Walletobjects_FlightObject([
    'id' => "{$issuerId}.{$objectSuffix}",
    'classId' => "{$issuerId}.{$classSuffix}",
    'state' => 'ACTIVE',
    'heroImage' => new Google_Service_Walletobjects_Image([
      'sourceUri' => new Google_Service_Walletobjects_ImageUri([
        'uri' => 'https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg'
      ]),
      'contentDescription' => new Google_Service_Walletobjects_LocalizedString([
        'defaultValue' => new Google_Service_Walletobjects_TranslatedString([
          'language' => 'en-US',
          'value' => 'Hero image description'
        ])
      ])
    ]),
    'textModulesData' => [
      new Google_Service_Walletobjects_TextModuleData([
        'header' => 'Text module header',
        'body' => 'Text module body',
        'id' => 'TEXT_MODULE_ID'
      ])
    ],
    'linksModuleData' => new Google_Service_Walletobjects_LinksModuleData([
      'uris' => [
        new Google_Service_Walletobjects_Uri([
          'uri' => 'http://maps.google.com/',
          'description' => 'Link module URI description',
          'id' => 'LINK_MODULE_URI_ID'
        ]),
        new Google_Service_Walletobjects_Uri([
          'uri' => 'tel:6505555555',
          'description' => 'Link module tel description',
          'id' => 'LINK_MODULE_TEL_ID'
        ])
      ]
    ]),
    'imageModulesData' => [
      new Google_Service_Walletobjects_ImageModuleData([
        'mainImage' => new Google_Service_Walletobjects_Image([
          'sourceUri' => new Google_Service_Walletobjects_ImageUri([
            'uri' => 'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg'
          ]),
          'contentDescription' => new Google_Service_Walletobjects_LocalizedString([
            'defaultValue' => new Google_Service_Walletobjects_TranslatedString([
              'language' => 'en-US',
              'value' => 'Image module description'
            ])
          ])
        ]),
        'id' => 'IMAGE_MODULE_ID'
      ])
    ],
    'barcode' => new Google_Service_Walletobjects_Barcode([
      'type' => 'QR_CODE',
      'value' => 'QR code value'
    ]),
    'locations' => [
      new Google_Service_Walletobjects_LatLongPoint([
        'latitude' => 37.424015499999996,
        'longitude' =>  -122.09259560000001
      ])
    ],
    'passengerName' => 'Passenger name',
    'boardingAndSeatingInfo' => new Google_Service_Walletobjects_BoardingAndSeatingInfo([
      'boardingGroup' => 'B',
      'seatNumber' => '42'
    ]),
    'reservationInfo' => new Google_Service_Walletobjects_ReservationInfo([
      'confirmationCode' => 'Confirmation code'
    ])
  ]);

  // The service account credentials are used to sign the JWT
  $serviceAccount = json_decode(file_get_contents($this->keyFilePath), true);

  // Create the JWT as an array of key/value pairs
  $claims = [
    'iss' => $serviceAccount['client_email'],
    'aud' => 'google',
    'origins' => ['www.example.com'],
    'typ' => 'savetowallet',
    'payload' => [
      'flightClasses' => [
        $newClass
      ],
      'flightObjects' => [
        $newObject
      ]
    ]
  ];

  $token = JWT::encode(
    $claims,
    $serviceAccount['private_key'],
    'RS256'
  );

  print "Add to Google Wallet link\n";
  print "https://pay.google.com/gp/v/save/{$token}";

  return "https://pay.google.com/gp/v/save/{$token}";
}

Python

def create_jwt_new_objects(self, issuer_id: str, class_suffix: str,
                           object_suffix: str) -> str:
    """Generate a signed JWT that creates a new pass class and object.

    When the user opens the "Add to Google Wallet" URL and saves the pass to
    their wallet, the pass class and object defined in the JWT are
    created. This allows you to create multiple pass classes and objects in
    one API call when the user saves the pass to their wallet.

    Args:
        issuer_id (str): The issuer ID being used for this request.
        class_suffix (str): Developer-defined unique ID for the pass class.
        object_suffix (str): Developer-defined unique ID for the pass object.

    Returns:
        An "Add to Google Wallet" link.
    """

    # Seelink  below for more information on required properties
    # https://developers.google.com/wallet/tickets/boarding-passes/rest/v1/flightclass
    new_class = {
        'id': f'{issuer_id}.{class_suffix}',
        'issuerName': 'Issuer name',
        'reviewStatus': 'UNDER_REVIEW',
        'localScheduledDepartureDateTime': '2023-07-02T15:30:00',
        'flightHeader': {
            'carrier': {
                'carrierIataCode': 'LX'
            },
            'flightNumber': '123'
        },
        'origin': {
            'airportIataCode': 'LAX',
            'terminal': '1',
            'gate': 'A2'
        },
        'destination': {
            'airportIataCode': 'SFO',
            'terminal': '2',
            'gate': 'C3'
        }
    }

    # See link below for more information on required properties
    # https://developers.google.com/wallet/tickets/boarding-passes/rest/v1/flightclass
    new_object = {
        'id': f'{issuer_id}.{object_suffix}',
        'classId': f'{issuer_id}.{class_suffix}',
        'state': 'ACTIVE',
        'heroImage': {
            'sourceUri': {
                'uri':
                    'https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg'
            },
            'contentDescription': {
                'defaultValue': {
                    'language': 'en-US',
                    'value': 'Hero image description'
                }
            }
        },
        'textModulesData': [{
            'header': 'Text module header',
            'body': 'Text module body',
            'id': 'TEXT_MODULE_ID'
        }],
        'linksModuleData': {
            'uris': [{
                'uri': 'http://maps.google.com/',
                'description': 'Link module URI description',
                'id': 'LINK_MODULE_URI_ID'
            }, {
                'uri': 'tel:6505555555',
                'description': 'Link module tel description',
                'id': 'LINK_MODULE_TEL_ID'
            }]
        },
        'imageModulesData': [{
            'mainImage': {
                'sourceUri': {
                    'uri':
                        'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg'
                },
                'contentDescription': {
                    'defaultValue': {
                        'language': 'en-US',
                        'value': 'Image module description'
                    }
                }
            },
            'id': 'IMAGE_MODULE_ID'
        }],
        'barcode': {
            'type': 'QR_CODE',
            'value': 'QR code'
        },
        'locations': [{
            'latitude': 37.424015499999996,
            'longitude': -122.09259560000001
        }],
        'passengerName': 'Passenger name',
        'boardingAndSeatingInfo': {
            'boardingGroup': 'B',
            'seatNumber': '42'
        },
        'reservationInfo': {
            'confirmationCode': 'Confirmation code'
        }
    }

    # Create the JWT claims
    claims = {
        'iss': self.credentials.service_account_email,
        'aud': 'google',
        'origins': ['www.example.com'],
        'typ': 'savetowallet',
        'payload': {
            # The listed classes and objects will be created
            'flightClasses': [new_class],
            'flightObjects': [new_object]
        }
    }

    # The service account credentials are used to sign the JWT
    signer = crypt.RSASigner.from_service_account_file(self.key_file_path)
    token = jwt.encode(signer, claims).decode('utf-8')

    print('Add to Google Wallet link')
    print(f'https://pay.google.com/gp/v/save/{token}')

    return f'https://pay.google.com/gp/v/save/{token}'

C#

/// <summary>
/// Generate a signed JWT that creates a new pass class and object.
/// <para />
/// When the user opens the "Add to Google Wallet" URL and saves the pass to
/// their wallet, the pass class and object defined in the JWT are created.
/// This allows you to create multiple pass classes and objects in one API
/// call when the user saves the pass to their wallet.
/// <para />
/// The Google Wallet C# library uses Newtonsoft.Json.JsonPropertyAttribute
/// to specify the property names when converting objects to JSON. The
/// Newtonsoft.Json.JsonConvert.SerializeObject method will automatically
/// serialize the object with the right property names.
/// </summary>
/// <param name="issuerId">The issuer ID being used for this request.</param>
/// <param name="classSuffix">Developer-defined unique ID for this pass class.</param>
/// <param name="objectSuffix">Developer-defined unique ID for the pass object.</param>
/// <returns>An "Add to Google Wallet" link.</returns>
public string CreateJWTNewObjects(string issuerId, string classSuffix, string objectSuffix)
{
  // Ignore null values when serializing to/from JSON
  JsonSerializerSettings excludeNulls = new JsonSerializerSettings()
  {
    NullValueHandling = NullValueHandling.Ignore
  };

  // See link below for more information on required properties
  // https://developers.google.com/wallet/tickets/boarding-passes/rest/v1/flightclass
  FlightClass newClass = new FlightClass
  {
    Id = $"{issuerId}.{classSuffix}",
    IssuerName = "Issuer name",
    ReviewStatus = "UNDER_REVIEW",
    LocalScheduledDepartureDateTime = "2023-07-02T15:30:00",
    FlightHeader = new FlightHeader
    {
      Carrier = new FlightCarrier
      {
        CarrierIataCode = "LX"
      },
      FlightNumber = "123"
    },
    Origin = new AirportInfo
    {
      AirportIataCode = "LAX",
      Terminal = "1",
      Gate = "A2"
    },
    Destination = new AirportInfo
    {
      AirportIataCode = "SFO",
      Terminal = "2",
      Gate = "C3"
    }
  };

  // See link below for more information on required properties
  // https://developers.google.com/wallet/tickets/boarding-passes/rest/v1/flightobject
  FlightObject newObject = new FlightObject
  {
    Id = $"{issuerId}.{objectSuffix}",
    ClassId = $"{issuerId}.{classSuffix}",
    State = "ACTIVE",
    HeroImage = new Image
    {
      SourceUri = new ImageUri
      {
        Uri = "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
      },
      ContentDescription = new LocalizedString
      {
        DefaultValue = new TranslatedString
        {
          Language = "en-US",
          Value = "Hero image description"
        }
      }
    },
    TextModulesData = new List<TextModuleData>
    {
      new TextModuleData
      {
        Header = "Text module header",
        Body = "Text module body",
        Id = "TEXT_MODULE_ID"
      }
    },
    LinksModuleData = new LinksModuleData
    {
      Uris = new List<Google.Apis.Walletobjects.v1.Data.Uri>
      {
        new Google.Apis.Walletobjects.v1.Data.Uri
        {
          UriValue = "http://maps.google.com/",
          Description = "Link module URI description",
          Id = "LINK_MODULE_URI_ID"
        },
        new Google.Apis.Walletobjects.v1.Data.Uri
        {
          UriValue = "tel:6505555555",
          Description = "Link module tel description",
          Id = "LINK_MODULE_TEL_ID"
        }
      }
    },
    ImageModulesData = new List<ImageModuleData>
    {
      new ImageModuleData
      {
        MainImage = new Image
        {
          SourceUri = new ImageUri
          {
            Uri = "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
          },
          ContentDescription = new LocalizedString
          {
            DefaultValue = new TranslatedString
            {
              Language = "en-US",
              Value = "Image module description"
            }
          }
        },
        Id = "IMAGE_MODULE_ID"
      }
    },
    Barcode = new Barcode
    {
      Type = "QR_CODE",
      Value = "QR code"
    },
    Locations = new List<LatLongPoint>
    {
      new LatLongPoint
      {
        Latitude = 37.424015499999996,
        Longitude = -122.09259560000001
      }
    },
    PassengerName = "Passenger name",
    BoardingAndSeatingInfo = new BoardingAndSeatingInfo
    {
      BoardingGroup = "B",
      SeatNumber = "42"
    },
    ReservationInfo = new ReservationInfo
    {
      ConfirmationCode = "Confirmation code"
    }
  };

  // Create JSON representations of the class and object
  JObject serializedClass = JObject.Parse(
      JsonConvert.SerializeObject(newClass, excludeNulls));
  JObject serializedObject = JObject.Parse(
      JsonConvert.SerializeObject(newObject, excludeNulls));

  // Create the JWT as a JSON object
  JObject jwtPayload = JObject.Parse(JsonConvert.SerializeObject(new
  {
    iss = credentials.Id,
    aud = "google",
    origins = new List<string>
    {
      "www.example.com"
    },
    typ = "savetowallet",
    payload = JObject.Parse(JsonConvert.SerializeObject(new
    {
      // The listed classes and objects will be created
      // when the user saves the pass to their wallet
      flightClasses = new List<JObject>
      {
        serializedClass
      },
      flightObjects = new List<JObject>
      {
        serializedObject
      }
    }))
  }));

  // Deserialize into a JwtPayload
  JwtPayload claims = JwtPayload.Deserialize(jwtPayload.ToString());

  // The service account credentials are used to sign the JWT
  RsaSecurityKey key = new RsaSecurityKey(credentials.Key);
  SigningCredentials signingCredentials = new SigningCredentials(
      key, SecurityAlgorithms.RsaSha256);
  JwtSecurityToken jwt = new JwtSecurityToken(
      new JwtHeader(signingCredentials), claims);
  string token = new JwtSecurityTokenHandler().WriteToken(jwt);

  Console.WriteLine("Add to Google Wallet link");
  Console.WriteLine($"https://pay.google.com/gp/v/save/{token}");

  return $"https://pay.google.com/gp/v/save/{token}";
}

Node.js

/**
 * Generate a signed JWT that creates a new pass class and object.
 *
 * When the user opens the "Add to Google Wallet" URL and saves the pass to
 * their wallet, the pass class and object defined in the JWT are
 * created. This allows you to create multiple pass classes and objects in
 * one API call when the user saves the pass to their wallet.
 *
 * @param {string} issuerId The issuer ID being used for this request.
 * @param {string} classSuffix Developer-defined unique ID for the pass class.
 * @param {string} objectSuffix Developer-defined unique ID for the pass object.
 *
 * @returns {string} An "Add to Google Wallet" link.
 */
createJwtNewObjects(issuerId, classSuffix, objectSuffix) {
  // See link below for more information on required properties
  // https://developers.google.com/wallet/tickets/boarding-passes/rest/v1/flightclass
  let newClass = {
    'id': `${issuerId}.${classSuffix}`,
    'issuerName': 'Issuer name',
    'reviewStatus': 'UNDER_REVIEW',
    'localScheduledDepartureDateTime': '2023-07-02T15:30:00',
    'flightHeader': {
      'carrier': {
        'carrierIataCode': 'LX'
      },
      'flightNumber': '123'
    },
    'origin': {
      'airportIataCode': 'LAX',
      'terminal': '1',
      'gate': 'A2'
    },
    'destination': {
      'airportIataCode': 'SFO',
      'terminal': '2',
      'gate': 'C3'
    }
  };

  // See link below for more information on required properties
  // https://developers.google.com/wallet/tickets/boarding-passes/rest/v1/flightobject
  let newObject = {
    'id': `${issuerId}.${objectSuffix}`,
    'classId': `${issuerId}.${classSuffix}`,
    'state': 'ACTIVE',
    'heroImage': {
      'sourceUri': {
        'uri': 'https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg'
      },
      'contentDescription': {
        'defaultValue': {
          'language': 'en-US',
          'value': 'Hero image description'
        }
      }
    },
    'textModulesData': [
      {
        'header': 'Text module header',
        'body': 'Text module body',
        'id': 'TEXT_MODULE_ID'
      }
    ],
    'linksModuleData': {
      'uris': [
        {
          'uri': 'http://maps.google.com/',
          'description': 'Link module URI description',
          'id': 'LINK_MODULE_URI_ID'
        },
        {
          'uri': 'tel:6505555555',
          'description': 'Link module tel description',
          'id': 'LINK_MODULE_TEL_ID'
        }
      ]
    },
    'imageModulesData': [
      {
        'mainImage': {
          'sourceUri': {
            'uri': 'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg'
          },
          'contentDescription': {
            'defaultValue': {
              'language': 'en-US',
              'value': 'Image module description'
            }
          }
        },
        'id': 'IMAGE_MODULE_ID'
      }
    ],
    'barcode': {
      'type': 'QR_CODE',
      'value': 'QR code'
    },
    'locations': [
      {
        'latitude': 37.424015499999996,
        'longitude': -122.09259560000001
      }
    ],
    'passengerName': 'Passenger name',
    'boardingAndSeatingInfo': {
      'boardingGroup': 'B',
      'seatNumber': '42'
    },
    'reservationInfo': {
      'confirmationCode': 'Confirmation code'
    }
  };

  // Create the JWT claims
  let claims = {
    iss: this.credentials.client_email,
    aud: 'google',
    origins: ['www.example.com'],
    typ: 'savetowallet',
    payload: {
      // The listed classes and objects will be created
      flightClasses: [newClass],
      flightObjects: [newObject]
    }
  };

  // The service account credentials are used to sign the JWT
  let token = jwt.sign(claims, this.credentials.private_key, { algorithm: 'RS256' });

  console.log('Add to Google Wallet link');
  console.log(`https://pay.google.com/gp/v/save/${token}`);

  return `https://pay.google.com/gp/v/save/${token}`;
}

署名付き JWT を取得したら、この情報を使用して [Google ウォレットに追加] リンクを作成できます。

[Google ウォレットに追加] リンクの形式は次のとおりです。

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

このリンクをウェブページまたはメールにハイパーリンクとして埋め込むことができます。チャットや SMS などの他のチャネルを使用して乗客に送信することも可能です。

エンコードされた JWT の安全な長さは 1,800 文字までです。JWT がこの上限を下回っている場合、オブジェクト全体を署名付き JWT に含めることができます。JWT の長さがこの上限を超えないようにしてください。1,800 文字を超えると、ウェブブラウザによって一部が切り捨てられ、[Google ウォレットに追加] が正常に機能しない場合があります。

[Google ウォレットに追加] ボタン

最善の結果を得るには、ウェブページ、メール、Android アプリで Google ウォレット ボタンのアセットを利用します。

Google ウォレット ボタンは次の 2 通りの方法で表示できます。

  • JavaScript ウェブボタンはウェブサイトで使用できます。
  • Google ウォレット ボタン付きの JWT リンクは、メール、SMS、アプリ、ウェブサイトで使用できます。

[テスト専用] パス

デモモードを使用している場合は、作成するすべてのパスのタイトルに「[テスト用]」というテキストが追加されます。これは、デモパスとライブパスを区別するためです。このようにデモモードのパスに追加されたテキストは、Google のチームから製品版の承認を得ると、接続されたデバイスでユーザーがウォレット アプリを再び開いたときに表示されなくなります。

次のステップ