Create and update interactive cards (original) (raw)

Skip to main content

Create and update interactive cards

This guide explains how to use the Google Chat API to create messages that contain interactive cards on behalf of users, and how to update those cards asynchronously.

Creating and updating cards is useful when you want to do the following:

Outside the Developer Preview Program, messages created with user authentication can only contain text.

Prerequisites

Node.js

Python

Java

Apps Script

Create an API key to access Developer Preview features

To call a Developer Preview API method, you must use a non-public developer preview version of the API discovery document. To authenticate the request, you must pass an API key.

To create the API Key, open your app's Google Cloud project and do the following:

  1. In the Google Cloud console, go to Menu > APIs & Services > Credentials.
    Go to Credentials
  2. Click Create credentials > API key.
  3. Your new API key is displayed.
    • Click Copy to copy your API key for use in your app's code. The API key can also be found in the "API Keys" section of your project's credentials.
    • To prevent unauthorized use, we recommend restricting where and for which APIs the API key can be used. For more details, seeAdd API restrictions.

Create a card message on behalf of a user

To create a message with cards on behalf of a user, useuser authentication.

To create the message, specify the following in your request:

The following example shows how to create a message with a card on behalf of a user:

Node.js

/**
 * This sample shows how to create a message with a card on behalf of a user.
 */
const {google} = require('googleapis');
const {auth} = require('google-auth-library');

async function main() {
  // Create a client
  const authClient = await auth.getClient({
    scopes: ['https://www.googleapis.com/auth/chat.messages.create']
  });
  google.options({auth: authClient});

  // Initialize the Chat API with Developer Preview labels
  const chat = await google.discoverAPI(
    'https://chat.googleapis.com/$discovery/rest?version=v1&labels=DEVELOPER_PREVIEW&key=API_KEY'
  );

  // The space to create the message in.
  const parent = 'spaces/SPACE_NAME';

  // Create the request
  const request = {
    parent: parent,
    requestBody: {
      text: 'Here is a card created on my behalf:',
      cardsV2: [{
        cardId: 'unique-card-id',
        card: {
          header: {
            title: 'Card Title',
            subtitle: 'Card Subtitle'
          },
          sections: [{
            widgets: [{
              textParagraph: {
                text: 'This card is attached to a user message.'
              }
            }]
          }]
        }
      }]
    }
  };

  // Call the API
  const response = await chat.spaces.messages.create(request);

  // Handle the response
  console.log(response.data);
}

main().catch(console.error);

Python

"""
This sample shows how to create a message with a card on behalf of a user.
"""
from google.oauth2 import service_account
from googleapiclient.discovery import build
import google.auth

def create_message_with_card():
    # Create a client
    scopes = ["https://www.googleapis.com/auth/chat.messages.create"]
    credentials, _ = google.auth.default(scopes=scopes)

    # Build the service endpoint for Chat API with Developer Preview labels.
    service = build(
        'chat',
        'v1',
        credentials=credentials,
        discoveryServiceUrl='https://chat.googleapis.com/$discovery/rest?version=v1&labels=DEVELOPER_PREVIEW&key=API_KEY'
    )

    # The space to create the message in.
    parent = "spaces/SPACE_NAME"

    # Create the request
    result = service.spaces().messages().create(
        parent=parent,
        body={
            'text': 'Here is a card created on my behalf:',
            'cardsV2': [{
                'cardId': 'unique-card-id',
                'card': {
                    'header': {
                        'title': 'Card Title',
                        'subtitle': 'Card Subtitle'
                    },
                    'sections': [{
                        'widgets': [{
                            'textParagraph': {
                                'text': 'This card is attached to a user message.'
                            }
                        }]
                    }]
                }
            }]
        }
    ).execute()

    print(result)

if __name__ == "__main__":
    create_message_with_card()

Java

/**
 * This sample shows how to create a message with a card on behalf of a user.
 */
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.GenericUrl;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpRequestFactory;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.json.JsonHttpContent;
import com.google.api.client.json.gson.GsonFactory;
import com.google.auth.http.HttpCredentialsAdapter;
import com.google.auth.oauth2.GoogleCredentials;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

public class CreateMessageWithCard {
  public static void main(String[] args) throws Exception {
    HttpTransport transport = GoogleNetHttpTransport.newTrustedTransport();
    GsonFactory jsonFactory = GsonFactory.getDefaultInstance();

    GoogleCredentials credentials = GoogleCredentials.getApplicationDefault()
        .createScoped(Arrays.asList("https://www.googleapis.com/auth/chat.messages.create"));
    HttpRequestFactory requestFactory = transport.createRequestFactory(new HttpCredentialsAdapter(credentials));

    String parent = "spaces/SPACE_NAME";
    GenericUrl url = new GenericUrl("https://chat.googleapis.com/v1/" + parent + "/messages");

    // Construct the message body
    Map<String, Object> message = new HashMap<>();
    message.put("text", "Here is a card created on my behalf:");

    Map<String, Object> header = new HashMap<>();
    header.put("title", "Card Title");
    header.put("subtitle", "Card Subtitle");

    Map<String, Object> textParagraph = new HashMap<>();
    textParagraph.put("text", "This card is attached to a user message.");

    Map<String, Object> widget = new HashMap<>();
    widget.put("textParagraph", textParagraph);

    Map<String, Object> section = new HashMap<>();
    section.put("widgets", Collections.singletonList(widget));

    Map<String, Object> card = new HashMap<>();
    card.put("header", header);
    card.put("sections", Collections.singletonList(section));

    Map<String, Object> cardWithId = new HashMap<>();
    cardWithId.put("cardId", "unique-card-id");
    cardWithId.put("card", card);

    message.put("cardsV2", Collections.singletonList(cardWithId));

    HttpRequest request = requestFactory.buildPostRequest(url, new JsonHttpContent(jsonFactory, message));
    System.out.println(request.execute().parseAsString());
  }
}

Apps Script

/**
 * This sample shows how to create a message with a card on behalf of a user.
 */
function createMessageWithCard() {
  const parent = 'spaces/SPACE_NAME';
  const url = `https://chat.googleapis.com/v1/${parent}/messages`;

  const message = {
    text: 'Here is a card created on my behalf:',
    cardsV2: [{
      cardId: 'unique-card-id',
      card: {
        header: {
          title: 'Card Title',
          subtitle: 'Card Subtitle'
        },
        sections: [{
          widgets: [{
            textParagraph: {
              text: 'This card is attached to a user message.'
            }
          }]
        }]
      }
    }]
  };

  const options = {
    method: 'post',
    headers: {
      Authorization: 'Bearer ' + ScriptApp.getOAuthToken()
    },
    contentType: 'application/json',
    payload: JSON.stringify(message),
    muteHttpExceptions: true
  };

  try {
    const response = UrlFetchApp.fetch(url, options);
    console.log(response.getContentText());
  } catch (err) {
    console.log('Failed to create message: ' + err.message);
  }
}

Update cards asynchronously

After creating a message with cards, you can update the cards asynchronously usingapp authentication. This allows your app to refresh the card content without requiring user interaction. Only the Chat app that added the card to the user's message can replace it. If a user edits the message text, the app-owned cards are removed, and your app can no longer update them.

To update the cards, call the replaceCards method with the following:

The following example shows how to update the cards of a message:

Node.js

/**
 * This sample shows how to update cards on a message.
 */
const {google} = require('googleapis');
const {auth} = require('google-auth-library');

async function main() {
  // Create a client with app credentials
  const authClient = await auth.getClient({
    scopes: ['https://www.googleapis.com/auth/chat.bot']
  });
  google.options({auth: authClient});

  // Initialize the Chat API with Developer Preview labels
  const chat = await google.discoverAPI(
    'https://chat.googleapis.com/$discovery/rest?version=v1&labels=DEVELOPER_PREVIEW&key=API_KEY'
  );

  // The message to update.
  const messageName = 'spaces/SPACE_NAME/messages/MESSAGE_ID';

  // Create the request
  const request = {
    name: messageName,
    requestBody: {
      cardsV2: [{
        cardId: 'unique-card-id',
        card: {
          header: {
            title: 'Updated Card Title',
            subtitle: 'Updated Card Subtitle'
          },
          sections: [{
            widgets: [{
              textParagraph: {
                text: 'The card content has been updated asynchronously.'
              }
            }]
          }]
        }
      }]
    }
  };

  // Call the API
  await chat.spaces.messages.replaceCards(request);
  console.log('Cards updated.');
}

main().catch(console.error);

Python

"""
This sample shows how to update cards on a message.
"""
from google.oauth2 import service_account
from googleapiclient.discovery import build
import google.auth

def replace_message_cards():
    # Create a client with app credentials
    scopes = ["https://www.googleapis.com/auth/chat.bot"]
    credentials, _ = google.auth.default(scopes=scopes)

    # Build the service endpoint for Chat API with Developer Preview labels.
    service = build(
        'chat',
        'v1',
        credentials=credentials,
        discoveryServiceUrl='https://chat.googleapis.com/$discovery/rest?version=v1&labels=DEVELOPER_PREVIEW&key=API_KEY'
    )

    # The message to update.
    message_name = "spaces/SPACE_NAME/messages/MESSAGE_ID"

    # Create the request
    result = service.spaces().messages().replaceCards(
        name=message_name,
        body={
            'cardsV2': [{
                'cardId': 'unique-card-id',
                'card': {
                    'header': {
                        'title': 'Updated Card Title',
                        'subtitle': 'Updated Card Subtitle'
                    },
                    'sections': [{
                        'widgets': [{
                            'textParagraph': {
                                'text': 'The card content has been updated asynchronously.'
                            }
                        }]
                    }]
                }
            }]
        }
    ).execute()

    print("Cards updated.")

if __name__ == "__main__":
    replace_message_cards()

Java

/**
 * This sample shows how to update cards on a message.
 */
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.GenericUrl;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpRequestFactory;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.json.JsonHttpContent;
import com.google.api.client.json.gson.GsonFactory;
import com.google.auth.http.HttpCredentialsAdapter;
import com.google.auth.oauth2.GoogleCredentials;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

public class ReplaceMessageCards {
  public static void main(String[] args) throws Exception {
    HttpTransport transport = GoogleNetHttpTransport.newTrustedTransport();
    GsonFactory jsonFactory = GsonFactory.getDefaultInstance();

    GoogleCredentials credentials = GoogleCredentials.getApplicationDefault()
        .createScoped(Arrays.asList("https://www.googleapis.com/auth/chat.bot"));
    HttpRequestFactory requestFactory = transport.createRequestFactory(new HttpCredentialsAdapter(credentials));

    String messageName = "spaces/SPACE_NAME/messages/MESSAGE_ID";
    GenericUrl url = new GenericUrl("https://chat.googleapis.com/v1/" + messageName + ":replaceCards");

    // Construct the body
    Map<String, Object> header = new HashMap<>();
    header.put("title", "Updated Card Title");
    header.put("subtitle", "Updated Card Subtitle");

    Map<String, Object> textParagraph = new HashMap<>();
    textParagraph.put("text", "The card content has been updated asynchronously.");

    Map<String, Object> widget = new HashMap<>();
    widget.put("textParagraph", textParagraph);

    Map<String, Object> section = new HashMap<>();
    section.put("widgets", Collections.singletonList(widget));

    Map<String, Object> card = new HashMap<>();
    card.put("header", header);
    card.put("sections", Collections.singletonList(section));

    Map<String, Object> cardWithId = new HashMap<>();
    cardWithId.put("cardId", "unique-card-id");
    cardWithId.put("card", card);

    Map<String, Object> body = new HashMap<>();
    body.put("cardsV2", Collections.singletonList(cardWithId));

    HttpRequest request = requestFactory.buildPostRequest(url, new JsonHttpContent(jsonFactory, body));
    request.execute();
    System.out.println("Cards updated.");
  }
}

Apps Script

/**
 * This sample shows how to update cards on a message.
 */
function replaceMessageCards() {
  const messageName = 'spaces/SPACE_NAME/messages/MESSAGE_ID';
  const url = `https://chat.googleapis.com/v1/${messageName}:replaceCards`;

  const request = {
    cardsV2: [{
      cardId: 'unique-card-id',
      card: {
        header: {
          title: 'Updated Card Title',
          subtitle: 'Updated Card Subtitle'
        },
        sections: [{
          widgets: [{
            textParagraph: {
              text: 'The card content has been updated asynchronously.'
            }
          }]
        }]
      }
    }]
  };

  const options = {
    method: 'post',
    headers: {
      Authorization: 'Bearer ' + ScriptApp.getOAuthToken()
    },
    contentType: 'application/json',
    payload: JSON.stringify(request),
    muteHttpExceptions: true
  };

  try {
    const response = UrlFetchApp.fetch(url, options);
    console.log('Cards updated.');
  } catch (err) {
    console.log('Failed to update cards: ' + err.message);
  }
}

Limitations

Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 4.0 License, and code samples are licensed under the Apache 2.0 License. For details, see the Google Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.

Last updated 2026-04-01 UTC.