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

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

このドキュメントでは、Google ウォレットの搭乗券フローを実装するための技術的な手順について説明します。また、RBM でスムーズかつ効率的にチェックインできるように、設計上のヒントを含むサンプル会話も備えています。

技術的な実装

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

Prerequisites

Google Wallet API を使用するには、必要な手順を行ってください。

  1. Google ウォレットのパスを作成して配布できるように、ウォレット発行者アカウントを登録します。
  2. Google Cloud Platform(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 ウォレットに追加」機能の提案を送信するには、Open 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. エージェントがお客様の選択を確認します。

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

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

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

    Google ウォレットのアイコンと「Google ウォレットに追加」の提案

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

    ウォレット アプリに、シンプルな搭乗券と [追加] ボタンが表示されている。

  20. ユーザーがボタンをタップするとパスが表示されます。

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

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

    フライトの詳細と QR コードがすべて含まれる搭乗券