ユーザーの操作を受信して応答する

このページでは、Google Chat アプリが Google Chat でのユーザー操作を受信して応答する方法について説明します。

Chat 用アプリのインタラクティブなインターフェースを構築するには、次のコンポーネントを使用します。

  • トリガー: Google Chat ユーザーが Chat 用アプリを呼び出す方法(スペースに追加する、メッセージを送信するなど)。
  • イベント オブジェクト: Chat 用アプリがトリガーまたは UI 操作から受け取るデータ。
  • アクション: メッセージの送信やカードベースのユーザー インターフェースの返信など、Chat 用アプリがインタラクションに応答する方法。
Chat 用アプリがスペースに追加されたトリガーからイベント オブジェクトを受け取る
図 1: ユーザーが Chat 用アプリをスペースに追加すると、スペースに追加トリガーが起動し、イベント オブジェクトが送信されます。メッセージで応答するには、Chat 用アプリがイベント オブジェクトを処理し、メッセージを作成するアクションを返します。

Chat 用アプリは、次の方法でインターフェースを構築して表示できます。

  • テキスト、静的カード、インタラクティブ カード、アクセサリ ボタンを含めることができるメッセージ。
  • Chat 用アプリとの 1 対 1 のダイレクト メッセージの [ホーム] タブに表示されるホームページ(アプリホーム)。
  • ダイアログ: 新しいウィンドウで開くカード。通常、ユーザーに情報の送信を求める。
  • リンク プレビュー。外部サービスに関する情報をプレビューするカードです。

前提条件

ユーザー操作の仕組み

ユーザーが Chat 用アプリを操作すると、Google Chat は構成済みのトリガーを呼び出し、Chat 用アプリのエンドポイントまたは関数にイベント オブジェクトを送信します。Chat 用アプリはイベント オブジェクトを処理し、30 秒以内にアクションを同期的に返すか、Chat API を使用して非同期的に応答できます。

次の図は、Google Chat 用アプリがユーザー操作を処理して応答する方法を示しています。

Google Chat アプリがユーザーのインタラクションを処理するアーキテクチャ。

トリガー

トリガーは、ユーザーが Chat UI を使用して Chat 用アプリを呼び出す特定の方法(名前リンクやアプリ コマンドの使用など)です。

次の表に、Chat トリガー、説明、Chat 用アプリの一般的な応答方法を示します。

トリガー 説明 一般的な対応
スペースに追加しました

ユーザーが Chat 用アプリをスペースに追加するか、Google Workspace 管理者が組織内のユーザーのダイレクト メッセージ スペースに Chat 用アプリをインストールします。管理者によってインストールされた Chat 用アプリについて詳しくは、Google Workspace 管理者用ヘルプ ドキュメントの組織に Marketplace アプリをインストールするをご覧ください。

Chat 用アプリは、アプリの機能とスペースのユーザーがアプリを操作する方法を説明するオンボーディング メッセージを送信します。
メッセージ

ユーザーは、次のいずれかの方法でメッセージ内の Chat 用アプリを操作します。

  • Chat 用アプリを使用して、ダイレクト メッセージ(DM)スペースにメッセージを送信します。
  • あらゆる種類のスペースで Chat 用アプリの名前リンクを付ける。
  • リンクのプレビューの URL パターンに一致するリンクを含むメッセージを送信します。
  • selectionInput ウィジェットの複数選択メニューにテキストを入力します。
Chat 用アプリは、メッセージの内容に基づいて応答します。たとえば、Chat 用アプリがメッセージで返信したり、リンクのプレビュー カードを添付したり、複数選択メニューで項目を提案したりします。
スペースから削除しました

ユーザーがスペースから Chat 用アプリを削除した場合、または Google Workspace 管理者が組織内のユーザーの Chat 用アプリをアンインストールした場合。

管理者がインストールした Chat 用アプリをユーザーが削除することはできません。ユーザーが以前に Chat アプリをインストールしていた場合、Google Workspace 管理者がアンインストールしようとしても、Chat アプリはインストールされたままになります。

Chat 用アプリは、スペース用に構成された受信通知を削除し(Webhook の削除など)、内部ストレージをクリアします。Chat 用アプリはスペースのメンバーではなくなったため、このトリガーにメッセージで応答できません。
アプリコマンド

ユーザーが Chat 用アプリのコマンド(スラッシュ コマンド、クイック コマンド、メッセージ アクションなど)を呼び出します。

Chat 用アプリがコマンドに応答します。たとえば、メッセージで応答したり、ダイアログを開いたりします。
アプリのホーム画面

ユーザーが Chat 用アプリとの 1 対 1 のダイレクト メッセージ(DM)スペースで [ホーム] タブを開くか、ホームページ カードのウィジェットを操作します。

Chat 用アプリは、ホームページ カード(pushCard)をプッシュするか、表示されているホームページ カード(updateCard)を更新する RenderActions オブジェクトを返します。

これらのトリガーのエンドポイントまたはコールバック関数は、Google Cloud コンソールの Chat API の [構成] ページで構成します。手順については、Google Chat API を構成するをご覧ください。

スターター プロンプトを設定する

スターター プロンプトは、ユーザーがアプリとの 1 対 1 の空のダイレクト メッセージを開いたときに、Chat 用アプリの機能を見つけるのに役立ちます。スターター プロンプトは最大 3 つまで設定できます。

開始プロンプトを追加して構成するには:

  1. Google Cloud コンソールで、Chat API の [構成] ページに移動します。

    [Chat API の構成] ページに移動

  2. [インタラクティブ機能] で [スターター プロンプト] を見つけて、[プロンプトを追加] をクリックします。

  3. [ランク(1 ~ 3)] フィールドに 1~3 の数値を入力して、表示順序を指定します。

  4. [タイプ選択] で、プロンプトの動作を選択します。

    • テキスト プロンプト: ユーザーがプロンプト チップをクリックすると、入力バーに事前定義されたテキストが入力されます。
    • コマンド プロンプト: クリックすると、登録済みのスラッシュ コマンドまたはクイック コマンドが実行されます。追加の引数を必要とするコマンドは選択できません。
  5. 選択したタイプに基づいてプロンプトを構成します。

    • [テキスト プロンプト] を選択した場合:

      1. [タイトル] に、チップに表示されるプロンプトのタイトルを入力します(半角 30 文字(全角 15 文字)まで)。
      2. [プロンプト テキスト] に、入力バーに表示されるテキストを入力します(最大 60 文字)。
      3. 省略可: 他の言語のユーザー向けにローカライズされたタイトルとテキストを追加します。
      4. [ローカライズされたプロンプト] で、[言語を追加] をクリックします。
      5. [言語] で、プルダウンからサポートされている言語を選択します。
      6. [Localized Title] に、ローカライズされたタイトルを入力します(半角 30 文字(全角 15 文字)まで)。
      7. [ローカライズされたプロンプト テキスト] に、ローカライズされたプロンプト テキスト(最大 60 文字)を入力します。
      8. 必要に応じて、この操作を繰り返して言語を追加します。
    • [コマンド プロンプト] を選択した場合:

      1. [スラッシュ コマンド / クイック コマンド] で、プルダウンからコマンドを選択します。
  6. [完了] をクリックし、ページの下部にある [保存] をクリックします。

サービスへの HTTP 呼び出しの再試行を処理する

サービスへの HTTPS リクエストが失敗した場合(タイムアウト、一時的なネットワーク障害、2xx 以外の HTTPS ステータス コードなど)、Google Chat は数分以内に数回配信を再試行することがあります(ただし、保証されるものではありません)。そのため、特定の状況では、Chat 用アプリが同じイベントを数回受信することがあります。リクエストが正常に完了しても、無効なレスポンス ペイロードが返された場合、Google Chat はリクエストを再試行しません。

イベント オブジェクト

Chat 用アプリは、Chat トリガーが実行されたとき、または Chat ユーザーが Chat 用アプリの UI を操作したとき(ボタンのクリックやダイアログの送信など)にイベント オブジェクトを受け取ります。イベント オブジェクトを使用すると、インタラクション データを使用して応答したり、UI を更新したりできます。

イベント オブジェクトのペイロード

各 Chat イベント オブジェクトには、ホストとプラットフォームの詳細(hostApp: "CHAT"、clientPlatform、userLocale、userTimezone、parameters、formInputs)を含む commonEventObject と、Chat 固有のコンテキストを含む chat オブジェクトが含まれます。

  • アプリホーム トリガー(ユーザーが Chat 用アプリとの 1 対 1 のダイレクト メッセージで [ホーム] タブを開いた場合)の場合、chat オブジェクトには、共用体 payload フィールドなしで chat.user と chat.eventTime が含まれます。ユーザーがホームページ カードのボタンをクリックすると、イベント オブジェクトには commonEventObject.parameters とともに chat.buttonClickedPayload が含まれます(カードにフォーム入力が含まれている場合は commonEventObject.formInputs も含まれます)。
  • スペースとメッセージのインタラクション(スペースに追加、メッセージ、スペースから削除、アプリコマンド、ボタンとウィジェットのインタラクション)の場合、chat オブジェクトには chat.user、chat.space、chat.eventTime、対応するインタラクション ペイロードが含まれます。
    • messagePayload: ユーザーがメッセージを送信したときに space、message、configCompleteRedirectUri を含みます。
    • addedToSpacePayload: Chat 用アプリがスペースに追加されたときに、space、interactionAdd、configCompleteRedirectUri が含まれます。
    • removedFromSpacePayload: Chat 用アプリがスペースから削除されたときに space が含まれます。
    • buttonClickedPayload: ユーザーがカードまたはダイアログのボタンをクリックしたときに、space、message、isDialogEvent、dialogEventType を含みます。
    • widgetUpdatedPayload: ユーザーが外部データソースを含む複数選択メニューへの入力などのウィジェットを操作したときに space を含みます。
    • appCommandPayload: ユーザーがアプリ コマンドを呼び出したときに、space、message、appCommandMetadata、isDialogEvent、dialogEventType、configCompleteRedirectUri を含みます。

Chat や他の Google Workspace アプリケーション内のアドオン イベント オブジェクトについては、イベント オブジェクトをご覧ください。

回答を配信する

このセクションでは、Chat 用アプリがアクションを使用してユーザー操作に同期的に応答する方法について説明します。

アクションで応答するには、Chat 用アプリは 30 秒以内に応答する必要があります。また、応答はやり取りが発生したスペースに適用される必要があります。これらの同期レスポンスには認証は必要ありません。Chat 用アプリで 30 秒以上かかる処理が必要な場合や、スペース外でアクションを実行する必要がある場合は、認証を設定し、Google Chat API を使用して非同期で応答します。

ユーザー操作に同期的に応答するには、Chat 用アプリが受信したイベント オブジェクトを処理し、次のいずれかの JSON オブジェクトを返します。

  • DataActions: chatDataActionMarkup を使用して、チャット メッセージ(CreateMessageAction、UpdateMessageAction)を作成または更新するか、リンクのプレビュー(UpdateInlinePreviewAction)を添付します。
  • RenderActions: ホームページまたはダイアログ(pushCard、updateCard、endNavigation: "CLOSE_DIALOG")を作成、更新、終了するか、複数選択メニュー(modifyCard)の動的な入力候補を提供します。
  • AuthorizationError: 基本的な認証カード(basic_authorization_prompt)でユーザーに外部サービスへのログインまたは認証を求める。

次の表に、Chat 用アプリがアクションで応答する方法を示します。Chat 用アプリは、JSON オブジェクトを直接返すか、Apps Script の AddOnResponseService と CardService を使用してレスポンスを構築できます。

Chat アプリの応答 返す必要があるアクション(JSON) 戻り値に必要なアクション(Apps Script)
メッセージを送信またはメッセージを更新します。 DataActions(createMessageAction または updateMessageAction) DataActionsResponse
Chat ユーザーがスペースで送信したメッセージ内のリンクのプレビュー。 DataActions(updateInlinePreviewAction) DataActionsResponse
ダイレクト メッセージの [ホーム] タブでホームページをレンダリングまたは更新します。 RenderActions(pushCard または updateCard) ActionResponse
ダイアログを開く、更新する、閉じる。 RenderActions(pushCard、updateCard、または endNavigation: "CLOSE_DIALOG") ActionResponse
カードやダイアログから情報を収集するには、ユーザーがマルチセレクト メニューに入力した内容に基づいて選択項目を提案します。 RenderActions(modifyCard) ActionResponse
外部サービスの構成または認可をリクエストします。 AuthorizationError(basic_authorization_prompt) AuthorizationException

メッセージで応答

Chat 用アプリは、次のトリガーまたは操作に対してメッセージで応答できます。

  • ユーザーが Chat 用アプリを @メンションしたり、ダイレクト メッセージを送信したりした場合など、メッセージ トリガー。
  • スペースに追加トリガー。ユーザーが Google Workspace Marketplace から Chat 用アプリをインストールしたり、スペースに追加したりしたときなど。
  • ユーザーがスラッシュ コマンドやクイック コマンドを呼び出したときなど、アプリ コマンド トリガー。
  • メッセージまたはダイアログのカードからのボタンクリック。たとえば、ユーザーが情報を入力して送信をクリックしたときなどです。

Chat 用アプリは、メッセージに次のいずれかを含めることができます。

  • ハイパーリンク、メンション、絵文字を含むテキスト。メッセージの書式を設定するをご覧ください。
  • 1 つ以上のカード。メッセージに表示したり、新しいウィンドウでダイアログとして開いたりできます。Google Chat アプリ用のカードを作成するをご覧ください。
  • 1 つ以上のアクセサリ ウィジェット。メッセージ内のテキストやカードの後に表示されるボタンです。

メッセージで返信するには、CreateMessageAction オブジェクトとともに DataActions を返します。

{
  "hostAppDataAction": {
    "chatDataAction": {
      "createMessageAction": {
        "message": <var>MESSAGE</var>
      }
    }
  }
}

MESSAGE は、Chat API の Message リソースに置き換えます。

次の例では、Chat 用アプリが DataActions で Added to space トリガーに応答することで、スペースに追加されるたびにオンボーディング テキスト メッセージを作成して送信します。

Node.js

/**
 * Sends an onboarding message when the Chat app is added to a space.
 *
 * @param {Object} req The request object from Google Chat.
 * @param {Object} res The response object from the Chat app.
 */
exports.cymbalApp = function cymbalApp(req, res) {
  const chatEvent = req.body.chat;
  // Send an onboarding message when added to a Chat space
  if (chatEvent.addedToSpacePayload) {
    res.json({ hostAppDataAction: { chatDataAction: { createMessageAction: { message: {
      text: 'Hi, Cymbal at your service. I help you manage your calendar ' +
        'from Google Chat. Take a look at your schedule today by typing ' +
        '`/checkCalendar`, or schedule a meeting with `/scheduleMeeting`. ' +
        'To learn what else I can do, type `/help`.'
    }}}}});
  }
};

Python

from flask import Flask, request, json
app = Flask(__name__)

@app.route('/', methods=['POST'])
def cymbal_app():
  """Sends an onboarding message when the Chat app is added to a space.

  Returns:
    Mapping[str, Any]: The response object from the Chat app.
  """
  chat_event = request.get_json()["chat"]
  if "addedToSpacePayload" in chat_event:
    return json.jsonify({ "hostAppDataAction": { "chatDataAction": {
      "createMessageAction": { "message": {
        "text": 'Hi, Cymbal at your service. I help you manage your calendar ' +
        'from Google Chat. Take a look at your schedule today by typing ' +
        '`/checkCalendar`, or schedule a meeting with `/scheduleMeeting`. ' +
        'To learn what else I can do, type `/help`.'
      }}
    }}})

Java

@SpringBootApplication
@RestController
public class App {
  public static void main(String[] args) {
    SpringApplication.run(App.class, args);
  }

  /*
   * Sends an onboarding message when the Chat app is added to a space.
   *
   * @return The response object from the Chat app.
   */
  @PostMapping("/")
  @ResponseBody
  public GenericJson onEvent(@RequestBody JsonNode event) throws Exception {
    JsonNode chatEvent = event.at("/chat");
    if (!chatEvent.at("/addedToSpacePayload").isEmpty()) {
      return new GenericJson() { {
        put("hostAppDataAction", new GenericJson() { {
          put("chatDataAction", new GenericJson() { {
            put("createMessageAction", new GenericJson() { {
              put("message", new Message().setText(
                "Hi, Cymbal at your service. I help you manage your calendar " +
                "from Google Chat. Take a look at your schedule today by typing " +
                "`/checkCalendar`, or schedule a meeting with `/scheduleMeeting`. " +
                "To learn what else I can do, type `/help`."
              ));
            } });
          } });
        } });
      } };
    }
    return new GenericJson();
  }
}

Apps Script

/**
 * Sends an onboarding message when the Chat app is added to a space.
 *
 * @param {Object} event The event object from Google Chat.
 * @return {Object} Response from the Chat app.
 */
function onAddedToSpace(event) {
  return { hostAppDataAction: { chatDataAction: { createMessageAction: { message: {
    text: 'Hi, Cymbal at your service. I help you manage your calendar ' +
          'from Google Chat. Take a look at your schedule today by typing ' +
          '`/checkCalendar`, or schedule a meeting with `/scheduleMeeting`. ' +
          'To learn what else I can do, type `/help`.'
  }}}}};
}

このコードサンプルは、次のテキスト メッセージを返します。

オンボーディング メッセージの例。

メッセージを更新する

Chat 用アプリは、送信したメッセージを更新することもできます。たとえば、Chat 用アプリは、ユーザーがダイアログを送信したり、メッセージ内のカードのボタンをクリックしたりした後に、メッセージを更新できます。

インタラクションに応じて Chat 用アプリのメッセージを更新するには、UpdateMessageAction を含む DataActions を返します。

{
  "hostAppDataAction": {
    "chatDataAction": {
      "updateMessageAction": {
        "message": <var>MESSAGE</var>
      }
    }
  }
}

MESSAGE は、Chat API の Message リソースに置き換えます。

Chat 用アプリは、updateInlinePreviewAction を使用して、ユーザーが送信したメッセージを更新し、リンクのプレビュー カードを添付することもできます。詳しくは、リンクのプレビューをご覧ください。

Google Chat API を使用した非同期応答

Chat 用アプリは、アクションを同期的に返すのではなく、Google Chat API を呼び出してインタラクションに応答したり、プロアクティブなメッセージを送信したりする必要がある場合があります。たとえば、Chat 用アプリは、次のいずれかの操作を行うために Google Chat API を呼び出す必要があります。

  • 30 秒後にインタラクションに応答する(長時間実行されるタスクの完了後など)。
  • スケジュールに基づいてメッセージを送信したり、外部リソースの変更に関する通知を送信したりします。
  • インタラクションが発生したスペース外でタスクを実行する。
  • スペースの一覧表示やスペースへのメンバーの追加など、同期アクションとして利用できないタスクを Chat で実行します。
  • Chat ユーザーに代わってタスクを実行します(ユーザー認証が必要です)。

30 秒後にインタラクションに応答する場合は、Chat 用アプリが応答していないというユーザー向けのエラー メッセージが表示されないように、30 秒以内に空のレスポンスを返してイベント オブジェクトの受信を確認する必要があります。

Node.js

async function onEvent(req, res) {
  // Trigger asynchronous job that will respond using the Google Chat API.
  ...

  // Respond with an empty response to the Google Chat platform.
  return res.send({});
};

Python

def on_event(event) -> dict:
  # Trigger asynchronous job that will respond using the Google Chat API.
  ...

  // Respond with an empty response to the Google Chat platform.
  return {}

Java

public String onEvent(JsonNode event) {
  // Trigger asynchronous job that will respond using the Google Chat API.
  ...

  // Respond with an empty response to the Google Chat platform.
  return "{}";
}

Apps Script

function onEvent(event) {
  // Trigger asynchronous job that will respond using the Google Chat API.
  ...

  // Respond with an empty response to the Google Chat platform.
  return null;
}

Chat API を使用してメッセージを送信するには、認証を設定して spaces.messages.create メソッドを呼び出します。手順については、メッセージを送信するをご覧ください。その他の Chat API メソッドの使用に関するガイドについては、Chat API の概要をご覧ください。

アドオンではない Chat 用アプリ: ユーザー インタラクションを受け取って応答する

Google Workspace アドオンではない Chat 用アプリは、Google Workspace アドオン イベント オブジェクト(EventObject)ではなく、Chat API インタラクション イベント(Event)を受け取り、アクションではなく Message リソースを返して応答します。

アドオンではない Chat 用アプリを Google Workspace アドオン フレームワークにアップグレードするには、Google Chat 用アプリを Google Workspace アドオンに変換するをご覧ください。

操作イベントの種類

ユーザー操作の種類ごとに、Google Chat はアドオンではない Chat 用アプリに、eventType フィールドで表されるタイプの Event オブジェクトを送信します。

ユーザーの操作 eventType アドオンではない Chat 用アプリからの一般的なレスポンス
ユーザーが Chat 用アプリにメッセージを送信します。たとえば、Chat 用アプリの名前リンクを付けたり、スラッシュ コマンドを使用したりします。 MESSAGE Chat 用アプリは、メッセージの内容に基づいて応答します。たとえば、Chat 用アプリは、スラッシュ コマンド /about に対して、Chat 用アプリが実行できるタスクを説明するメッセージで応答します。
ユーザーが Chat 用アプリをスペースに追加します。 ADDED_TO_SPACE Chat 用アプリは、アプリの機能とスペース内のユーザーがアプリを操作する方法を説明するオンボーディング メッセージを送信します。
ユーザーがスペースから Chat 用アプリを削除する。 REMOVED_FROM_SPACE Chat 用アプリは、スペース用に構成された受信通知を削除し(Webhook の削除など)、内部ストレージをクリアします。
ユーザーが Chat 用アプリのメッセージ、ダイアログ、ホームページのカードにあるボタンをクリックします。 CARD_CLICKED Chat 用アプリは、ユーザーが送信したデータを処理して保存するか、別のカードを返します。
ユーザーが 1 対 1 のメッセージで [ホーム] タブをクリックして、Chat 用アプリのホームページを開きます。 APP_HOME Chat 用アプリは、ホームページから静的カードまたはインタラクティブ カードを返します。
ユーザーが Chat 用アプリのホームページからフォームを送信します。 SUBMIT_FORM Chat 用アプリは、ユーザーが送信したデータを処理して保存するか、別のカードを返します。
ユーザーがクイック コマンドを使用してコマンドを呼び出す。 APP_COMMAND Chat 用アプリは、呼び出されたコマンドに基づいて応答します。たとえば、Chat 用アプリは About コマンドに対して、Chat 用アプリで実行できるタスクを説明するメッセージで応答します。

サポートされているすべてのインタラクション イベントと JSON ペイロードの例については、Chat 用アプリのインタラクション イベントのタイプと EventType リファレンス ドキュメントをご覧ください。

ダイアログからのインタラクション イベント

アドオンではない Chat 用アプリがダイアログを開くと、インタラクション イベントには、レスポンスの処理に使用できる次の追加情報が含まれます。

  • isDialogEvent フィールドは true に設定されています。
  • DialogEventType(REQUEST_DIALOG、SUBMIT_DIALOG、CANCEL_DIALOG)は、インタラクションによってダイアログが開くか、ダイアログから情報が送信されるか、ダイアログが閉じられるかを明確にします。

アドオンではない Chat 用アプリがインタラクション イベントを受け取るように構成する

  1. Google Cloud コンソールで、Chat API の [構成] ページに移動します。

    [Chat API の構成] ページに移動

  2. [インタラクティブ機能] で、[この Chat 用アプリを Google Workspace アドオンとしてビルドする] のチェックを外し、[機能]、単一の [接続設定] エンドポイント(HTTP エンドポイント URL、Apps Script、Cloud Pub/Sub トピック名、Dialogflow)、[コマンド]、[スターター プロンプト]、[リンクのプレビュー]、[公開設定] を構成します。

  3. [保存] をクリックします。

アドオンではない Chat 用アプリでメッセージを返信する

アドオンではない Chat 用アプリで同期的に応答するには、Message オブジェクトを直接返します。次の例では、ADDED_TO_SPACE インタラクション イベントにテキスト メッセージで応答しています。

Node.js

/**
 * Sends an onboarding message when the Chat app is added to a space.
 *
 * @param {Object} req The event object from Chat API.
 * @param {Object} res The response object from the Chat app.
 */
exports.cymbalApp = function cymbalApp(req, res) {
  // Send an onboarding message when added to a Chat space
  if (req.body.type === 'ADDED_TO_SPACE') {
    res.json({
      'text': 'Hi, Cymbal at your service. I help you manage your calendar ' +
        'from Google Chat. Take a look at your schedule today by typing ' +
        '`/checkCalendar`, or schedule a meeting with `/scheduleMeeting`. To ' +
        'learn what else I can do, type `/help`.'
    });
  }
};

Python

from flask import Flask, request, json
app = Flask(__name__)

@app.route('/', methods=['POST'])
def cymbal_app():
  """Sends an onboarding message when the Chat app is added to a space.

  Returns:
    Mapping[str, Any]: The response object from the Chat app.
  """
  event = request.get_json()
  if event['type'] == 'ADDED_TO_SPACE':
    return json.jsonify({
      'text': 'Hi, Cymbal at your service. I help you manage your calendar ' +
      'from Google Chat. Take a look at your schedule today by typing ' +
      '`/checkCalendar`, or schedule a meeting with `/scheduleMeeting`. To ' +
      'learn what else I can do, type `/help`.'
    })
  return json.jsonify({})

Java

@SpringBootApplication
@RestController
public class App {
  public static void main(String[] args) {
    SpringApplication.run(App.class, args);
  }

  /*
   * Sends an onboarding message when the Chat app is added to a space.
   *
   * @return The response object from the Chat app.
   */
  @PostMapping("/")
  @ResponseBody
  public Message onEvent(@RequestBody JsonNode event) {
    switch (event.get("type").asText()) {
      case "ADDED_TO_SPACE":
        return new Message().setText(
          "Hi, Cymbal at your service. I help you manage your calendar " +
          "from Google Chat. Take a look at your schedule today by typing " +
          "`/checkCalendar`, or schedule a meeting with `/scheduleMeeting`. " +
          "To learn what else I can do, type `/help`.");
      default:
        return new Message();
    }
  }
}

Apps Script

/**
 * Sends an onboarding message when the Chat app is added to a space.
 *
 * @param {Object} event The event object from Chat API.
 * @return {Object} Response from the Chat app.
 */
function onAddToSpace(event) {
  return {
    'text': 'Hi, Cymbal at your service. I help you manage your calendar ' +
      'from Google Chat. Take a look at your schedule today by typing ' +
      '`/checkCalendar`, or schedule a meeting with `/scheduleMeeting`. To learn ' +
      'what else I can do, type `/help`.'
  };
}