Google ウォレットに搭乗券を追加する

RCS と Google ウォレットで Google メッセージを使用すると、シームレスなチェックイン フローを設計できます。ユーザーはチェックインを完了し、搭乗券を受け取って、メッセージ アプリから Google ウォレットに直接追加できます。ウォレットに追加されたパスは、フライトの詳細が変更されると自動的に更新されます。ユーザーは、スマートフォンで最新の搭乗券にすばやくアクセスできます。

このドキュメントでは、搭乗券を Google ウォレット フローに実装するための技術的な手順について説明します。また、RBM を使用してスムーズかつ効率的なチェックイン エクスペリエンスを実現するための設計のヒントと、会話のサンプルも紹介します。

技術実装

搭乗券を Google ウォレット フローに実装するには、Google Wallet API と RBM API を使用します。

前提条件

Google Wallet API の使用を開始するには、次の必須の手順を行います。

  1. 登録して、Google ウォレットのパスを作成して配布できるようにウォレット発行者アカウントを取得します。
  2. Google Cloud(GCP)プロジェクトを作成します(まだ作成していない場合)。
  3. Google Wallet API を有効にします。
  4. Google Wallet API を呼び出すためのサービス アカウントとキーを作成します。
  5. Google Pay と Google ウォレットのコンソールでサービス アカウントを承認します。
  6. 搭乗券テンプレートを使用して、新しい Boarding クラスを作成します。

Google ウォレット API

搭乗券を作成し、RBM 用の [Google ウォレットに追加] URL を生成する手順は次のとおりです。

  1. 必要な認証と認可を行います。
  2. パス オブジェクトを作成します。
  3. 署名付き JSON Web Token(JWT)を取得します。エンコードされた JWT の最大長は 2,048 文字です。
  4. JWT を使用して [Google ウォレットに追加] URL を生成します。

RBM API

RBM から [Google ウォレットに追加] の候補を送信するには、[URL を開く] アクションを送信します。 メッセージ ペイロードで次の操作を行います。

  1. text に「Google ウォレットに追加」と入力します。
  2. url に [Google ウォレットに追加] URL を入力します。

候補のラベルに Google ウォレットのアイコンが自動的に表示されます。

[Google ウォレットに追加] の候補に表示される Google ウォレットのアイコン

会話設計

このサンプルでは、会話の独自の機能を使用して、ユーザーをチェックイン フロー全体にわたって案内します。自然なダイアログと、ワンタップの候補やリッチカードなどの豊富な機能を使用して、ユーザーが目標を達成できるようにする方法を示します。この例では、ユーザーの目標は次のとおりです。(1)フライト エクスペリエンスをカスタマイズする、(2)搭乗券を受け取る、(3)空港で簡単にアクセスできるように Google ウォレットに追加する。

次は、会話の概要です。その後に、設計のヒントとフローの詳細な手順を示します。エージェントに同様のデザインを実装するには、手順の後のコードサンプルをご覧ください。

会話の図

設計に関するアドバイス

チェックイン フローを設計する際は、次の原則に留意してください。

  • 最初のメッセージが最も重要です。会話の目的を簡潔に説明して、ユーザーが参加する理由を示します。
  • 各メッセージで、少量の情報を提供し、ユーザーにレスポンスを促します。候補の返信候補のアクション は、ユーザーが次のステップに進むのに役立ちます。
  • エージェントは、ロボットではなく、レスポンスが迅速である必要があります。ブランドのトーンを反映した言語を使用します。理想的なブランド担当者は、お客様とどのようにチャットしますか?
  • 人は特別扱いされることを好みます。ユーザーのフライト履歴に基づいて座席や食事を提案することで、チェックイン エクスペリエンスをパーソナライズできます。
  • リッチカードカルーセル を使用すると、会話がより動的になります。画像や詳細情報を共有して、ユーザーが選択肢の中から選択できるようにします。
  • 良い会話は、良い結末を迎えます。搭乗券を送信する前に、ユーザーのチェックインの詳細を確認します。フレンドリーな見送りで、人間味を添えます。

チェックイン フロー

  1. エージェントは、フライトのチェックインが開始されたことをユーザーに通知します。

    チェックインの詳細と返信文の候補を含む挨拶メッセージ

    コードサンプル

    const suggestions = [
      {
        reply: {
          text: '⚡ Check in',
          postbackData: 'checkIn',
        },
      },
      {
        reply: {
          text: '⏰ Remind me later',
          postbackData: 'remindMe',
        },
      },
      {
        reply: {
          text: '✈️ View my flight details',
          postbackData: 'flightDetails',
        },
      },
      {
        reply: {
          text: '🔀 Change my flight',
          postbackData: 'flightChange',
        },
      },
    ];  
    
    const params = {
      messageText: 'Check-in for your flight',
      messageDescription: '👏 Happy morning, Jo! Check-in is now open for your flight from London to Mumbai on ' + getFlightTime() + ' at 2:00PM. What would you like to do? ',
      msisdn: phoneNumber,
      suggestions: suggestions,
      imageUrl: getImageUrl('fly.png'),
      height: 'MEDIUM',
    };  
    
    rbmApiHelper.sendRichCard(params);      
  2. ユーザーは、候補の返信をタップしてチェックインします。

    チェックインの候補がタップされた

  3. エージェントは、チェックイン プロセスの期待値を設定します。

    メッセージには「OK, great.」と表示されます。チェックインは 3 ステップで完了します。オンボーディングの最初の手順は次のとおりです

    コードサンプル

    const params = {
      messageText: "OK, great. It's just 3 simple steps to check in. Here's the first step to get you onboard:",
      msisdn: msisdn,
    };  
    
    let self = this;
    
    rbmApiHelper.sendMessage(params, function (response, err) {
      self.sendPolicyImage(msisdn);
    });   

  4. エージェントは、安全に関するポリシーに同意するようユーザーに求めます。

    安全に関するポリシーのインフォグラフィックと、同意または不同意の提案を含むリッチカード。カードのテキスト: 安全なフライトを確保するため、安全に関するポリシーをご確認のうえ、同意したことをお知らせください。

    コードサンプル

    const suggestions = [
      {
        reply: {
          text: 'Yes, I agree',
          postbackData: 'policy_agree',
        },
      },
      {
        reply: {
          text: "No, I don't agree",
          postbackData: 'policy_nack',
        },
      },
    ];  
    
    const params = {
      messageText: 'Baggage safety policy',
      messageDescription: 'To help us ensure a safe flight, please review our safety policy and let us know you agree',
      msisdn: msisdn,
      suggestions: suggestions,
      imageUrl: getImageUrl('policyImage.png'),
      height: 'MEDIUM',
      orientation: 'HORIZONTAL',
      thumbnailImageAlignment: 'LEFT',
    };  
    
    rbmApiHelper.sendRichCard(params);

  5. ユーザーは、候補の返信をタップして同意します。

    同意する候補がタップされた

  6. エージェントはユーザーに感謝し、次のステップを紹介します。

    メッセージ: 安全な乗客は幸せな乗客です。ご協力ありがとうございました。次のステップ

    コードサンプル

    const params = {
      messageText: "Thank you - A safe passenger is a happy passenger! Here's the next step:",
      msisdn: msisdn,
    };
    
    let self = this;
    
    rbmApiHelper.sendMessage(params, function (response, err) {
      self.sendPlan(msisdn);
    });     

  7. エージェントは、座席を選択するようユーザーに促します。

    座席マップのインフォグラフィックを含むリッチカード。カードのテキスト: ゆったりとくつろぐ時間です。お客様の前回のフライトに基づいて、おすすめの座席をご提案します。ご希望の座席を選択するか、番号を入力してご希望の座席をお知らせください。カードの下に、いくつかの座席オプションが表示される

    コードサンプル

    const suggestions = [
      {
        reply: {
          text: 'View the seat map',
          postbackData: 'view_seat_map',
        },
      },
    ];
    
    const outerSuggestions = [
      {
        reply: {
          text: '17A',
          postbackData: 'seat_17A',
        },
      },
      {
        reply: {
          text: '17C',
          postbackData: 'seat_17C',
        },
      },
      {
        reply: {
          text: '18A',
          postbackData: 'seat_18A',
        },
      },
      {
        reply: {
          text: 'Show me more',
          postbackData: 'more',
        },
      },
    ];  
    
    const params = {
      messageText: 'Choose your seat',
      messageDescription: "It's time to sit back and get comfy! 💺 We've recommended some seats based on your last flight. Choose the one you want, or let us know your preferred seat by typing the number.",
      msisdn: msisdn,
      imageUrl: getImageUrl('seatMap.png'),
      height: 'TALL',
      orientation: 'VERTICAL',
      outerSuggestions: outerSuggestions
    };  
    
    rbmApiHelper.sendRichCard(params);

  8. ユーザーは、選択した座席の返信の候補をタップします。

    18A の座席の候補がタップされた

  9. エージェントはユーザーの選択を確認します。

    メッセージの状態: 18A 席を確保しました。

    コードサンプル

    this.seatmap[msisdn] = seat;  
    
    const params = {
      messageText: `Seat ${seat}, you got it`,
      msisdn: msisdn,
    };  
    
    let self = this;  
      rbmApiHelper.sendMessage(params, function(res) {
        self.sendFoodOptions(msisdn);
    }); 

  10. エージェントは、機内食を選択するようユーザーに求めます。

    メッセージ: さて、食べ物の話に移りましょう。機内食を事前予約できます。ベジタリアン向けのメイン料理か、鶏肉のメイン料理でよろしいですか?

    コードサンプル

    const params = {
      messageText: `Now let's talk food 😋 You can pre-order your in-flight meal. Would you be happy with a vegetarian entree or a chicken entree?`,
      msisdn: msisdn,
    };  
    
    let self = this;  
    
    rbmApiHelper.sendMessage(params, function(res) {
      self.sendFoodDetails(msisdn);
    });

  11. エージェントは食事の選択肢を表示します。

    リッチカードのカルーセルに 2 つのカードが表示されています。1 つはサラダの画像、もう 1 つはローストチキンの画像です。どちらのカードにも、食材リストと、その食事を選ぶことを提案するメッセージが表示されています

    コードサンプル

    const cardContents = [
      {
        title: 'Panzanella salad (v)',
        description: 'Ingredients: bread, lettuce, onions, tomatoes, olive oil',
        suggestions: [
          {
            reply: {
              text: 'Choose vegetarian',
              postbackData: 'veggie',
            },
          },
        ],
        media: {
          height: 'MEDIUM',
          contentInfo: {
            fileUrl: getImageUrl('salad.jpg'),
          },
        },
      },
      {
        title: 'Grilled chicken with greens',
        description: 'Ingredients: chicken, potatoes, peppers, olive oil',
        suggestions: [
          {
            reply: {
              text: 'Choose chicken',
              postbackData: 'chicken',
            },
          },
        ],
        media: {
          height: 'MEDIUM',
          contentInfo: {
            fileUrl: getImageUrl('chicken.png'),
          },
        },
      },
    ];  
    
    const params = {
      msisdn: msisdn,
      cardContents: cardContents,
    };  
    
    rbmApiHelper.sendCarouselCard(params);

  12. ユーザーは、選択した食事の候補の返信をタップします。

    ベジタリアンを選択する候補がタップされた。

  13. エージェントはユーザーの選択を確認します。

    メッセージには「ベジタリアンにします」とあります。

    コードサンプル

    const params = {
      messageText: `Vegetarian it is 💚`,
      msisdn: msisdn,
    };  
    
    let self = this;  
    
    rbmApiHelper.sendMessage(params, function (response, err) {
      self.sendAskConfirmation(msisdn);  
    });

  14. エージェントはチェックインの詳細を要約します。

    メッセージの内容: 以下の内容を承りました。座席 18A とベジタリアン ミールをご希望です。選択内容をご確認ください。メッセージの下に、詳細の確認、食事の変更、座席の変更を行うための候補が表示されます。

    コードサンプル

    let seat = this.seatmap[msisdn];  
    
    const suggestions = [
      {
        reply: {
          text: "Yes, I'm happy with that",
          postbackData: 'happy',
        },
      },
      {
        reply: {
          text: 'Change my seat',
          postbackData: 'change_seat',
        },
      },
      {
        reply: {
          text: 'Change my meal',
          postbackData: 'change_meal',
        },
      },
    ];
    
    const params = {
      messageText: "Here's what we've noted down: You've opted for seat " + seat + " and a vegetarian meal. Please confirm your choices.",
      msisdn: msisdn,
      suggestions: suggestions
    };  
    
    rbmApiHelper.sendMessage(params);  

  15. ユーザーは、候補の返信をタップしてチェックインの詳細を確認します。

    詳細を確認する候補がタップされた。

  16. エージェントはチェックインが完了したことを通知します。

    メッセージに「お見事」と表示されます。これでフライトのチェックインが完了しました。こちらが搭乗券になります。皆様にお会いできることを楽しみにしております。

    コードサンプル

    const params = {
      messageText: "Hooray! You're now checked in for your flight ☑️ Here's your boarding pass. We're so happy to host you soon!",
      msisdn: msisdn,
    };  
    
    let self = this;  
    
    rbmApiHelper.sendMessage(params, function (response, err) {
      self.sendWalletPass(msisdn);       
    }); 

  17. エージェントはユーザーの搭乗券を送信します。

    リッチカードには、QR コードとフライトの詳細情報が記載された搭乗券の画像が表示されます。カードのテキスト: 最新情報をお届けします。フライトの詳細が変更された場合は、通知が届きます。カードに [Google ウォレットに追加] という提案が表示されている。

    コードサンプル

    this.walletHelper.createFlightPassUrl(this.seatmap[msisdn]).then((url) => {
      let suggestions = [
        {
          action: {
            text: 'Add to Google Wallet',
            postbackData: 'addToWallet',
            openUrlAction: {
              url: url
            },
          },
        },
      ];  
    
      const params = {
        messageText: 'HS123 LHR to BOM\nPassenger: Jo Flow',
        messageDescription: "We'll keep you up to date! You'll get a notification if your flight details change.",
        msisdn: msisdn,
        suggestions: suggestions,
        imageUrl: getImageUrl('boardingPass.png'),
        height: 'TALL',
        orientation: 'HORIZONTAL',
        thumbnailImageAlignment: 'LEFT',
      };  
    
      rbmApiHelper.sendRichCard(params);
    }); 

    この横型リッチカードの画像は、航空会社が提供する完全に機能する搭乗券です。画像には、スキャン可能なバーコードなど、必要な搭乗情報がすべて表示されます。ユーザーは画像をタップして、Google のメッセージ アプリから搭乗券を表示してスキャンできます。

    リッチカードに [Google ウォレットに追加] の候補が表示されます。この候補は、Google ウォレット アプリを開く [URL を開く] アクション をトリガーします。ユーザーは、このアプリで搭乗券を ウォレットに追加できます(アプリがユーザーのデバイスにインストールされていない場合は、インストールするよう求められます)。 パスが Google ウォレットに追加されると、ユーザーは フライトのリマインダーステータスの更新情報 を、フライトの詳細が変更された場合に自動的に受け取ります。

    パスを Google ウォレットに追加しないユーザーにも、最新情報を提供する必要があります。リッチカードに表示される搭乗情報の変更についてユーザーにメッセージを送信します。

  18. ユーザーは、候補のアクションをタップしてパスを Google ウォレットに追加します。

    Google ウォレットのアイコンと [Google ウォレットに追加] の候補

  19. Google ウォレット アプリが開きます。ユーザーはボタンをタップしてパスをウォレットに追加します。

    ウォレット アプリに簡略化された搭乗券と [追加] ボタンが表示されています。

  20. ユーザーはボタンをタップしてパスを表示します。

    パスの上にチェックマークが表示されます。[Google ウォレットで表示] ボタンが表示されます。

  21. QR コード付きの搭乗券が表示されます。

    フライトの詳細と QR コードが記載された搭乗券