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

Google メッセージを RCS と 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 and Wallet Console でサービス アカウントを承認します。
  6. 搭乗券テンプレートを使用して、新しい搭乗クラスを作成します。

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. エージェントは、チェックイン プロセスの見通しをお客様に伝えます。

    メッセージには次のように表示されます。チェックインは 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 枚のカードが表示されます。どちらのカードにも、食材リストとその食事を選択するための候補が表示されます。

    コードサンプル

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

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

  18. ユーザーが提案されたアクションをタップして、パスを Google ウォレットに追加します。

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

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

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

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

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

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

    フライトの詳細と QR コードがすべて記載されている搭乗券