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:

  • Post a card that represents a task or external resource on behalf of a user.
  • Update the status of the card (for example, "In Progress" to "Completed") based on external events, without waiting for a user interaction.
  • Refresh the content of a card on a user message, such as a link preview.

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, see Add API restrictions.

Create a card message on behalf of a user

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

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

  • The chat.messages.create or chat.messages authorization scope.
  • The cardsV2 field in the Message resource, containing the card data.
  • The cardId for each card, which is required for asynchronous updates.

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');
asyncfunctionmain(){
// Create a client
constauthClient=awaitauth.getClient({
scopes:['https://www.googleapis.com/auth/chat.messages.create']
});
google.options({auth:authClient});
// Initialize the Chat API with Developer Preview labels
constchat=awaitgoogle.discoverAPI(
'https://chat.googleapis.com/$discovery/rest?version=v1&labels=DEVELOPER_PREVIEW&key=API_KEY'
);
// The space to create the message in.
constparent='spaces/SPACE_NAME';
// Create the request
constrequest={
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
constresponse=awaitchat.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.
"""
fromgoogle.oauth2import service_account
fromgoogleapiclient.discoveryimport build
importgoogle.auth
defcreate_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.
 */
importcom.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
importcom.google.api.client.http.GenericUrl;
importcom.google.api.client.http.HttpRequest;
importcom.google.api.client.http.HttpRequestFactory;
importcom.google.api.client.http.HttpTransport;
importcom.google.api.client.http.json.JsonHttpContent;
importcom.google.api.client.json.gson.GsonFactory;
importcom.google.auth.http.HttpCredentialsAdapter;
importcom.google.auth.oauth2.GoogleCredentials;
importjava.util.Arrays;
importjava.util.Collections;
importjava.util.HashMap;
importjava.util.Map;
publicclass CreateMessageWithCard{
publicstaticvoidmain(String[]args)throwsException{
HttpTransporttransport=GoogleNetHttpTransport.newTrustedTransport();
GsonFactoryjsonFactory=GsonFactory.getDefaultInstance();
GoogleCredentialscredentials=GoogleCredentials.getApplicationDefault()
.createScoped(Arrays.asList("https://www.googleapis.com/auth/chat.messages.create"));
HttpRequestFactoryrequestFactory=transport.createRequestFactory(newHttpCredentialsAdapter(credentials));
Stringparent="spaces/SPACE_NAME";
GenericUrlurl=newGenericUrl("https://chat.googleapis.com/v1/"+parent+"/messages");
// Construct the message body
Map<String,Object>message=newHashMap<>();
message.put("text","Here is a card created on my behalf:");
Map<String,Object>header=newHashMap<>();
header.put("title","Card Title");
header.put("subtitle","Card Subtitle");
Map<String,Object>textParagraph=newHashMap<>();
textParagraph.put("text","This card is attached to a user message.");
Map<String,Object>widget=newHashMap<>();
widget.put("textParagraph",textParagraph);
Map<String,Object>section=newHashMap<>();
section.put("widgets",Collections.singletonList(widget));
Map<String,Object>card=newHashMap<>();
card.put("header",header);
card.put("sections",Collections.singletonList(section));
Map<String,Object>cardWithId=newHashMap<>();
cardWithId.put("cardId","unique-card-id");
cardWithId.put("card",card);
message.put("cardsV2",Collections.singletonList(cardWithId));
HttpRequestrequest=requestFactory.buildPostRequest(url,newJsonHttpContent(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.
 */
functioncreateMessageWithCard(){
constparent='spaces/SPACE_NAME';
consturl=`https://chat.googleapis.com/v1/${parent}/messages`;
constmessage={
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.'
}
}]
}]
}
}]
};
constoptions={
method:'post',
headers:{
Authorization:'Bearer '+ScriptApp.getOAuthToken()
},
contentType:'application/json',
payload:JSON.stringify(message),
muteHttpExceptions:true
};
try{
constresponse=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 using app 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 chat.bot authorization scope.
  • The name of the message to update.
  • The new cardsV2 list. This replaces all existing cards in the message. If you provide an empty list, the cards are removed.

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');
asyncfunctionmain(){
// Create a client with app credentials
constauthClient=awaitauth.getClient({
scopes:['https://www.googleapis.com/auth/chat.bot']
});
google.options({auth:authClient});
// Initialize the Chat API with Developer Preview labels
constchat=awaitgoogle.discoverAPI(
'https://chat.googleapis.com/$discovery/rest?version=v1&labels=DEVELOPER_PREVIEW&key=API_KEY'
);
// The message to update.
constmessageName='spaces/SPACE_NAME/messages/MESSAGE_ID';
// Create the request
constrequest={
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
awaitchat.spaces.messages.replaceCards(request);
console.log('Cards updated.');
}
main().catch(console.error);

Python

"""
This sample shows how to update cards on a message.
"""
fromgoogle.oauth2import service_account
fromgoogleapiclient.discoveryimport build
importgoogle.auth
defreplace_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.
 */
importcom.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
importcom.google.api.client.http.GenericUrl;
importcom.google.api.client.http.HttpRequest;
importcom.google.api.client.http.HttpRequestFactory;
importcom.google.api.client.http.HttpTransport;
importcom.google.api.client.http.json.JsonHttpContent;
importcom.google.api.client.json.gson.GsonFactory;
importcom.google.auth.http.HttpCredentialsAdapter;
importcom.google.auth.oauth2.GoogleCredentials;
importjava.util.Arrays;
importjava.util.Collections;
importjava.util.HashMap;
importjava.util.Map;
publicclass ReplaceMessageCards{
publicstaticvoidmain(String[]args)throwsException{
HttpTransporttransport=GoogleNetHttpTransport.newTrustedTransport();
GsonFactoryjsonFactory=GsonFactory.getDefaultInstance();
GoogleCredentialscredentials=GoogleCredentials.getApplicationDefault()
.createScoped(Arrays.asList("https://www.googleapis.com/auth/chat.bot"));
HttpRequestFactoryrequestFactory=transport.createRequestFactory(newHttpCredentialsAdapter(credentials));
StringmessageName="spaces/SPACE_NAME/messages/MESSAGE_ID";
GenericUrlurl=newGenericUrl("https://chat.googleapis.com/v1/"+messageName+":replaceCards");
// Construct the body
Map<String,Object>header=newHashMap<>();
header.put("title","Updated Card Title");
header.put("subtitle","Updated Card Subtitle");
Map<String,Object>textParagraph=newHashMap<>();
textParagraph.put("text","The card content has been updated asynchronously.");
Map<String,Object>widget=newHashMap<>();
widget.put("textParagraph",textParagraph);
Map<String,Object>section=newHashMap<>();
section.put("widgets",Collections.singletonList(widget));
Map<String,Object>card=newHashMap<>();
card.put("header",header);
card.put("sections",Collections.singletonList(section));
Map<String,Object>cardWithId=newHashMap<>();
cardWithId.put("cardId","unique-card-id");
cardWithId.put("card",card);
Map<String,Object>body=newHashMap<>();
body.put("cardsV2",Collections.singletonList(cardWithId));
HttpRequestrequest=requestFactory.buildPostRequest(url,newJsonHttpContent(jsonFactory,body));
request.execute();
System.out.println("Cards updated.");
}
}

Apps Script

/**
 * This sample shows how to update cards on a message.
 */
functionreplaceMessageCards(){
constmessageName='spaces/SPACE_NAME/messages/MESSAGE_ID';
consturl=`https://chat.googleapis.com/v1/${messageName}:replaceCards`;
constrequest={
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.'
}
}]
}]
}
}]
};
constoptions={
method:'post',
headers:{
Authorization:'Bearer '+ScriptApp.getOAuthToken()
},
contentType:'application/json',
payload:JSON.stringify(request),
muteHttpExceptions:true
};
try{
constresponse=UrlFetchApp.fetch(url,options);
console.log('Cards updated.');
}catch(err){
console.log('Failed to update cards: '+err.message);
}
}

Limitations

  • When creating messages with cards on behalf of a user or updating cards, the Chat app must be a member of the space. This requirement applies when:

    This requirement is different from other APIs that use user authentication, which typically don't require the app to be a member of the space.

  • The replaceCards method supports card replacement and removal, and you can add additional cards while replacing them, but you can't add cards to a message that doesn't already have cards.

  • The Chat app can only replace cards that it attached to a message, not cards that other Chat apps attached.

  • If a user edits the message text, the Chat app-owned cards are removed, and you can no longer update them.

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年07月22日 UTC.