12 KiB
12 KiB
Common Errors - HTTP Status Codes and Zoom Error Codes
Complete reference for Zoom REST API error codes, HTTP status codes, and solutions.
HTTP Status Codes
2XX - Success
| 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 |
4XX - Client Errors
| 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 |
5XX - Server Errors
| 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, retry later |
Zoom Error Codes
When an API call fails, Zoom returns an error response:
{
"code": 300,
"message": "Request Body should be a valid JSON object."
}
Common Zoom Error Codes
| 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 |
Detailed Error Scenarios
401 Unauthorized
Scenario 1: Token Expired
{
"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;
}
}
Scenario 2: Missing/Invalid Token
{
"code": 200,
"message": "Invalid credentials."
}
Solution:
- Check
Authorizationheader is present:Authorization: Bearer ACCESS_TOKEN - Verify token format (should be JWT)
- Ensure token is for the correct account
Scenario 3: Missing Scopes
{
"code": 4700,
"message": "Invalid access token, does not contain scopes."
}
Solution:
- Go to your app on Zoom Marketplace
- Add required scopes (e.g.,
meeting:write:admin) - Request new access token with updated scopes
403 Forbidden
Scenario 1: Missing Permission
{
"code": 3001,
"message": "This user is not allowed to access this resource."
}
Solution:
- Verify user has appropriate role (Admin, Owner)
- Check if endpoint requires admin-level scopes
- Use account-level scope (e.g.,
meeting:write:admininstead ofmeeting:write)
Scenario 2: Shared Access Permissions
{
"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
404 Not Found
Scenario 1: User Not Found (Wrong me Usage)
{
"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}` }
});
Scenario 2: Meeting/Resource Not Found
{
"code": 300,
"message": "Meeting not found."
}
Causes:
- Meeting deleted
- Meeting expired (30 days after last use)
- Invalid meetingId
- Wrong UUID encoding
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 });
429 Too Many Requests
{
"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})`);
Validation Error Responses
Field Validation Errors
{
"code": 300,
"message": "Validation Failed.",
"errors": [
{
"field": "start_time",
"message": "Invalid field."
},
{
"field": "type",
"message": "Invalid field."
}
]
}
Solution:
- Check each field's format in API documentation
- Verify required fields are present
- Ensure data types match (number vs string)
Common Field Errors
| 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 |
Error Response Structure
Standard Error
{
"code": 300,
"message": "Descriptive error message"
}
Validation Error
{
"code": 300,
"message": "Validation Failed.",
"errors": [
{
"field": "field_name",
"message": "Error description"
}
]
}
Error Handling Best Practices
1. Parse Error Response
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();
}
2. Retry with Exponential Backoff
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);
}
}
}
3. Log Errors with Context
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);
}
4. User-Friendly Error Messages
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.';
}
Troubleshooting Checklist
Quick Diagnostic Steps
- Check HTTP status code - Indicates error category (auth, validation, server)
- Read error message - Provides specific details
- Check Zoom error code - Maps to specific issue
- Verify authentication - Token valid, scopes present
- Check rate limits - Monitor
X-RateLimit-Remainingheader - Test with Postman - Isolate code vs API issue
- Check Zoom Status - Visit status.zoom.us
Common Fixes
| 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 |
Related Documentation
- API Architecture -
mekeyword, UUID encoding, time formats - Rate Limiting Strategy - Handle 429 errors
- Authentication Flows - Token refresh patterns
- Common Issues - Practical troubleshooting