Setting the file. One moment.
Skill 132 · Build Zoom REST API App
Subchapter 132.52
troubleshooting/common-errors.mdMarkdown12 KBView on GitHub
Complete reference for Zoom REST API error codes, HTTP status codes, and solutions.
| Status | Description | Action |
|---|---|---|
200 OK | Request succeeded | Parse response body |
201 Created | Resource created | Check Location header for new resource URL |
204 No Content | Request succeeded, no body | Common for UPDATE/DELETE operations |
| Status | Description | Common Causes | Solution |
|---|---|---|---|
400 Bad Request | Invalid request | Missing required fields, invalid JSON, validation errors | Check request body format and required fields |
401 Unauthorized | Authentication failed | Invalid/expired token, missing Authorization header | Refresh access token, check token format |
403 Forbidden | Permission denied | Missing scopes, user lacks permission, shared access not granted | Add required scopes, check user role |
404 Not Found | Resource doesn’t exist | Invalid userId/meetingId, wrong me keyword usage | Verify resource ID, check me keyword rules |
409 Conflict | Resource conflict | Email already exists, duplicate operation | Use unique identifiers |
429 Too Many Requests | Rate limit exceeded | Too many requests per second/day | Implement exponential backoff, throttle requests |
| Status | Description | Action |
|---|---|---|
500 Internal Server Error | Zoom server error | Retry with exponential backoff |
502 Bad Gateway | Gateway error | Retry after delay |
503 Service Unavailable | Zoom service down | Check status.zoom.us (opens in a new tab), retry later |
When an API call fails, Zoom returns an error response:
{
"code": 300,
"message": "Request Body should be a valid JSON object."
}| Code | HTTP | Message | Cause | Solution |
|---|---|---|---|---|
300 | 400 | Invalid request | Bad JSON, validation error | Check request body structure |
124 | 400 | Invalid parameter | Wrong parameter type/value | Validate parameters against API docs |
200 | 401 | Invalid credentials | Incorrect OAuth token | Refresh access token |
201 | 401 | Access token expired | Token expired | Request new token |
1001 | 404 | User does not exist | Invalid userId or wrong me usage | Check userId, review me keyword rules |
300 | 404 | Meeting not found | Invalid meetingId | Verify meeting exists |
3000 | 404 | Cannot access webinar info | Webinar doesn’t exist or no access | Check webinarId and scopes |
200 | 429 | Rate limit exceeded | Too many requests | Implement rate limiting |
4700 | 401 | Invalid access token | Token missing scopes | Add required scopes in app config |
3001 | 403 | Not allowed to access | Missing permission | Upgrade user role or add scope |
{
"code": 201,
"message": "Access token is expired."
}Solution:
async function apiCallWithRetry(url, options) {
try {
const response = await fetch(url, options);
if (response.status === 401) {
const error = await response.json();
if (error.code === 201) {
// Token expired - refresh and retry
const newToken = await refreshAccessToken();
options.headers['Authorization'] = `Bearer ${newToken}`;
return await fetch(url, options);
}
}
return response;
} catch (error) {
console.error('API call failed:', error);
throw error;
}
}{
"code": 200,
"message": "Invalid credentials."
}Solution:
Authorization header is present: Authorization: Bearer ACCESS_TOKEN{
"code": 4700,
"message": "Invalid access token, does not contain scopes."
}Solution:
meeting:write:admin){
"code": 3001,
"message": "This user is not allowed to access this resource."
}Solution:
meeting:write:admin instead of meeting:write){
"code": 3001,
"message": "Authenticated user has not permitted access to the targeted resource."
}Cause: User hasn’t authorized shared access permissions for your app.
Solution: Direct user to: Allowing Apps Access to Shared Access Permissions (opens in a new tab)
{
"code": 1001,
"message": "User does not exist: user@example.com"
}Cause: Using userId with User OAuth app (should use me).
Solution:
// WRONG (User OAuth app)
fetch('https://api.zoom.us/v2/users/user@example.com', {
headers: { 'Authorization': `Bearer ${userToken}` }
});
// CORRECT (User OAuth app)
fetch('https://api.zoom.us/v2/users/me', {
headers: { 'Authorization': `Bearer ${userToken}` }
});{
"code": 300,
"message": "Meeting not found."
}Causes:
Solution for UUID:
// UUID starts with / or contains // → double-encode
const uuid = '/xyzAbC123==';
const encoded = encodeURIComponent(encodeURIComponent(uuid));
fetch(`https://api.zoom.us/v2/meetings/${encoded}`, { headers });{
"code": 200,
"message": "You have reached the maximum per-second rate limit for this API."
}Solution: Implement exponential backoff
async function apiCallWithBackoff(url, options, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
const response = await fetch(url, options);
if (response.status === 429) {
const retryAfter = response.headers.get('Retry-After') || Math.pow(2, attempt);
console.log(`Rate limited. Retrying after ${retryAfter}s`);
await sleep(retryAfter * 1000);
continue;
}
return response;
}
throw new Error('Max retries exceeded');
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}Check rate limit headers:
const remaining = response.headers.get('X-RateLimit-Remaining');
const type = response.headers.get('X-RateLimit-Type');
console.log(`Rate limit remaining: ${remaining} (${type})`);{
"code": 300,
"message": "Validation Failed.",
"errors": [
{
"field": "start_time",
"message": "Invalid field."
},
{
"field": "type",
"message": "Invalid field."
}
]
}Solution:
| Field | Error | Cause | Fix |
|---|---|---|---|
start_time | Invalid field | Wrong format | Use yyyy-MM-ddTHH:mm:ssZ |
type | Invalid field | Invalid meeting type | Use 1, 2, 3, or 8 |
email | Invalid field | Invalid email format | Check email format |
duration | Invalid field | Duration too long | Max duration varies by plan |
{
"code": 300,
"message": "Descriptive error message"
}{
"code": 300,
"message": "Validation Failed.",
"errors": [
{
"field": "field_name",
"message": "Error description"
}
]
}async function handleApiResponse(response) {
if (!response.ok) {
const error = await response.json();
console.error(`API Error ${response.status}:`, error);
// Check for validation errors
if (error.errors && Array.isArray(error.errors)) {
error.errors.forEach(err => {
console.error(`- Field "${err.field}": ${err.message}`);
});
}
throw new Error(`${error.code}: ${error.message}`);
}
return await response.json();
}async function retryWithBackoff(fn, maxRetries = 3, baseDelay = 1000) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await fn();
} catch (error) {
const isRetryable = error.status >= 500 || error.status === 429;
if (!isRetryable || attempt === maxRetries) {
throw error;
}
const delay = baseDelay * Math.pow(2, attempt - 1);
const jitter = Math.random() * 1000; // Add randomness
console.log(`Retry attempt ${attempt} after ${delay + jitter}ms`);
await sleep(delay + jitter);
}
}
}function logApiError(error, context) {
const logEntry = {
timestamp: new Date().toISOString(),
status: error.status,
code: error.code,
message: error.message,
context: {
endpoint: context.endpoint,
method: context.method,
userId: context.userId
}
};
console.error('API Error:', JSON.stringify(logEntry, null, 2));
// Send to monitoring service
// monitoring.track(logEntry);
}function getUserFriendlyError(error) {
const errorMap = {
1001: 'User not found. Please check the email address.',
300: 'Invalid request. Please check your input.',
201: 'Your session has expired. Please sign in again.',
4700: 'Permission denied. Please contact your administrator.',
200: 'Too many requests. Please try again in a few moments.'
};
return errorMap[error.code] || 'An unexpected error occurred. Please try again.';
}X-RateLimit-Remaining header| Symptom | Check | Fix |
|---|---|---|
| 401 Unauthorized | Token expiry | Refresh access token |
| 404 User not found | me keyword usage | Use me for User OAuth |
| 404 Meeting not found | UUID encoding | Double-encode UUIDs starting with / |
| 403 Forbidden | Scopes | Add required scopes in app config |
| 429 Rate limit | Request rate | Implement throttling |
| 400 Validation error | Request body | Check field formats in docs |
me keyword, UUID encoding, time formats