Build Zoom Team Chat App
AnthropicOfficialCreated by ZoomDistributed by Anthropic
- Skill
- Tool integration
- Automation and integrations
- MIT
- Medium risk
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
This skill provides a structured framework for developing integrations with Zoom Team Chat. It clarifies the critical distinction between the Team Chat API (for user-authenticated messaging) and the Chatbot API (for interactive bot experiences). The documentation covers environment setup, authentication flows, webhook management, and the implementation of rich message cards, slash commands, and interactive UI components.
What it does
- Distinguishes between user-level Team Chat API and bot-level Chatbot API implementations.
- Provides setup guides for OAuth and Client Credentials authentication flows.
- Details the structure and components for building rich, interactive message cards.
- Explains how to handle webhook events for slash commands and button interactions.
- Offers patterns for integrating LLMs and managing chatbot lifecycles.
- Includes troubleshooting guides for common authentication and webhook issues.
When to use it
- When you need to send automated notifications from CI/CD pipelines or scripts.
- When building interactive chatbots that respond to user slash commands.
- When creating rich UI elements like buttons, forms, or dropdowns within Zoom chat.
- When you need to integrate external services or LLMs into a Zoom chat environment.
Advantages
- Clear separation of concerns between user-based and bot-based integration types.
- Comprehensive library of examples for common operations and interactive features.
- Standardized approach to environment configuration and security best practices.
- Centralized navigation for official documentation and sample applications.
Usage examples
- “How do I send a simple message to a Zoom channel as a user?”
- The skill provides the Team Chat API endpoint and a JavaScript fetch example using OAuth to post messages to a specific channel ID.
- “I want to build a chatbot that uses buttons for user input.”
- The skill guides you to use the Chatbot API, explains the required Client Credentials, and provides a template for sending rich message cards with action items.
Install
Download the skill as a ZIP:
https://autogineer.com/agent-skills/anthropics/build-zoom-team-chat-app/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip build-zoom-team-chat-app.zip -d .agents/skills
Documentation by Zoom
/build-zoom-team-chat-app
Background reference for Zoom Team Chat integrations. Use this after the workflow is clear, especially when the Team Chat API versus Chatbot API distinction matters.
Read This First (Critical)
There are two different integration types and they are not interchangeable:
Team Chat API (user type)
Sends messages as a real authenticated user
Uses User OAuth (
authorization_code)Endpoint family:
/v2/chat/users/...
Chatbot API (bot type)
Sends messages as your bot identity
Uses Client Credentials (
client_credentials)Endpoint family:
/v2/im/chat/messages
If you choose the wrong type early, auth/scopes/endpoints all mismatch and implementation fails.
Official Documentation: https://developers.zoom.us/docs/team-chat/
Chatbot Documentation: https://developers.zoom.us/docs/team-chat/chatbot/extend/
API Reference: https://developers.zoom.us/docs/api/rest/reference/chatbot/
Quick Links
New to Team Chat? Follow this path:
Get Started - End-to-end fast path (user type vs bot type)
Choose Your API - Team Chat API vs Chatbot API
Environment Setup - Credentials, scopes, app configuration
OAuth Setup - Complete authentication flow
Send First Message - Working code to send messages
Reference:
Chatbot Message Cards - Complete card component reference
Webhook Events - All webhook event types
API Reference - Endpoints, methods, parameters
Sample Applications - 10+ official sample apps
Integrated Index - see the section below in this file
Having issues?
Authentication errors → OAuth Troubleshooting
Webhook not receiving events → Webhook Setup Guide
Messages not sending → Common Issues
Start with quick checks → 5-Minute Runbook
OAuth endpoint sanity check:
Authorize URL:
https://zoom.us/oauth/authorizeToken URL:
https://zoom.us/oauth/tokenIf
/oauth/tokenreturns 404/HTML, usehttps://zoom.us/oauth/token.
Building Interactive Bots?
Button Actions - Handle button clicks
Form Submissions - Process form data
Slash Commands - Create custom commands
Quick Decision: Which API?
| Use Case | API to Use |
|---|---|
| Send notifications from scripts/CI/CD | Team Chat API |
| Automate messages as a user | Team Chat API |
| Build an interactive chatbot | Chatbot API |
| Respond to slash commands | Chatbot API |
| Create messages with buttons/forms | Chatbot API |
| Handle user interactions | Chatbot API |
Team Chat API (User-Level)
Messages appear as sent by authenticated user
Requires User OAuth (authorization_code flow)
Endpoint:
POST https://api.zoom.us/v2/chat/users/me/messagesScopes:
chat_message:write,chat_channel:read
Chatbot API (Bot-Level)
Messages appear as sent by your bot
Requires Client Credentials grant
Endpoint:
POST https://api.zoom.us/v2/im/chat/messagesScopes:
imchat:bot(auto-added)Rich cards: buttons, forms, dropdowns, images
Prerequisites
System Requirements
Zoom account
Account owner, admin, or Zoom for developers role enabled
To enable: User Management → Roles → Role Settings → Advanced features → Enable Zoom for developers
Create Zoom App
Go to Zoom App Marketplace
Click Develop → Build App
Select General App (OAuth)
⚠️ Do NOT use Server-to-Server OAuth - S2S apps don't have the Chatbot/Team Chat feature. Only General App (OAuth) supports chatbots.
Required Credentials
From Zoom Marketplace → Your App:
| Credential | Location | Used By |
|---|---|---|
| Client ID | App Credentials → Development | Both APIs |
| Client Secret | App Credentials → Development | Both APIs |
| Account ID | App Credentials → Development | Chatbot API |
| Bot JID | Features → Chatbot → Bot Credentials | Chatbot API |
| Secret Token | Features → Team Chat Subscriptions | Chatbot API |
See: Environment Setup Guide for complete configuration steps.
Quick Start: Team Chat API
Send a message as a user:
// 1. Get access token via OAuth
const accessToken = await getOAuthToken(); // See examples/oauth-setup.md
// 2. Send message to channel
const response = await fetch('https://api.zoom.us/v2/chat/users/me/messages', {
method: 'POST',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
message: 'Hello from CI/CD pipeline!',
to_channel: 'CHANNEL_ID'
})
});
const data = await response.json();
// { "id": "msg_abc123", "date_time": "2024-01-15T10:30:00Z" }Complete example: Send Message Guide
Quick Start: Chatbot API
Build an interactive chatbot:
// 1. Get chatbot token (client_credentials)
async function getChatbotToken() {
const credentials = Buffer.from(
`${CLIENT_ID}:${CLIENT_SECRET}`
).toString('base64');
const response = await fetch('https://zoom.us/oauth/token', {
method: 'POST',
headers: {
'Authorization': `Basic ${credentials}`,
'Content-Type': 'application/x-www-form-urlencoded'
},
body: 'grant_type=client_credentials'
});
return (await response.json()).access_token;
}
// 2. Send chatbot message with buttons
const response = await fetch('https://api.zoom.us/v2/im/chat/messages', {
method: 'POST',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
robot_jid: process.env.ZOOM_BOT_JID,
to_jid: payload.toJid, // From webhook
account_id: payload.accountId, // From webhook
content: {
head: {
text: 'Build Notification',
sub_head: { text: 'CI/CD Pipeline' }
},
body: [
{ type: 'message', text: 'Deployment successful!' },
{
type: 'fields',
items: [
{ key: 'Branch', value: 'main' },
{ key: 'Commit', value: 'abc123' }
]
},
{
type: 'actions',
items: [
{ text: 'View Logs', value: 'view_logs', style: 'Primary' },
{ text: 'Dismiss', value: 'dismiss', style: 'Default' }
]
}
]
}
})
});Complete example: Chatbot Setup Guide
Key Features
Team Chat API
| Feature | Description |
|---|---|
| Send Messages | Post messages to channels or direct messages |
| List Channels | Get user's channels with metadata |
| Create Channels | Create public/private channels programmatically |
| Threaded Replies | Reply to specific messages in threads |
| Edit/Delete | Modify or remove messages |
Chatbot API
| Feature | Description |
|---|---|
| Rich Message Cards | Headers, images, fields, buttons, forms |
| Slash Commands | Custom /commands trigger webhooks |
| Button Actions | Interactive buttons with webhook callbacks |
| Form Submissions | Collect user input with forms |
| Dropdown Selects | Channel, member, date/time pickers |
| LLM Integration | Easy integration with Claude, GPT, etc. |
Webhook Events (Chatbot API)
| Event | Trigger | Use Case |
|---|---|---|
bot_notification | User messages bot or uses slash command | Process commands, integrate LLM |
bot_installed | Bot added to account | Initialize bot state |
interactive_message_actions | Button clicked | Handle button actions |
chat_message.submit | Form submitted | Process form data |
app_deauthorized | Bot removed | Cleanup |
Message Card Components
Build rich interactive messages with these components:
| Component | Description |
|---|---|
| header | Title and subtitle |
| message | Plain text |
| fields | Key-value pairs |
| actions | Buttons (Primary, Danger, Default styles) |
| section | Colored sidebar grouping |
| attachments | Images with links |
| divider | Horizontal line |
| form_field | Text input |
| dropdown | Select menu |
| date_picker | Date selection |
See: Message Cards Reference for complete component catalog
Architecture Patterns
Chatbot Lifecycle
User types /command → Webhook receives bot_notification
↓
payload.cmd = "user's input"
↓
Process command
↓
Send response via sendChatbotMessage()LLM Integration Pattern
case 'bot_notification': {
const { toJid, cmd, accountId } = payload;
// 1. Call your LLM
const llmResponse = await callClaude(cmd);
// 2. Send response back
await sendChatbotMessage(toJid, accountId, {
body: [{ type: 'message', text: llmResponse }]
});
}Sample Applications
| Sample | Description | Link |
|---|---|---|
| Chatbot Quickstart | Official tutorial (recommended start) | GitHub |
| Claude Chatbot | AI chatbot with Anthropic Claude | GitHub |
| Unsplash Chatbot | Image search with database | GitHub |
| ERP Chatbot | Oracle ERP with scheduled alerts | GitHub |
| Task Manager | Full CRUD app | GitHub |
See: Sample Applications Guide for analysis of all 10 samples
Common Operations
Send Message to Channel
// Team Chat API
await fetch('https://api.zoom.us/v2/chat/users/me/messages', {
method: 'POST',
headers: { 'Authorization': `Bearer ${token}` },
body: JSON.stringify({
message: 'Hello!',
to_channel: 'CHANNEL_ID'
})
});Handle Button Click
// Webhook handler
case 'interactive_message_actions': {
const { actionItem, toJid, accountId } = payload;
if (actionItem.value === 'approve') {
await sendChatbotMessage(toJid, accountId, {
body: [{ type: 'message', text: '✅ Approved!' }]
});
}
}Verify Webhook Signature
function verifyWebhook(req) {
const message = `v0:${req.headers['x-zm-request-timestamp']}:${JSON.stringify(req.body)}`;
const hash = crypto.createHmac('sha256', process.env.ZOOM_VERIFICATION_TOKEN)
.update(message)
.digest('hex');
return req.headers['x-zm-signature'] === `v0=${hash}`;
}Deployment
ngrok for Local Development
# Install ngrok
npm install -g ngrok
# Expose local server
ngrok http 4000
# Use HTTPS URL as Bot Endpoint URL in Zoom Marketplace
# Example: https://abc123.ngrok.io/webhookProduction Deployment
See: Deployment Guide for:
Nginx reverse proxy setup
Base path configuration
OAuth redirect URI setup
Limitations
| Limit | Value |
|---|---|
| Message length | 4,096 characters |
| File size | 512 MB |
| Members per channel | 10,000 |
| Channels per user | 500 |
Security Best Practices
Verify webhook signatures - Always validate using
x-zm-signatureheaderSanitize messages - Limit to 4096 chars, remove control characters
Validate JIDs - Check format:
user@domainorchannel@domainEnvironment variables - Never hardcode credentials
Use HTTPS - Required for production webhooks
Complete Documentation Library
Core Concepts (Start Here!)
API Selection Guide - Choose Team Chat API vs Chatbot API
Environment Setup - Complete credentials guide
Authentication Flows - OAuth vs Client Credentials
Webhook Architecture - How webhooks work
Message Card Structure - Card component hierarchy
Complete Examples
OAuth Setup - Full OAuth implementation
Send Message - Team Chat API message sending
Chatbot Setup - Complete chatbot with webhooks
Button Actions - Handle interactive buttons
Form Submissions - Process form data
Slash Commands - Create custom commands
LLM Integration - Claude/GPT integration
Scheduled Alerts - Cron + incoming webhooks
Channel Management - Create/manage channels
References
API Reference - All endpoints and methods
Webhook Events - Complete event reference
Message Cards - All card components
Sample Applications - Analysis of 10 official samples
Error Codes - Error handling guide
Troubleshooting
OAuth Issues - Authentication failures
Webhook Issues - Webhook debugging
Common Issues - Quick diagnostics
Resources
Official Docs: https://developers.zoom.us/docs/team-chat/
API Reference: https://developers.zoom.us/docs/api/rest/reference/chatbot/
Dev Forum: https://devforum.zoom.us/
App Marketplace: https://marketplace.zoom.us/
Need help? Start with Integrated Index section below for complete navigation.
Integrated Index
This section was migrated from SKILL.md.
Complete navigation guide for the Zoom Team Chat skill.
Quick Start Paths
Start here: Get Started
Fast troubleshooting first: 5-Minute Runbook
Path 1: Team Chat API (User-Level Messaging)
For sending messages as a user account.
API Selection Guide - Confirm Team Chat API is right
Environment Setup - Get credentials
OAuth Setup Example - Implement authentication
Send Message Example - Send your first message
Path 2: Chatbot API (Interactive Bots)
For building interactive chatbots with rich messages.
API Selection Guide - Confirm Chatbot API is right
Environment Setup - Get credentials (including Bot JID)
Webhook Architecture - Understand webhook events
Chatbot Setup Example - Build your first bot
Message Cards Reference - Create rich messages
Core Concepts
Essential understanding for both APIs.
| Document | Description |
|---|---|
| API Selection Guide | Choose Team Chat API vs Chatbot API |
| Environment Setup | Complete credentials and app configuration |
| Authentication Flows | OAuth vs Client Credentials |
| Webhook Architecture | How webhooks work (Chatbot API) |
| Message Card Structure | Card component hierarchy |
| Deployment Guide | Production deployment strategies |
| Security Best Practices | Secure your integration |
Complete Examples
Working code for common scenarios.
Authentication
| Example | Description |
|---|---|
| OAuth Setup | User OAuth flow implementation |
| Token Management | Refresh tokens, expiration handling |
Basic Operations
| Example | Description |
|---|---|
| Send Message | Team Chat API message sending |
| Chatbot Setup | Complete chatbot with webhooks |
| List Channels | Get user's channels |
| Create Channel | Create public/private channels |
Interactive Features (Chatbot API)
| Example | Description |
|---|---|
| Button Actions | Handle button clicks |
| Form Submissions | Process form data |
| Slash Commands | Create custom commands |
| Dropdown Selects | Channel/member pickers |
Advanced Integration
| Example | Description |
|---|---|
| LLM Integration | Integrate Claude/GPT |
| Scheduled Alerts | Cron + incoming webhooks |
| Database Integration | Store conversation state |
| Multi-Step Workflows | Complex user interactions |
References
API Documentation
| Reference | Description |
|---|---|
| API Reference | Pointers and common endpoints |
| Webhook Events | Event types and handling checklist |
| Message Cards | All card components |
| Error Codes | Error handling guide |
Sample Applications
| Reference | Description |
|---|---|
| Sample Applications | Sample app index/notes |
Field Guides
| Reference | Description |
|---|---|
| JID Formats | Understanding JID identifiers |
| Scopes Reference | Common scopes |
| Rate Limits | Throttling guidance |
Troubleshooting
| Guide | Description |
|---|---|
| Common Issues | Quick diagnostics and solutions |
| OAuth Issues | Authentication failures |
| Webhook Issues | Webhook debugging |
| Message Issues | Message sending problems |
| Deployment Issues | Production problems |
Architecture Patterns
Chatbot Lifecycle
User Action → Webhook → Process → ResponseLLM Integration Pattern
User Input → Chatbot receives → Call LLM → Send responseApproval Workflow Pattern
Request → Send card with buttons → User clicks → Update status → NotifyCommon Use Cases
Notifications
CI/CD build notifications
Server monitoring alerts
Scheduled reports
System health checks
Workflows
Approval requests
Task assignment
Status updates
Form submissions
Integrations
LLM-powered assistants
Database queries
External API integration
File/image sharing
Automation
Scheduled messages
Auto-responses
Data collection
Report generation
Resource Links
Official Documentation
Team Chat Docs - Official overview
Chatbot Docs - Chatbot guide
API Reference - REST API docs
App Marketplace - Create and manage apps
Sample Code
Chatbot Quickstart - Official tutorial
Claude Chatbot - AI integration
Unsplash Chatbot - Image search bot
ERP Chatbot - Enterprise integration
Task Manager - Full CRUD app
Tools
App Card Builder - Visual card designer
ngrok - Local webhook testing
Postman - API testing
Community
Developer Forum - Ask questions
GitHub Discussions - Community support
Developer Support - Official support
Documentation Status
✅ Complete
Main skill.md entry point
API Selection Guide
Environment Setup
Webhook Architecture
Chatbot Setup Example (complete working code)
Message Cards Reference
Common Issues Troubleshooting
📝 Pending (High Priority)
OAuth Setup Example
Send Message Example
Button Actions Example
LLM Integration Example
Webhook Events Reference
API Reference
Sample Applications Analysis
📋 Planned (Lower Priority)
Form Submissions Example
Channel Management Examples
Database Integration Example
Error Codes Reference
Rate Limits Guide
Deployment troubleshooting
Getting Started Checklist
For Team Chat API
[ ] Read API Selection Guide
[ ] Complete Environment Setup
[ ] Obtain Client ID, Client Secret
[ ] Add required scopes
[ ] Implement OAuth flow
[ ] Send first message
For Chatbot API
[ ] Read API Selection Guide
[ ] Complete Environment Setup
[ ] Obtain Client ID, Client Secret, Bot JID, Secret Token, Account ID
[ ] Enable Team Chat in Features
[ ] Configure Bot Endpoint URL and Slash Command
[ ] Set up ngrok for local testing
[ ] Implement webhook handler
[ ] Send first chatbot message
Version History
v1.0 (2026-02-09) - Initial comprehensive documentation
Core concepts (API selection, environment setup, webhooks)
Complete chatbot setup example
Message cards reference
Common issues troubleshooting
Support
Use this SKILL.md as the navigation hub for Team Chat API selection, setup, examples, and troubleshooting.
Environment Variables
See references/environment-variables.md for standardized
.envkeys and where to find each value.
Files
- ATTRIBUTION.mdAdded by AutoGineer989 B
- LICENSELicence file added by AutoGineer1.1 KiB
- RUNBOOK.md2.7 KiB
- SKILL.md23.2 KiB
- concepts/api-selection.md7.3 KiB
- concepts/authentication.md1.4 KiB
- concepts/deployment.md719 B
- concepts/environment-setup.md8.8 KiB
- concepts/message-structure.md676 B
- concepts/security.md479 B
- concepts/webhooks.md11.9 KiB
- examples/button-actions.md394 B
- examples/channel-management.md321 B
- examples/chatbot-setup.md12.2 KiB
- examples/database-integration.md313 B
- examples/dropdown-selects.md305 B
- examples/form-submissions.md386 B
- examples/llm-integration.md532 B
- examples/multi-step-workflows.md301 B
- examples/oauth-setup.md1.6 KiB
- examples/scheduled-alerts.md353 B
- examples/send-message.md418 B
- examples/slash-commands.md510 B
- examples/token-management.md443 B
- get-started.md1.6 KiB
- references/api-reference.md539 B
- references/environment-variables.md1006 B
- references/error-codes.md449 B
- references/jid-formats.md248 B
- references/message-cards.md6.6 KiB
- references/rate-limits.md206 B
- references/sample-comparison.md1.1 KiB
- references/samples.md14.4 KiB
- references/scopes.md341 B
- references/webhook-events.md565 B
- troubleshooting/common-issues.md9.7 KiB
- troubleshooting/deployment-issues.md641 B
- troubleshooting/message-issues.md318 B
- troubleshooting/oauth-issues.md882 B
- troubleshooting/webhook-issues.md365 B
references/samples.md
Sample Applications Analysis
Analysis of 10 official Zoom Team Chat sample applications, extracted patterns, and best practices.
Sample Overview
| Sample | Language | Complexity | Best For |
|---|---|---|---|
| chatbot-nodejs-quickstart | Node.js | ⭐ Beginner | Start here - Tutorial series |
| zoom-chatbot-claude-sample | Node.js | ⭐⭐ Intermediate | LLM integration pattern |
| unsplash-chatbot | Node.js | ⭐⭐ Intermediate | API integration + database |
| zoom-erp-chatbot-sample | Node.js | ⭐⭐⭐ Advanced | Enterprise integration |
| task-manager-sample | Node.js | ⭐⭐⭐ Advanced | Full CRUD application |
| zoom-cohere-chatbot-sample | Node.js | ⭐⭐ Intermediate | Cohere LLM integration |
| zoom-cerebras-chatbot-sample | Node.js | ⭐⭐ Intermediate | Cerebras LLM integration |
| zoom-team-chat-shortcut-sample | Node.js | ⭐⭐ Intermediate | Shortcuts and UI elements |
| zoom-teams-chat-snowflake-sample | Node.js | ⭐⭐⭐ Advanced | Snowflake data integration |
| rivet-javascript-sample | Node.js | ⭐⭐ Intermediate | Rivet SDK usage |
1. chatbot-nodejs-quickstart
Repository: https://github.com/zoom/chatbot-nodejs-quickstart
Description: Official tutorial series covering 9 episodes from setup to advanced features.
Key Features:
Setup & Send Messages
Handle Events
Slash Commands
Markdown & Emojis
Reactions & Interactive Messages
Threaded Replies
Search Messages via API
Scheduling Messages
Zoom Workplace App Integration
Project Structure:
chatbot-nodejs-quickstart/
├── routes/
│ ├── zoom-webhookHandler.js # Webhook event handling
│ └── oauth-routes.js # OAuth flow
├── utils/
│ ├── zoom-api.js # API helper functions
│ ├── zoom-chatbot-auth.js # Token generation
│ └── validation.js # Webhook signature verification
├── views/ # EJS templates
├── server.js # Express app
└── .env.example # Environment variablesKey Patterns:
Webhook Handler Pattern
async function handleZoomWebhook(req, res) {
verifyZoomWebhookSignature(req);
const { event, payload } = req.body;
switch (event) {
case 'bot_notification':
return handleBotNotification(payload, res);
case 'interactive_message_actions':
return handleButtonClick(payload, res);
// ... more cases
}
}Token Generation
async function getChatbotToken() {
const credentials = Buffer.from(
`${CLIENT_ID}:${CLIENT_SECRET}`
).toString('base64');
const response = await fetch('https://zoom.us/oauth/token', {
method: 'POST',
headers: { 'Authorization': `Basic ${credentials}` },
body: 'grant_type=client_credentials'
});
return (await response.json()).access_token;
}Best Practices:
✅ Signature verification on all webhooks
✅ Environment variables for credentials
✅ Modular route structure
✅ Error handling with try/catch
✅ Immediate webhook response (200 status)
Recommended For: First-time chatbot developers
2. zoom-chatbot-claude-sample
Repository: https://github.com/zoom/zoom-chatbot-claude-sample
Description: AI-powered chatbot using Anthropic Claude for natural language responses.
Key Features:
Claude API integration
Conversation history tracking
Streaming responses (optional)
Context management
LLM Integration Pattern:
case 'bot_notification': {
const { toJid, cmd, accountId } = payload;
// Call Claude API
const response = await anthropic.messages.create({
model: 'claude-sonnet-4-20250514',
max_tokens: 1024,
messages: [{ role: 'user', content: cmd }]
});
const llmResponse = response.content[0].text;
// Send back to Zoom
await sendChatbotMessage(toJid, accountId, {
body: [{ type: 'message', text: llmResponse }]
});
}Conversation History Pattern:
const conversationHistory = new Map();
function addToHistory(userId, role, content) {
if (!conversationHistory.has(userId)) {
conversationHistory.set(userId, []);
}
conversationHistory.get(userId).push({ role, content });
}
// In bot_notification handler
const history = conversationHistory.get(userId) || [];
const response = await anthropic.messages.create({
model: 'claude-sonnet-4-20250514',
messages: history
});Environment Variables:
ANTHROPIC_API_KEY=your_api_key_here
ZOOM_CLIENT_ID=...
ZOOM_CLIENT_SECRET=...
ZOOM_BOT_JID=...Recommended For: Building AI assistants
3. unsplash-chatbot
Repository: https://github.com/zoom/unsplash-chatbot
Description: Image search bot integrating Unsplash API with database storage.
Key Features:
Third-party API integration (Unsplash)
Database persistence (SQLite/PostgreSQL)
Image search and display
User preference storage
Database Schema:
CREATE TABLE users (
id INTEGER PRIMARY KEY,
zoom_user_id TEXT UNIQUE,
preferences TEXT
);
CREATE TABLE searches (
id INTEGER PRIMARY KEY,
user_id INTEGER,
query TEXT,
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id)
);Image Display Pattern:
{
"content": {
"head": { "text": "Image Results" },
"body": [
{
"type": "attachments",
"img_url": imageData.urls.regular,
"resource_url": imageData.links.html,
"information": {
"title": { "text": imageData.description },
"description": { "text": `Photo by ${imageData.user.name}` }
}
}
]
}
}Best Practices:
✅ API rate limiting handling
✅ Error handling for external APIs
✅ Database connection pooling
✅ User data privacy
Recommended For: External API integration patterns
4. zoom-erp-chatbot-sample
Repository: https://github.com/zoom/zoom-erp-chatbot-sample
Description: Enterprise Resource Planning integration with scheduled alerts.
Key Features:
Oracle ERP API integration
Scheduled notifications (cron)
Approval workflows
Threaded conversations
Scheduled Alerts Pattern:
const cron = require('node-cron');
// Daily report at 9 AM
cron.schedule('0 9 * * *', async () => {
const report = await getERPReport();
await sendChatbotMessage(channelJid, accountId, {
head: { "text": "Daily ERP Report" },
body: [
{ "type": "fields", "items": report.fields },
{
"type": "actions",
"items": [
{ "text": "View Details", "value": "view_report" }
]
}
]
});
});Approval Workflow Pattern:
// Send approval request
{
"head": { "text": "Expense Approval Required" },
"body": [
{ "type": "fields", "items": expenseFields },
{
"type": "actions",
"items": [
{ "text": "Approve", "value": `approve_${expenseId}`, "style": "Primary" },
{ "text": "Reject", "value": `reject_${expenseId}`, "style": "Danger" }
]
}
]
}
// Handle button click
case 'interactive_message_actions': {
const action = payload.actionItem.value;
const [decision, expenseId] = action.split('_');
await updateERPStatus(expenseId, decision);
await sendConfirmation(payload.toJid, decision);
}Recommended For: Enterprise integrations, workflows
5. task-manager-sample
Repository: https://github.com/zoom/task-manager-sample
Description: Full-featured task management application with CRUD operations.
Key Features:
Create, read, update, delete tasks
Task assignment
Due date tracking
Status management
Persistent storage
CRUD Pattern:
// CREATE
case 'bot_notification': {
if (cmd.startsWith('create task')) {
const taskData = parseTaskCommand(cmd);
const task = await db.createTask(taskData);
await sendTaskCreatedMessage(toJid, accountId, task);
}
}
// READ
case 'interactive_message_actions': {
if (actionItem.value.startsWith('view_task')) {
const taskId = actionItem.value.split('_')[2];
const task = await db.getTask(taskId);
await sendTaskDetails(toJid, accountId, task);
}
}
// UPDATE
case 'interactive_message_actions': {
if (actionItem.value.startsWith('complete_task')) {
const taskId = actionItem.value.split('_')[2];
await db.updateTaskStatus(taskId, 'completed');
await sendStatusUpdate(toJid, accountId, taskId);
}
}
// DELETE
case 'interactive_message_actions': {
if (actionItem.value.startsWith('delete_task')) {
const taskId = actionItem.value.split('_')[2];
await db.deleteTask(taskId);
await sendDeletionConfirmation(toJid, accountId, taskId);
}
}Recommended For: Full application architecture
Common Patterns Across Samples
1. Environment Variable Management
All samples use .env files with similar structure:
# Authentication
ZOOM_CLIENT_ID=
ZOOM_CLIENT_SECRET=
ZOOM_BOT_JID=
ZOOM_VERIFICATION_TOKEN=
ZOOM_ACCOUNT_ID=
# Third-party APIs (if applicable)
ANTHROPIC_API_KEY=
UNSPLASH_ACCESS_KEY=
# Server
PORT=4000
NODE_ENV=development2. Project Structure
Common folder organization:
sample-app/
├── routes/
│ ├── webhook.js # Webhook handlers
│ └── oauth.js # OAuth flows (if needed)
├── utils/
│ ├── zoom-api.js # Zoom API wrappers
│ ├── auth.js # Token management
│ └── validation.js # Input validation
├── models/ # Database models (if applicable)
├── views/ # Frontend templates (if applicable)
├── server.js # Express app
├── .env.example
└── package.json3. Webhook Verification
All samples verify webhook signatures:
function verifyWebhook(req) {
const signature = req.headers['x-zm-signature'];
const timestamp = req.headers['x-zm-request-timestamp'];
const message = `v0:${timestamp}:${JSON.stringify(req.body)}`;
const hash = crypto.createHmac('sha256', SECRET_TOKEN)
.update(message)
.digest('hex');
return signature === `v0=${hash}`;
}4. Error Handling
Consistent error handling pattern:
app.post('/webhook', async (req, res) => {
try {
verifyWebhook(req);
await handleWebhook(req.body);
res.status(200).json({ success: true });
} catch (error) {
console.error('Webhook error:', error);
if (error.message.includes('signature')) {
return res.status(401).json({ error: 'Invalid signature' });
}
res.status(500).json({ error: 'Internal server error' });
}
});5. Async Webhook Processing
Respond immediately, process async:
app.post('/webhook', (req, res) => {
// Respond immediately
res.status(200).json({ success: true });
// Process asynchronously
processWebhookAsync(req.body).catch(error => {
console.error('Async processing error:', error);
});
});Architecture Lessons
Chatbot Lifecycle
Common lifecycle across all samples:
1. User Action (slash command, button click, message)
↓
2. Zoom sends webhook to Bot Endpoint URL
↓
3. Server verifies signature
↓
4. Server responds 200 (immediately)
↓
5. Server processes request (async)
↓
6. Server calls external APIs if needed
↓
7. Server sends chatbot message back to ZoomState Management
Simple bots: In-memory state (Map/Object) Production bots: Database (PostgreSQL, MongoDB, Redis)
// Simple (development)
const userState = new Map();
// Production
const userState = {
async get(userId) {
return await db.query('SELECT * FROM user_state WHERE user_id = $1', [userId]);
},
async set(userId, state) {
return await db.query('INSERT INTO user_state (user_id, state) VALUES ($1, $2) ON CONFLICT (user_id) DO UPDATE SET state = $2', [userId, state]);
}
};Deprecation Notes
Some samples may use deprecated patterns:
❌ Old Pattern (Don't Use)
// Hardcoded credentials
const CLIENT_ID = 'abc123';✅ New Pattern (Use This)
// Environment variables
const CLIENT_ID = process.env.ZOOM_CLIENT_ID;❌ Old Pattern (Don't Use)
// Synchronous webhook processing (may timeout)
app.post('/webhook', async (req, res) => {
await longRunningProcess();
res.status(200).json({ success: true });
});✅ New Pattern (Use This)
// Async processing
app.post('/webhook', (req, res) => {
res.status(200).json({ success: true });
longRunningProcess().catch(console.error);
});Sample Selection Guide
Choose chatbot-nodejs-quickstart if:
You're new to Zoom chatbots
You want a tutorial series
You need step-by-step guidance
Choose zoom-chatbot-claude-sample if:
You want to integrate an LLM
You need conversational AI
You want to see LLM integration patterns
Choose unsplash-chatbot if:
You need to integrate external APIs
You want database patterns
You need user preference storage
Choose zoom-erp-chatbot-sample if:
You're building enterprise integrations
You need scheduled notifications
You want approval workflows
Choose task-manager-sample if:
You want a full CRUD application
You need complex state management
You want to see production architecture
Next Steps
Chatbot Setup Example - Build your own using these patterns
LLM Integration Example - Integrate Claude/GPT
Button Actions Example - Handle interactive components
Sample Comparison - Compare common sample shapes before choosing a baseline
Resources
Requirements and compatibility
Written for: Claude Code, Claude apps
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Needs: Needs network access, Needs Node.js
Security
What our scanner noticed· Medium risk
- Possible data-exfiltration endpoints
- Instructions that use the network
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Created by
- Zoom
- Publisher
- Anthropic (Official)
- Distributed by
- Anthropic
- Source
- anthropics/knowledge-work-plugins · partner-built/zoom-plugin/skills/team-chat · commit e050c2e
- Licence
- MIT License (redistribution allowed)
- LICENSE (added by AutoGineer from partner-built/zoom-plugin/LICENSE)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by Zoom or Anthropic.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download build-zoom-team-chat-app.zip