7.2 KiB
Testing & Development Environment
Set up development and testing environments for Zoom integrations.
Overview
Zoom provides several options for development and testing:
- Development app credentials (separate from production)
- Test accounts
- Local webhook testing tools
- SDK sandbox modes
Skills Needed
- general - App configuration
- webhooks - Webhook testing
Development vs Production Apps
Create Separate Apps
Always create separate apps for development and production:
| Environment | Purpose | Credentials |
|---|---|---|
| Development | Testing, debugging | Dev Client ID/Secret |
| Production | Live users | Prod Client ID/Secret |
- Go to Zoom Marketplace
- Create "MyApp - Development" for testing
- Create "MyApp - Production" for live deployment
- Use environment variables to switch between them
// .env.development
ZOOM_CLIENT_ID=dev_client_id_here
ZOOM_CLIENT_SECRET=dev_secret_here
ZOOM_ACCOUNT_ID=dev_account_id
// .env.production
ZOOM_CLIENT_ID=prod_client_id_here
ZOOM_CLIENT_SECRET=prod_secret_here
ZOOM_ACCOUNT_ID=prod_account_id
Test Accounts
Option 1: Developer Account
Use your own Zoom account for initial development:
- Free tier works for basic API testing
- Pro account needed for SDK testing
- Create test meetings manually
Option 2: Zoom Developer Sandbox (ISV Partners)
ISV partners can request sandbox accounts:
- Contact Zoom partnership team
- Isolated test environment
- Multiple test users
Option 3: Programmatic Test Users
Create test users via API (requires admin account):
// Create a test user
const response = await axios.post(
'https://api.zoom.us/v2/users',
{
action: 'create',
user_info: {
email: 'testuser+1@yourcompany.com', // Use + alias
type: 1, // Basic user
first_name: 'Test',
last_name: 'User'
}
},
{ headers: { 'Authorization': `Bearer ${accessToken}` }}
);
Tip: Use email aliases (testuser+1@company.com, testuser+2@company.com) that all route to one inbox.
Local Webhook Testing
Option 1: ngrok (Recommended)
Expose your local development webhook server to the internet for testing:
# Install ngrok
npm install -g ngrok
# Start your local server
node server.js # Running on port 3000
# In another terminal, create tunnel
ngrok http 3000
Output:
Forwarding https://abc123.ngrok.io -> http://YOUR_DEV_HOST:3000
Use https://abc123.ngrok.io/webhook as your webhook URL in Zoom Marketplace.
Option 2: Cloudflare Tunnel
# Install cloudflared
brew install cloudflare/cloudflare/cloudflared
# Create tunnel
LOCAL_WEBHOOK_BASE_URL="http://YOUR_DEV_HOST:3000"
cloudflared tunnel --url "$LOCAL_WEBHOOK_BASE_URL"
Option 3: localtunnel
npm install -g localtunnel
lt --port 3000
Webhook URL Validation
Zoom requires validating your webhook endpoint. Your server must respond to the challenge:
app.post('/webhook', (req, res) => {
// Handle Zoom's endpoint validation
if (req.body.event === 'endpoint.url_validation') {
const hashForValidate = crypto
.createHmac('sha256', ZOOM_WEBHOOK_SECRET)
.update(req.body.payload.plainToken)
.digest('hex');
return res.json({
plainToken: req.body.payload.plainToken,
encryptedToken: hashForValidate
});
}
// Handle actual events
// ...
});
SDK Development Mode
Meeting SDK Web
Enable debug logging:
const client = ZoomMtgEmbedded.createClient();
client.init({
debug: true, // Enable debug logs
zoomAppRoot: document.getElementById('meetingSDKElement'),
language: 'en-US',
});
Video SDK Web
const client = ZoomVideo.createClient();
await client.init('en-US', 'CDN', {
enforceMultipleVideos: true,
stayAwake: true,
patchJsMedia: true,
leaveOnPageUnload: true,
});
// Enable debug mode
ZoomVideo.setLogLevel('debug');
Native SDKs (iOS/Android/Desktop)
Enable verbose logging:
// iOS
let initParams = ZoomVideoSDKInitParams()
initParams.enableLog = true
initParams.logFilePrefix = "videosdk_debug"
// Android
val initParams = ZoomVideoSDKInitParams().apply {
enableLog = true
logFilePrefix = "videosdk_debug"
}
Mock Webhook Events
Manual Testing with curl
Test your webhook handler locally:
LOCAL_WEBHOOK_BASE_URL="http://YOUR_DEV_HOST:3000"
# Simulate meeting.started event
curl -X POST "$LOCAL_WEBHOOK_BASE_URL/webhook" \
-H "Content-Type: application/json" \
-H "x-zm-signature: v0=test" \
-H "x-zm-request-timestamp: $(date +%s)" \
-d '{
"event": "meeting.started",
"payload": {
"account_id": "abc123",
"object": {
"id": "123456789",
"uuid": "abcd-1234-efgh",
"topic": "Test Meeting",
"host_id": "xyz789"
}
}
}'
Webhook Replay Tool
Build a simple replay tool for testing:
const fs = require('fs');
// Save incoming webhooks to file
app.post('/webhook', (req, res) => {
const filename = `webhooks/${Date.now()}_${req.body.event}.json`;
fs.writeFileSync(filename, JSON.stringify(req.body, null, 2));
// Process normally...
});
// Replay saved webhook
async function replayWebhook(filename) {
const payload = JSON.parse(fs.readFileSync(filename));
await processWebhook(payload);
}
Testing Checklist
Before Going Live
- Test OAuth flow end-to-end
- Verify webhook signature validation
- Test with multiple user types (host, participant, admin)
- Handle rate limiting gracefully
- Test error scenarios (invalid tokens, network failures)
- Verify recording download permissions
- Test SDK on all target platforms
- Load test with expected user volume
API Testing
// Test helper for API calls
async function testAPICall(name, fn) {
console.log(`Testing: ${name}`);
try {
const result = await fn();
console.log(`Pass: ${name}`);
return result;
} catch (error) {
console.error(`Fail: ${name}:`, error.message);
throw error;
}
}
// Run tests
await testAPICall('Create meeting', () =>
createMeeting({ topic: 'Test' })
);
await testAPICall('Get meeting', () =>
getMeeting(meetingId)
);
await testAPICall('Delete meeting', () =>
deleteMeeting(meetingId)
);
Debugging Tips
Enable Request Logging
const axios = require('axios');
// Log all requests
axios.interceptors.request.use(config => {
console.log(`-> ${config.method.toUpperCase()} ${config.url}`);
return config;
});
axios.interceptors.response.use(
response => {
console.log(`<- ${response.status} ${response.config.url}`);
return response;
},
error => {
console.error(`<- ${error.response?.status} ${error.config?.url}`);
console.error('Error:', error.response?.data);
throw error;
}
);
SDK Log Collection
See SDK Logs & Troubleshooting for collecting SDK debug logs.
Resources
- ngrok: https://ngrok.com/
- Postman Collection: https://developers.zoom.us/docs/api/rest/postman/
- Developer Forum: https://devforum.zoom.us/