Build Zoom Team Chat App
OpenAIOfficialCreated by ZoomDistributed by OpenAI
- Skill
- Tool integration
- Software development
- MIT
- Medium risk
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
This skill provides a systematic approach to building applications for Zoom Team Chat. It guides developers through selecting the appropriate API surface, configuring app settings, modeling message structures, and implementing secure authentication and webhook handling. It covers the lifecycle of building both user-scoped messaging integrations and interactive chatbot workflows.
What it does
- Helps select between Team Chat API and Chatbot API based on integration requirements.
- Outlines the configuration of app types, scopes, and role enablement.
- Provides guidance on modeling message structures including rich cards, forms, and slash commands.
- Details the implementation of OAuth flows and token management.
- Supports the setup of webhook handlers with signature verification.
- Assists in debugging common issues related to JID formats, channel membership, and payload shapes.
When to use it
- When you need to integrate custom messaging or automation into Zoom Team Chat.
- When designing interactive chatbot workflows with buttons, forms, or dropdowns.
- When setting up OAuth authentication for Zoom-based applications.
- When troubleshooting connectivity or message delivery issues in a Zoom integration.
Advantages
- Provides a clear, step-by-step path for Zoom app development.
- Ensures security best practices like signature verification are prioritized.
- Helps avoid common pitfalls in API selection and message formatting.
- Centralizes references for environment variables and API endpoints.
Usage examples
- “How do I start building a chatbot for Zoom Team Chat?”
- The agent will guide you through choosing the Chatbot API, configuring the bot identity, and setting up the necessary OAuth and webhook infrastructure.
- “I am getting an invalid access token error when sending messages.”
- The agent will help you verify your app type, check if the required scopes are enabled, and confirm if the user has re-consented after recent scope changes.
Install
Download the skill as a ZIP:
https://autogineer.com/agent-skills/openai/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
Use this skill when the target surface is Zoom Team Chat. First decide whether the integration is user-scoped messaging, a chatbot, an interactive message-card workflow, or a webhook-driven automation.
Workflow
Choose the API surface: Team Chat API for user-scoped actions, Chatbot API for bot identity and chatbot workflows.
Confirm app type, scopes, role enablement, and whether the account has Zoom for Developers enabled.
Model message structure before coding: plain messages, rich cards, buttons, dropdowns, forms, slash commands, and threaded replies.
Implement OAuth and token refresh separately from message sending, with clear storage boundaries.
Add webhook handlers for interactivity and lifecycle events with signature verification and retry-safe processing.
Debug by checking JID formats, channel membership, bot installation, scopes, role settings, and message-card payload shape.
References
Full preserved guide: references/full-guide.md
API selection: concepts/api-selection.md
Message structure: concepts/message-structure.md
Message cards: references/message-cards.md
Scopes: references/scopes.md
Chatbot setup: examples/chatbot-setup.md
Common issues: troubleshooting/common-issues.md
Files
- ATTRIBUTION.mdAdded by AutoGineer880 B
- LICENSELicence file added by AutoGineer1.1 KiB
- RUNBOOK.md2.7 KiB
- SKILL.md1.5 KiB
- agents/openai.yaml145 B
- concepts/api-selection.md7.3 KiB
- concepts/authentication.md1.4 KiB
- concepts/deployment.md719 B
- concepts/environment-setup.md8.8 KiB
- concepts/message-structure.md675 B
- concepts/security.md478 B
- concepts/webhooks.md11.8 KiB
- examples/button-actions.md393 B
- examples/channel-management.md320 B
- examples/chatbot-setup.md12.2 KiB
- examples/database-integration.md312 B
- examples/dropdown-selects.md304 B
- examples/form-submissions.md385 B
- examples/llm-integration.md532 B
- examples/multi-step-workflows.md300 B
- examples/oauth-setup.md1.6 KiB
- examples/scheduled-alerts.md352 B
- examples/send-message.md417 B
- examples/slash-commands.md509 B
- examples/token-management.md442 B
- get-started.md1.6 KiB
- references/api-reference.md538 B
- references/environment-variables.md1006 B
- references/error-codes.md448 B
- references/full-guide.md22.9 KiB
- references/jid-formats.md247 B
- references/message-cards.md6.6 KiB
- references/rate-limits.md205 B
- references/sample-comparison.md1.1 KiB
- references/samples.md14.2 KiB
- references/scopes.md340 B
- references/webhook-events.md564 B
- troubleshooting/common-issues.md9.7 KiB
- troubleshooting/deployment-issues.md641 B
- troubleshooting/message-issues.md317 B
- troubleshooting/oauth-issues.md882 B
- troubleshooting/webhook-issues.md364 B
troubleshooting/common-issues.md
Common Issues and Solutions
Quick diagnostics and solutions for Zoom Team Chat development.
Authentication Issues
"Invalid client_id or client_secret"
Cause: Incorrect credentials or using wrong environment (dev vs production)
Solution:
Verify credentials in
.envmatch Zoom MarketplaceCheck you're using Development credentials (not Production)
Regenerate Client Secret if needed
"Get Bot Token" returns 404 or HTML page
Cause: Using wrong token endpoint.
Fix:
Use
https://zoom.us/oauth/tokenfor token exchange.Do not use
https://zoom.us/oauth/tokenfor chatbot token requests.
Quick check:
curl -X POST https://zoom.us/oauth/token \
-H "Authorization: Basic <base64(client_id:client_secret)>" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials""Token expired"
Cause: Access token has expired (1 hour for user tokens)
Solution:
// Implement token refresh
if (error.message.includes('token expired')) {
const newToken = await refreshAccessToken(refreshToken);
// Retry request with new token
}"Scope not authorized"
Cause: Missing required scope in app configuration
Solution:
Go to Zoom Marketplace → Your App → Scopes
Add missing scope (e.g.,
chat_message:write)Users must re-authorize the app
Webhook Issues
"Cannot GET /webhook" (Browser)
Expected Behavior: This is NORMAL
Explanation: Webhooks are POST-only. Browsers send GET requests.
Test properly:
WEBHOOK_BASE_URL="http://YOUR_DEV_HOST:4000"
# Use POST instead
curl -X POST "$WEBHOOK_BASE_URL/webhook" \
-H "Content-Type: application/json" \
-d '{"event":"test"}'"Invalid webhook signature"
Cause: Mismatch between your Secret Token and Zoom's
Solution:
Verify
ZOOM_VERIFICATION_TOKENin.envCheck Secret Token in Zoom Marketplace → Features → Team Chat Subscriptions
Ensure no extra spaces/characters in token
Debug:
console.log('Expected token:', process.env.ZOOM_VERIFICATION_TOKEN);
console.log('Signature from Zoom:', req.headers['x-zm-signature']);URL Validation Fails
Cause: Incorrect response format
Correct response:
{
"plainToken": "xyz123",
"encryptedToken": "hmac_sha256_hash"
}Incorrect:
{ "success": true } // Wrong!No Webhooks Received
Checklist:
[ ] ngrok is running:
ngrok http 4000[ ] Bot Endpoint URL in Zoom Marketplace matches ngrok URL
[ ] Server is running:
node server.js[ ] Slash command configured in Zoom Marketplace
[ ] Bot installed in your account
Test:
# In Zoom Team Chat, type:
/yourbot test
# Should see webhook in server logsBot JID Issues
"Bot JID not found"
Cause: Chatbot feature not enabled
Solution:
Go to Zoom Marketplace → Your App → Features
Toggle Chatbot ON
Bot JID will appear in Bot Credentials section
"Bot JID appears but messages not sending"
Cause: Wrong Bot JID format or environment mismatch
Solution:
Verify format:
[email protected]Use Development Bot JID for testing
Check Account ID matches the bot's account
Message Sending Issues
"Messages not appearing in Team Chat"
Common causes:
Wrong
to_jid// Use toJid from webhook payload await sendMessage(payload.toJid, accountId, content);Missing
account_id// Required for chatbot messages { "account_id": process.env.ZOOM_ACCOUNT_ID, // Don't forget! "robot_jid": process.env.ZOOM_BOT_JID, "to_jid": toJid }Incorrect content format
// ❌ Wrong { "text": "Hello" } // ✅ Correct { "content": { "body": [ { "type": "message", "text": "Hello" } ] } }
"Message truncated or garbled"
Cause: Special characters or exceeding 4096 char limit
Solution:
function sanitizeMessage(message) {
return message
.trim()
.replace(/[\x00-\x1F\x7F]/g, '') // Remove control chars
.substring(0, 4096); // Enforce limit
}Button/Form Issues
"Buttons not clickable"
Cause: Missing value field
Incorrect:
{
"type": "actions",
"items": [
{ "text": "Click Me" } // Missing value!
]
}Correct:
{
"type": "actions",
"items": [
{ "text": "Click Me", "value": "clicked" }
]
}"Button clicks not triggering webhooks"
Checklist:
[ ] Webhook handler has
interactive_message_actionscase[ ] Bot Endpoint URL configured correctly
[ ] Server responding with 200 status
[ ] Webhook signature verification passing
ngrok Issues
"ngrok session expired"
Cause: Free ngrok URLs expire after 2 hours
Solutions:
Short-term: Restart ngrok, update Bot Endpoint URL
Long-term: Use ngrok paid plan or deploy to production
"ngrok URL changes every restart"
Free plan behavior: URL changes each time
Solutions:
Use ngrok auth token for persistent URLs (paid)
Use environment variable for flexibility:
const WEBHOOK_URL = process.env.WEBHOOK_URL || 'https://YOUR_PUBLIC_WEBHOOK_URL/webhook';
Deployment Issues
"Works locally but not in production"
Common causes:
Environment variables not set
# Verify all vars exist echo $ZOOM_CLIENT_ID echo $ZOOM_CLIENT_SECRET echo $ZOOM_BOT_JIDHTTP instead of HTTPS
Production MUST use HTTPS
Zoom rejects HTTP endpoints
Port binding issues
// Use PORT from environment const PORT = process.env.PORT || 4000;Credentials exist, but wrong
.envfile is loadedIf your app keeps per-mode env files (for example
project/team-chat-api/.envandproject/chatbot-api/.env), make sure runtime loads those files explicitly.Verify loaded config via a health/config endpoint before debugging OAuth logic.
404 on /team-chat/api/channel/*
Cause: Route mismatch between old and new demo structure.
Fix:
New pages should use:
/team-chat/user-demo/team-chat/bot-demo
Keep compatibility routes in backend if older UI still calls:
/api/channel/list/api/channel/messages/api/channel/message
Browser shows ERR_BLOCKED_BY_CLIENT
Cause: Browser extension/adblock/privacy filter blocked a request.
What to do:
Test in Incognito or with extensions disabled for your host.
Confirm backend route with
curlbefore treating this as server failure.
Rate Limiting
"Rate limit exceeded"
Zoom Limits:
10 requests/second per user
100 requests/second per app
Solution:
// Implement exponential backoff
async function retryWithBackoff(fn, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await fn();
} catch (error) {
if (error.status === 429) {
const delay = Math.pow(2, i) * 1000;
await new Promise(resolve => setTimeout(resolve, delay));
} else {
throw error;
}
}
}
throw new Error('Max retries exceeded');
}General App Issues
"App not appearing in Team Chat"
Cause: Team Chat surface not enabled
Solution:
Go to Zoom Marketplace → Your App → Features → Surface
Check Team Chat
Configure Home URL and Domain Allow List
Save changes
"Users can't install the app"
Cause: App not in Local Test or not published
Solutions:
For testing: Go to Local Test → Generate Authorization URL → Share with team
For production: Submit app for Zoom review and publish
Debugging Tools
Log All Webhooks
app.post('/webhook', (req, res) => {
console.log('=== Webhook Received ===');
console.log('Event:', req.body.event);
console.log('Payload:', JSON.stringify(req.body.payload, null, 2));
console.log('Headers:', req.headers);
// ... handle webhook
});Test Token Generation
// Test script: test-token.js
require('dotenv').config();
const { getChatbotToken } = require('./utils/auth');
(async () => {
try {
const token = await getChatbotToken();
console.log('✅ Token generated successfully');
console.log('Token:', token.substring(0, 20) + '...');
} catch (error) {
console.error('❌ Token error:', error.message);
}
})();Verify Credentials
// verify-setup.js
require('dotenv').config();
const required = [
'ZOOM_CLIENT_ID',
'ZOOM_CLIENT_SECRET',
'ZOOM_BOT_JID',
'ZOOM_VERIFICATION_TOKEN',
'ZOOM_ACCOUNT_ID'
];
console.log('=== Credential Check ===');
required.forEach(key => {
const value = process.env[key];
if (!value) {
console.error(`❌ Missing: ${key}`);
} else {
console.log(`✅ ${key}: ${value.substring(0, 10)}...`);
}
});Getting Help
Before Asking for Help
Check error messages in console/logs
Verify all credentials are correct
Test with curl or Postman
Review official samples
Where to Get Help
Include in Support Requests
Zoom app type (General App OAuth)
Error message (full text)
Code snippet (sanitized - no credentials!)
Steps to reproduce
Expected vs actual behavior
Next Steps
Webhook Architecture - Deep dive into webhooks
Chatbot Setup - Complete working example
API Reference - Endpoint documentation
Requirements and compatibility
Written for: OpenAI Codex
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.
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
- OpenAI (Official)
- Distributed by
- OpenAI
- Source
- openai/plugins · plugins/zoom/skills/team-chat · commit d420d13
- Licence
- MIT License (redistribution allowed)
- LICENSE (added by AutoGineer from plugins/zoom/LICENSE)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by Zoom or OpenAI.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download build-zoom-team-chat-app.zip