Back to Communication & Collaboration

google-chat-api

Google ChatAPI integrationchatbotswebhooksCloudflare Workersworkflow automationmessagingAI agent
⭐ 860πŸ“„ MITπŸ•’ 2026-06-11Source β†—

Install this skill

npx skills add jezweb/claude-skills

Works across Claude Code, Cursor, Codex, Copilot & Antigravity

The google-chat-api skill enables developers to integrate Google Chat spaces with external systems using either simple webhook notifications or fully interactive bots. It supports the modern Cards v2 schema, ensuring interface components like buttons, input fields, and date pickers align with current Google design standards. For basic status updates, incoming webhooks offer a direct, zero-auth integration path. For sophisticated requirements, the HTTP endpoint approach allows bots to respond to user actions with dynamic content rendered via HTML or Markdown. The implementation environment typically involves Cloudflare Workers, requiring strict adherence to Google's JSON schema definitions and response timeout constraints. This skill is essential for automating team alerts, building workflow-based interactive forms, or bridging service monitoring systems directly into organizational communication channels.

When to Use This Skill

  • β€’Automating deployment notifications from CI/CD pipelines to team spaces
  • β€’Creating interactive helpdesk ticketing workflows directly inside chat
  • β€’Syncing status updates from server monitoring tools to incident response rooms
  • β€’Building administrative tools that trigger tasks based on user button selection

How to Invoke This Skill

Example prompts that trigger this skill in Claude Code, Cursor, or Antigravity:

  • β€œsend a notification to our team chat space
  • β€œcreate an interactive bot for google chat
  • β€œhow do I format a card message for google chat
  • β€œset up a webhook for automated chat alerts
  • β€œdeploy a cloudflare worker for a google chat bot

Pro Tips

  • πŸ’‘For interactive bots, always use Cloudflare Workers or similar serverless functions for efficient, scalable event processing and rapid responses.
  • πŸ’‘Start with webhook integrations for simple outgoing messages; it drastically reduces setup complexity for basic notifications.
  • πŸ’‘Design rich, interactive cards (Cards v2) instead of plain text messages to enhance user experience and facilitate structured input.

What this skill does

  • β€’Send automated messages to specific chat spaces via incoming webhooks
  • β€’Develop interactive bots that process user input and button clicks
  • β€’Construct complex UI layouts using the Cards v2 widget schema
  • β€’Support rich text and code blocks through HTML or Markdown formatting
  • β€’Verify secure bearer tokens for authenticated HTTP endpoint communication

When not to use it

  • βœ•When you require an AI assistant with persistent long-term memory
  • βœ•When your task involves direct manipulation of Google Drive or Workspace files outside the chat context

Example workflow

  1. Register a new chat app in the Google Cloud Console
  2. Configure an HTTP endpoint URL pointing to your Cloudflare Worker
  3. Implement the event listener to receive incoming JSON payloads
  4. Format the response using the Cards v2 structure with button widgets
  5. Handle the button click action within the required 30-second window
  6. Verify the sender using the Google system account bearer token

Prerequisites

  • –Active Google Cloud Project
  • –Enabled Google Chat API
  • –Cloudflare account for hosting the endpoint
  • –Existing Google Chat space with management permissions

Pitfalls & limitations

  • !Ignoring the 30-second response timeout which triggers bot failure
  • !Using deprecated Cards v1 formatting which will not render correctly
  • !Failing to handle the system-signed bearer token, leaving your endpoint vulnerable

FAQ

What is the difference between an incoming webhook and an interactive bot?
Incoming webhooks are one-way notification pipelines that require no coding. Interactive bots allow for two-way communication, enabling user inputs, buttons, and complex interface responses.
Are there limitations to the response format?
Yes, you must strictly follow the Cards v2 JSON schema. An incorrect field or invalid nesting will prevent the message from rendering in the chat client.
Can I use Markdown in my messages?
Yes, Google Chat supports both Markdown and HTML within card widgets, making it easier to render formatted lists, bold text, and code blocks.

How it compares

Unlike manual message pasting, this skill programmatically ensures that notifications are structured, interactive, and verifiable by the Google ecosystem.

Source & trust

⭐ 860 starsπŸ“„ MITπŸ•’ Updated 2026-06-11
πŸ“„ Full skill instructions β€” original source: jezweb/claude-skills
# Google Chat API

**Status**: Production Ready
**Last Updated**: 2026-01-09 (Added: Spaces API, Members API, Reactions API, Rate Limits)
**Dependencies**: Cloudflare Workers (recommended), Web Crypto API for token verification
**Latest Versions**: Google Chat API v1 (stable), Cards v2 (Cards v1 deprecated), [email protected]

---

## Quick Start (5 Minutes)

### 1. Create Webhook (Simplest Approach)

# No code needed - just configure in Google Chat
# 1. Go to Google Cloud Console
# 2. Create new project or select existing
# 3. Enable Google Chat API
# 4. Configure Chat app with webhook URL


**Webhook URL**: https://your-worker.workers.dev/webhook

**Why this matters:**
- Simplest way to send messages to Chat
- No authentication required for incoming webhooks
- Perfect for notifications from external systems
- Limited to sending messages (no interactive responses)

### 2. Create Interactive Bot (Cloudflare Worker)

export default {
async fetch(request: Request, env: Env): Promise<Response> {
const event = await request.json()

// Respond with a card
return Response.json({
text: "Hello from bot!",
cardsV2: [{
cardId: "unique-card-1",
card: {
header: { title: "Welcome" },
sections: [{
widgets: [{
textParagraph: { text: "Click the button below" }
}, {
buttonList: {
buttons: [{
text: "Click me",
onClick: {
action: {
function: "handleClick",
parameters: [{ key: "data", value: "test" }]
}
}
}]
}
}]
}]
}
}]
})
}
}


**CRITICAL:**
- **Must respond within timeout** (typically 30 seconds)
- **Always return valid JSON** with cardsV2 array
- **Card schema must be exact** - one wrong field breaks the whole card

### 3. Verify Bearer Tokens (Production Security)

async function verifyToken(token: string): Promise<boolean> {
// Verify token is signed by [email protected]
// See templates/bearer-token-verify.ts for full implementation
return true
}


**Why this matters:**
- Prevents unauthorized access to your bot
- Required for HTTP endpoints (not webhooks)
- Uses Web Crypto API (Cloudflare Workers compatible)

---

## The 3-Step Setup Process

### Step 1: Choose Integration Type

**Option A: Incoming Webhook (Notifications Only)**

Best for:
- CI/CD notifications
- Alert systems
- One-way communication
- External service β†’ Chat

**Setup**:
1. Create Chat space
2. Configure incoming webhook in Space settings
3. POST JSON to webhook URL

**No code required** - just HTTP POST:
curl -X POST 'https://chat.googleapis.com/v1/spaces/.../messages?key=...' \
-H 'Content-Type: application/json' \
-d '{"text": "Hello from webhook!"}'


**Option B: HTTP Endpoint Bot (Interactive)**

Best for:
- Interactive forms
- Button-based workflows
- User input collection
- Chat β†’ Your service β†’ Chat

**Setup**:
1. Create Google Cloud project
2. Enable Chat API
3. Configure Chat app with HTTP endpoint
4. Deploy Cloudflare Worker
5. Handle events and respond with cards

**Requires code** - see templates/interactive-bot.ts

### Step 2: Design Cards (If Using Interactive Bot)

**IMPORTANT**: Use Cards v2 only. Cards v1 was deprecated in 2025. Cards v2 matches Material Design on web (faster rendering, better aesthetics).

Cards v2 structure:
{
"cardsV2": [{
"cardId": "unique-id",
"card": {
"header": {
"title": "Card Title",
"subtitle": "Optional subtitle",
"imageUrl": "https://..."
},
"sections": [{
"header": "Section 1",
"widgets": [
{ "textParagraph": { "text": "Some text" } },
{ "buttonList": { "buttons": [...] } }
]
}]
}
}]
}


**Widget Types**:
- textParagraph - Text content
- buttonList - Buttons (text or icon)
- textInput - Text input field
- selectionInput - Dropdowns, checkboxes, switches
- dateTimePicker - Date/time selection
- divider - Horizontal line
- image - Images
- decoratedText - Text with icon/button

**Text Formatting** (NEW: Sept 2025 - GA):

Cards v2 supports both HTML and Markdown formatting:

// HTML formatting (traditional)
{
textParagraph: {
text: "This is <b>bold</b> and <i>italic</i> text with <font color='#ea9999'>color</font>"
}
}

// Markdown formatting (NEW - better for AI agents)
{
textParagraph: {
text: "This is **bold** and *italic* text\n\n- Bullet list\n- Second item\n\n
\ncode block\n``"
}
}
**Supported Markdown** (text messages and cards):
-
**bold** or *italic*
-
code for inline code
-
- list item or 1. ordered for lists
-
code block`` for multi-line code
- ~strikethrough~

**Supported HTML** (cards only):
- <b>bold</b>, <i>italic</i>, <u>underline</u>
- <font color="#FF0000">colored</font>
- <a href="url">link</a>

**Why Markdown matters**: LLMs naturally output Markdown. Before Sept 2025, you had to convert Markdown→HTML. Now you can pass Markdown directly to Chat.

**CRITICAL**:
- **Max 100 widgets per card** - silently truncated if exceeded
- **Widget order matters** - displayed top to bottom
- **cardId must be unique** - use timestamp or UUID

### Step 3: Handle User Interactions

When user clicks button or submits form:

export default {
async fetch(request: Request): Promise<Response> {
const event = await request.json()

// Check event type
if (event.type === 'MESSAGE') {
// User sent message
return handleMessage(event)
}

if (event.type === 'CARD_CLICKED') {
// User clicked button
const action = event.action.actionMethodName
const params = event.action.parameters

if (action === 'submitForm') {
return handleFormSubmission(event)
}
}

return Response.json({ text: "Unknown event" })
}
}


**Event Types**:
- ADDED_TO_SPACE - Bot added to space
- REMOVED_FROM_SPACE - Bot removed
- MESSAGE - User sent message
- CARD_CLICKED - User clicked button/submitted form

---

## Critical Rules

### Always Do

βœ… Return valid JSON with cardsV2 array structure
βœ… Set unique cardId for each card
βœ… Verify bearer tokens for HTTP endpoints (production)
βœ… Handle all event types (MESSAGE, CARD_CLICKED, etc.)
βœ… Keep widget count under 100 per card
βœ… Validate form inputs server-side

### Never Do

❌ Store secrets in code (use Cloudflare Workers secrets)
❌ Exceed 100 widgets per card (silently fails)
❌ Return malformed JSON (breaks entire message)
❌ Skip bearer token verification (security risk)
❌ Trust client-side validation only (validate server-side)
❌ Use synchronous blocking operations (timeout risk)

---

## Known Issues Prevention

This skill prevents **6** documented issues:

### Issue #1: Bearer Token Verification Fails (401)
**Error**: "Unauthorized" or "Invalid credentials"
**Source**: Google Chat API Documentation
**Why It Happens**: Token not verified or wrong verification method
**Prevention**: Template includes Web Crypto API verification (Cloudflare Workers compatible)

### Issue #2: Invalid Card JSON Schema (400)
**Error**: "Invalid JSON payload" or "Unknown field"
**Source**: Cards v2 API Reference
**Why It Happens**: Typo in field name, wrong nesting, or extra fields
**Prevention**: Use google-chat-cards library or templates with exact schema

### Issue #3: Widget Limit Exceeded (Silent Failure)
**Error**: No error - widgets beyond 100 simply don't render
**Source**: Google Chat API Limits
**Why It Happens**: Adding too many widgets to single card
**Prevention**: Skill documents 100 widget limit + pagination patterns

### Issue #4: Form Validation Error Format Wrong
**Error**: Form doesn't show validation errors to user
**Source**: Interactive Cards Documentation
**Why It Happens**: Wrong error response format
**Prevention**: Templates include correct error format:
{
"actionResponse": {
"type": "DIALOG",
"dialogAction": {
"actionStatus": {
"statusCode": "INVALID_ARGUMENT",
"userFacingMessage": "Email is required"
}
}
}
}


### Issue #5: Webhook "Unable to Connect" Error
**Error**: Chat shows "Unable to connect to bot"
**Source**: Webhook Setup Guide
**Why It Happens**: URL not publicly accessible, timeout, or wrong response format
**Prevention**: Skill includes timeout handling + response format validation

### Issue #6: Rate Limit Exceeded (429)
**Error**: "RESOURCE_EXHAUSTED" or 429 status code
**Source**: Google Chat API Quotas
**Why It Happens**: Exceeding per-project, per-space, or per-user request limits
**Prevention**: Skill documents rate limits + exponential backoff pattern

---

## Configuration Files Reference

### Cloudflare Worker (wrangler.jsonc)

{
"name": "google-chat-bot",
"main": "src/index.ts",
"compatibility_date": "2026-01-03",
"compatibility_flags": ["nodejs_compat"],

// Secrets (set with: wrangler secret put CHAT_BOT_TOKEN)
"vars": {
"ALLOWED_SPACES": "spaces/SPACE_ID_1,spaces/SPACE_ID_2"
}
}


**Why these settings:**
- nodejs_compat - Required for Web Crypto API (token verification)
- Secrets stored securely (not in code)
- Environment variables for configuration

---

## Common Patterns

### Pattern 1: Notification Bot (Webhook)

// External service sends notification to Chat
async function sendNotification(webhookUrl: string, message: string) {
await fetch(webhookUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
text: message,
cardsV2: [{
cardId: notif-${Date.now()},
card: {
header: { title: "Alert" },
sections: [{
widgets: [{
textParagraph: { text: message }
}]
}]
}
}]
})
})
}


**When to use**: CI/CD alerts, monitoring notifications, event triggers

### Pattern 2: Interactive Form

// Show form to collect data
function showForm() {
return {
cardsV2: [{
cardId: "form-card",
card: {
header: { title: "Enter Details" },
sections: [{
widgets: [
{
textInput: {
name: "email",
label: "Email",
type: "SINGLE_LINE",
hintText: "[email protected]"
}
},
{
selectionInput: {
name: "priority",
label: "Priority",
type: "DROPDOWN",
items: [
{ text: "Low", value: "low" },
{ text: "High", value: "high" }
]
}
},
{
buttonList: {
buttons: [{
text: "Submit",
onClick: {
action: {
function: "submitForm",
parameters: [{
key: "formId",
value: "contact-form"
}]
}
}
}]
}
}
]
}]
}
}]
}
}


**When to use**: Data collection, approval workflows, ticket creation

### Pattern 3: Dialog (Modal)

// Open modal dialog
function openDialog() {
return {
actionResponse: {
type: "DIALOG",
dialogAction: {
dialog: {
body: {
sections: [{
header: "Confirm Action",
widgets: [{
textParagraph: { text: "Are you sure?" }
}, {
buttonList: {
buttons: [
{
text: "Confirm",
onClick: {
action: { function: "confirm" }
}
},
{
text: "Cancel",
onClick: {
action: { function: "cancel" }
}
}
]
}
}]
}]
}
}
}
}
}
}


**When to use**: Confirmations, multi-step workflows, focused data entry

---

## Using Bundled Resources

### Scripts (scripts/)

No executable scripts for this skill.

### Templates (templates/)

**Required for all projects:**
- templates/webhook-handler.ts - Basic webhook receiver
- templates/wrangler.jsonc - Cloudflare Workers config

**Optional based on needs:**
- templates/interactive-bot.ts - HTTP endpoint with event handling
- templates/card-builder-examples.ts - Common card patterns
- templates/form-validation.ts - Input validation with error responses
- templates/bearer-token-verify.ts - Token verification utility

**When to load these**: Claude should reference templates when user asks to:
- Set up Google Chat bot
- Create interactive cards
- Add form validation
- Verify bearer tokens
- Handle button clicks

### References (references/)

- references/google-chat-docs.md - Key documentation links
- references/cards-v2-schema.md - Complete card structure reference
- references/common-errors.md - Error troubleshooting guide

**When Claude should load these**: Troubleshooting errors, designing cards, understanding API

---

## Advanced Topics

### Slash Commands

Register slash commands for quick actions:

// User types: /create-ticket Bug in login
if (event.message?.slashCommand?.commandName === 'create-ticket') {
const text = event.message.argumentText

return Response.json({
text: Creating ticket: ${text},
cardsV2: [/* ticket confirmation card */]
})
}


**Use cases**: Quick actions, shortcuts, power user features

### Thread Replies

Reply in existing thread:

return Response.json({
text: "Reply in thread",
thread: {
name: event.message.thread.name // Use existing thread
}
})


**Use cases**: Conversations, follow-ups, grouped discussions

---

## Spaces API

Programmatically manage Google Chat spaces (rooms). Requires [Chat Admin or App permissions](https://developers.google.com/workspace/chat/authenticate-authorize).

### Available Methods

| Method | Description | Scope Required |
|--------|-------------|----------------|
| spaces.create | Create new space | chat.spaces.create |
| spaces.delete | Delete a space | chat.delete |
| spaces.get | Get space details | chat.spaces.readonly |
| spaces.list | List spaces bot is in | chat.spaces.readonly |
| spaces.patch | Update space settings | chat.spaces |
| spaces.search | Search spaces by criteria | chat.spaces.readonly |
| spaces.setup | Create space and add members | chat.spaces.create |
| spaces.findDirectMessage | Find DM with specific user | chat.spaces.readonly |

### Create a Space

async function createSpace(accessToken: string) {
const response = await fetch('https://chat.googleapis.com/v1/spaces', {
method: 'POST',
headers: {
'Authorization': Bearer ${accessToken},
'Content-Type': 'application/json'
},
body: JSON.stringify({
spaceType: 'SPACE', // or 'GROUP_CHAT', 'DIRECT_MESSAGE'
displayName: 'Project Team',
singleUserBotDm: false,
spaceDetails: {
description: 'Team collaboration space',
guidelines: 'Be respectful and on-topic'
}
})
})
return response.json()
}


### List Spaces (Bot's Accessible Spaces)

async function listSpaces(accessToken: string) {
const response = await fetch(
'https://chat.googleapis.com/v1/spaces?pageSize=100',
{
headers: { 'Authorization': Bearer ${accessToken} }
}
)
const data = await response.json()
// Returns: { spaces: [...], nextPageToken: '...' }
return data.spaces
}


### Search Spaces

async function searchSpaces(accessToken: string, query: string) {
const params = new URLSearchParams({
query: query, // e.g., 'displayName:Project'
pageSize: '50'
})
const response = await fetch(
https://chat.googleapis.com/v1/spaces:search?${params},
{
headers: { 'Authorization': Bearer ${accessToken} }
}
)
return response.json()
}


**Search Query Syntax**:
- displayName:Project - Name contains "Project"
- spaceType:SPACE - Only spaces (not DMs)
- createTime>2025-01-01 - Created after date
- Combine with AND/OR operators

---

## Members API

Manage space membership programmatically. Requires [User or App authorization](https://developers.google.com/workspace/chat/authenticate-authorize).

### Available Methods

| Method | Description | Scope Required |
|--------|-------------|----------------|
| spaces.members.create | Add member to space | chat.memberships |
| spaces.members.delete | Remove member | chat.memberships |
| spaces.members.get | Get member details | chat.memberships.readonly |
| spaces.members.list | List all members | chat.memberships.readonly |
| spaces.members.patch | Update member role | chat.memberships |

### Add Member to Space

async function addMember(accessToken: string, spaceName: string, userEmail: string) {
const response = await fetch(
https://chat.googleapis.com/v1/${spaceName}/members,
{
method: 'POST',
headers: {
'Authorization': Bearer ${accessToken},
'Content-Type': 'application/json'
},
body: JSON.stringify({
member: {
name: users/${userEmail},
type: 'HUMAN' // or 'BOT'
},
role: 'ROLE_MEMBER' // or 'ROLE_MANAGER'
})
}
)
return response.json()
}


### List Space Members

async function listMembers(accessToken: string, spaceName: string) {
const response = await fetch(
https://chat.googleapis.com/v1/${spaceName}/members?pageSize=100,
{
headers: { 'Authorization': Bearer ${accessToken} }
}
)
return response.json()
// Returns: { memberships: [...], nextPageToken: '...' }
}


### Update Member Role

async function updateMemberRole(
accessToken: string,
memberName: string, // e.g., 'spaces/ABC/members/DEF'
newRole: 'ROLE_MEMBER' | 'ROLE_MANAGER'
) {
const response = await fetch(
https://chat.googleapis.com/v1/${memberName}?updateMask=role,
{
method: 'PATCH',
headers: {
'Authorization': Bearer ${accessToken},
'Content-Type': 'application/json'
},
body: JSON.stringify({ role: newRole })
}
)
return response.json()
}


**Member Roles**:
- ROLE_MEMBER - Standard member (read/write messages)
- ROLE_MANAGER - Can manage space settings and members

---

## Reactions API

Add emoji reactions to messages. Added in 2025, supports custom workspace emojis.

### Available Methods

| Method | Description |
|--------|-------------|
| spaces.messages.reactions.create | Add reaction to message |
| spaces.messages.reactions.delete | Remove reaction |
| spaces.messages.reactions.list | List reactions on message |

### Add Reaction

async function addReaction(
accessToken: string,
messageName: string, // e.g., 'spaces/ABC/messages/XYZ'
emoji: string
) {
const response = await fetch(
https://chat.googleapis.com/v1/${messageName}/reactions,
{
method: 'POST',
headers: {
'Authorization': Bearer ${accessToken},
'Content-Type': 'application/json'
},
body: JSON.stringify({
emoji: {
unicode: emoji // e.g., 'πŸ‘' or custom emoji code
}
})
}
)
return response.json()
}


### List Reactions

async function listReactions(accessToken: string, messageName: string) {
const response = await fetch(
https://chat.googleapis.com/v1/${messageName}/reactions?pageSize=100,
{
headers: { 'Authorization': Bearer ${accessToken} }
}
)
return response.json()
// Returns: { reactions: [...], nextPageToken: '...' }
}


**Custom Emoji**: Workspace administrators can upload custom emoji. Use the emoji's customEmoji.uid instead of unicode.

---

## Rate Limits

Google Chat API enforces strict quotas to prevent abuse. Understanding these limits is critical for production apps.

### Per-Project Quotas (Per Minute)

| Operation | Limit | Notes |
|-----------|-------|-------|
| **Read operations** | 3,000/min | spaces.get, members.list, messages.list |
| **Membership writes** | 300/min | members.create, members.delete |
| **Space writes** | 60/min | spaces.create, spaces.patch |
| **Message operations** | 600/min | messages.create, reactions.create |
| **Reactions** | 600/min | Shared with message operations |

### Per-Space Quotas (Per Second)

| Operation | Limit |
|-----------|-------|
| **Read operations** | 15/sec |
| **Write operations** | 1/sec |

### Per-User Quotas

User-authenticated requests are also throttled per user:
- **60 requests/minute** per user for most operations
- **10 requests/minute** for space creation

### Handling Rate Limit Errors

async function withRetry<T>(
fn: () => Promise<T>,
maxRetries = 3
): Promise<T> {
for (let i = 0; i < maxRetries; i++) {
try {
return await fn()
} catch (error: any) {
if (error.status === 429) {
// Rate limited - wait with exponential backoff
const waitMs = Math.pow(2, i) * 1000 + Math.random() * 1000
await new Promise(r => setTimeout(r, waitMs))
continue
}
throw error
}
}
throw new Error('Max retries exceeded')
}

// Usage
const spaces = await withRetry(() => listSpaces(accessToken))


**Best Practices**:
- Cache read operations where possible
- Batch membership operations
- Use pagination efficiently (request larger pages, fewer requests)
- Implement exponential backoff for 429 errors
- Monitor quota usage in Google Cloud Console

---

## Dependencies

**Required**:
- Cloudflare Workers account (free tier works)
- Google Cloud Project with Chat API enabled
- Public HTTPS endpoint (Workers provides this)

**Optional**:
- [email protected] - Type-safe card builder (unofficial)
- Web Crypto API (built into Cloudflare Workers)

---

## Official Documentation

- **Google Chat API**: https://developers.google.com/workspace/chat
- **Cards v2 Reference**: https://developers.google.com/workspace/chat/api/reference/rest/v1/cards
- **Webhooks Guide**: https://developers.google.com/workspace/chat/quickstart/webhooks
- **Interactive Cards**: https://developers.google.com/workspace/chat/dialogs
- **Cloudflare Workers**: https://developers.cloudflare.com/workers

---

## Package Versions (Verified 2026-01-09)

{
"dependencies": {
"google-chat-cards": "^1.0.3"
},
"devDependencies": {
"@cloudflare/workers-types": "^4.20260109.0",
"wrangler": "^4.58.0"
}
}


**Note**: No official Google Chat npm package - use fetch API directly.

---

## Production Example

This skill is based on real-world implementations:
- **Community Examples**: translatebot (Worker + Chat + Translate API)
- **Official Samples**: Multiple working examples in Google's documentation

**Token Savings**: ~65-70% (8k β†’ 2.5k tokens)
**Errors Prevented**: 6/6 documented issues
**Validation**: βœ… Webhook handlers, βœ… Card builders, βœ… Token verification, βœ… Form validation, βœ… Rate limit handling

---

## Troubleshooting

### Problem: "Unauthorized" (401) error
**Solution**: Implement bearer token verification (see templates/bearer-token-verify.ts)

### Problem: Cards don't render / "Invalid JSON payload"
**Solution**: Validate card JSON against Cards v2 schema, ensure exact field names

### Problem: Widgets beyond first 100 don't show
**Solution**: Split into multiple cards or use pagination

### Problem: Form validation errors not showing to user
**Solution**: Return correct error format with actionResponse.dialogAction.actionStatus

### Problem: "Unable to connect to bot"
**Solution**: Ensure URL is publicly accessible, responds within timeout, returns valid JSON

---

## Complete Setup Checklist

Use this checklist to verify your setup:

- [ ] Google Cloud project created
- [ ] Chat API enabled in project
- [ ] Chat app configured with webhook/HTTP endpoint URL
- [ ] Cloudflare Worker deployed and accessible
- [ ] Bearer token verification implemented (if using HTTP endpoint)
- [ ] Card JSON validated against schema
- [ ] Widget count under 100 per card
- [ ] Form validation returns correct error format
- [ ] Tested in Chat space successfully
- [ ] Error handling for all event types

---

**Questions? Issues?**

1. Check references/common-errors.md for troubleshooting
2. Verify card JSON structure matches Cards v2 schema
3. Check official docs: https://developers.google.com/workspace/chat
4. Ensure bearer token verification is implemented for HTTP endpoints

How to Use This Skill Unit

Option A: Project-Specific (Recommended)

  1. Click "Download" above
  2. In your project, create the directory: .agent/skills/google-chat-api/
  3. Save the file as SKILL.md
  4. The agent will automatically discover the skill based on its description.

Option B: Global Installation (All Agents)

Save the file to these locations to make it available across all projects:

  • Claude Code: ~/.claude/skills/jezweb/claude-skills/google-chat-api/SKILL.md
  • Cursor: ~/.cursor/skills/jezweb/claude-skills/google-chat-api/SKILL.md
  • Antigravity: ~/.gemini/antigravity/skills/jezweb/claude-skills/google-chat-api/SKILL.md

πŸš€ Install with CLI:
npx skills add jezweb/claude-skills

Read the Master Guide: Mastering Agent Skills β†’

Recommended Rules

View more rules β†’

Recommended Workflows

View more workflows β†’

Recommended MCP Servers

View more MCP servers β†’

Take It Further

Maximize your productivity with these powerful resources

πŸ“‹

Define Your Standards

Set up coding standards to ensure this workflow produces consistent, high-quality results.

Browse Rules Library
πŸ“–

Master Workflows

Learn how to create custom workflows, use Turbo Mode, and build your automation library.

Complete Guide

How to use this Skill in Claude Code & Cursor

For Claude Code (CLI)

To use this skill in Claude Code, copy the rule content into your project's custom instructions or follow our Add-Skill CLI guide. This ensures Claude follows your standards during every code generation.

For Cursor & Windsurf

For Cursor or Windsurf, individual skills are best used in the "Rules for AI" section. This specific unit helps the agent avoid communication & collaboration issues, leading to cleaner, more efficient code.

Why the skill format matters: the standardized Agent Skills format lets your AI agent load detailed instructions only when they are relevant, keeping your prompt clean while improving results.

Source & attribution

This skill is categorized under Communication & Collaboration and is published by JezWeb, maintained in jezweb/claude-skills.

← Browse All Agent Skills
Sponsored AI assistant. Recommendations may be paid.