Error Handling
Understanding and handling errors in the WhatsApp API.
HTTP Status Codes
| Code | Status | Description |
|---|---|---|
200 | OK | Request successful |
201 | Created | Resource created successfully |
400 | Bad Request | Invalid parameters or malformed request |
401 | Unauthorized | Missing or invalid API key |
403 | Forbidden | API key doesn't have access to this resource |
404 | Not Found | Session or resource not found |
429 | Too Many Requests | Rate limit exceeded |
500 | Internal Server Error | Server error |
503 | Service Unavailable | Service temporarily unavailable |
Error Response Format
All errors follow this format:
{
"success": false,
"error": "Error message describing what went wrong"
}
Some errors include additional fields:
{
"success": false,
"error": "Rate limit exceeded",
"retryAfter": 60
}
Common Errors
Authentication Errors
Missing API Key
{
"success": false,
"error": "API key required. Please provide an API key via X-API-Key header, Authorization header, or api_key query parameter."
}
Solution: Include API key in request headers.
curl -H "X-API-Key: wask_your_key" http://localhost:3000/sessions/{id}/status
Invalid API Key
{
"success": false,
"error": "Invalid API key"
}
Solution: Verify your API key is correct and active.
Wrong Session Access
{
"success": false,
"error": "This API key can only access its own session"
}
Solution: Use the correct API key for the session, or use an admin key.
Session Errors
Session Not Found
{
"success": false,
"error": "Session not found"
}
Solution: Verify the session ID is correct and the session exists.
Session Not Authenticated
{
"success": false,
"error": "Session not authenticated. Please scan the QR code first using GET /sessions/{id}/qr"
}
Solution: Scan the QR code to authenticate the session.
Session Still Connecting
{
"success": false,
"error": "Session is still connecting. Please wait."
}
Solution: Wait a few seconds and retry.
QR Code Not Ready
{
"success": false,
"error": "QR code not available yet. Session state: starting"
}
Solution: Wait for session state to become qr_ready.
Message Errors
Invalid Phone Number
{
"success": false,
"error": "Invalid phone number format"
}
Solution: Use correct format with country code (e.g., 919876543210).
Number Not on WhatsApp
{
"success": false,
"error": "Number is not registered on WhatsApp"
}
Solution: Verify the number is active on WhatsApp using /check-number endpoint.
Message Too Long
{
"success": false,
"error": "Message text exceeds maximum length"
}
Solution: Split long messages into multiple parts.
Rate Limit Errors
Rate Limit Exceeded
{
"success": false,
"error": "Rate limit exceeded. Please wait 45 seconds before trying again.",
"retryAfter": 45
}
Solution: Wait for the specified time before retrying.
QR Polling Too Fast
{
"success": false,
"error": "Please wait 5 seconds before requesting QR again"
}
Solution: Add delay between QR code requests.
Trial Key Errors
Trial Expired
{
"success": false,
"error": "Trial period has expired"
}
Solution: Convert to paid key or request trial extension.
Number Not Allowed
{
"success": false,
"error": "Trial key can only send to allowed numbers: +919876543210"
}
Solution: Send only to allowed numbers or upgrade to standard key.
Media Errors
Invalid Media URL
{
"success": false,
"error": "Failed to download media from URL"
}
Solution: Verify URL is accessible and returns valid media.
Media Too Large
{
"success": false,
"error": "Media file size exceeds maximum allowed (16MB)"
}
Solution: Compress or resize media before sending.
Error Handling Examples
PHP
<?php
try {
$result = $whatsapp->sendText('919876543210', 'Hello!');
echo "Message sent: " . $result['messageId'];
} catch (Exception $e) {
$error = $e->getMessage();
if (strpos($error, 'Rate limit') !== false) {
// Handle rate limit
error_log("Rate limited, will retry later");
// Add to queue for retry
} elseif (strpos($error, 'not authenticated') !== false) {
// Session needs authentication
error_log("Session not authenticated, please scan QR");
} elseif (strpos($error, 'not found') !== false) {
// Session doesn't exist
error_log("Session not found");
} else {
// Other errors
error_log("Error: " . $error);
}
}
Node.js
try {
const result = await whatsapp.sendText('919876543210', 'Hello!');
console.log('Message sent:', result.messageId);
} catch (error) {
const errorMsg = error.message;
if (errorMsg.includes('Rate limit')) {
// Handle rate limit
console.log('Rate limited, will retry later');
// Add to queue for retry
} else if (errorMsg.includes('not authenticated')) {
// Session needs authentication
console.log('Session not authenticated, please scan QR');
} else if (errorMsg.includes('not found')) {
// Session doesn't exist
console.log('Session not found');
} else {
// Other errors
console.error('Error:', errorMsg);
}
}
Python
try:
result = whatsapp.send_text('919876543210', 'Hello!')
print(f"Message sent: {result['messageId']}")
except Exception as e:
error_msg = str(e)
if 'Rate limit' in error_msg:
# Handle rate limit
print('Rate limited, will retry later')
# Add to queue for retry
elif 'not authenticated' in error_msg:
# Session needs authentication
print('Session not authenticated, please scan QR')
elif 'not found' in error_msg:
# Session doesn't exist
print('Session not found')
else:
# Other errors
print(f"Error: {error_msg}")
Retry Strategies
Exponential Backoff
async function sendWithRetry(whatsapp, to, message, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await whatsapp.sendText(to, message);
} catch (error) {
const isLastAttempt = attempt === maxRetries - 1;
const isRetryable = error.message.includes('Rate limit') ||
error.message.includes('still connecting');
if (isRetryable && !isLastAttempt) {
const delay = Math.pow(2, attempt) * 1000; // 1s, 2s, 4s
console.log(`Retry ${attempt + 1}/${maxRetries} after ${delay}ms`);
await new Promise(resolve => setTimeout(resolve, delay));
} else {
throw error;
}
}
}
}
Conditional Retry
import time
def should_retry(error):
"""Determine if error is retryable"""
retryable_errors = [
'Rate limit',
'still connecting',
'temporarily unavailable',
'timeout'
]
return any(err in str(error) for err in retryable_errors)
def send_with_retry(whatsapp, to, message, max_retries=3):
for attempt in range(max_retries):
try:
return whatsapp.send_text(to, message)
except Exception as e:
if should_retry(e) and attempt < max_retries - 1:
delay = 2 ** attempt
print(f"Retry {attempt + 1}/{max_retries} after {delay}s")
time.sleep(delay)
else:
raise
Error Logging
Structured Logging
const winston = require('winston');
const logger = winston.createLogger({
level: 'info',
format: winston.format.json(),
transports: [
new winston.transports.File({ filename: 'error.log', level: 'error' }),
new winston.transports.File({ filename: 'combined.log' })
]
});
try {
await whatsapp.sendText(to, message);
} catch (error) {
logger.error('Failed to send message', {
to,
error: error.message,
timestamp: new Date().toISOString(),
sessionId: whatsapp.sessionId
});
}
Error Monitoring
<?php
class ErrorMonitor {
private $errors = [];
public function recordError($type, $message, $context = []) {
$this->errors[] = [
'type' => $type,
'message' => $message,
'context' => $context,
'timestamp' => date('c')
];
// Send to monitoring service (e.g., Sentry)
$this->sendToMonitoring($type, $message, $context);
}
public function getErrorStats() {
$stats = [];
foreach ($this->errors as $error) {
$type = $error['type'];
$stats[$type] = ($stats[$type] ?? 0) + 1;
}
return $stats;
}
private function sendToMonitoring($type, $message, $context) {
// Send to Sentry, Rollbar, etc.
}
}
Validation
Pre-Send Validation
class MessageValidator {
static validate(to, message) {
const errors = [];
// Validate phone number
if (!/^\d{10,15}$/.test(to.replace(/[+\s-]/g, ''))) {
errors.push('Invalid phone number format');
}
// Validate message length
if (message.length > 4096) {
errors.push('Message exceeds maximum length (4096 characters)');
}
// Validate message not empty
if (!message.trim()) {
errors.push('Message cannot be empty');
}
return {
valid: errors.length === 0,
errors
};
}
}
// Usage
const validation = MessageValidator.validate(to, message);
if (!validation.valid) {
console.error('Validation errors:', validation.errors);
return;
}
await whatsapp.sendText(to, message);
Debugging Tips
Enable Verbose Logging
const axios = require('axios');
// Log all requests
axios.interceptors.request.use(request => {
console.log('Request:', {
method: request.method,
url: request.url,
data: request.data
});
return request;
});
// Log all responses
axios.interceptors.response.use(
response => {
console.log('Response:', response.data);
return response;
},
error => {
console.error('Error:', {
status: error.response?.status,
data: error.response?.data
});
return Promise.reject(error);
}
);
Check Session State
def ensure_session_ready(whatsapp, max_wait=60):
"""Wait for session to be ready"""
import time
start = time.time()
while time.time() - start < max_wait:
status = whatsapp.get_status()
state = status['session']['state']
if state == 'ready':
return True
elif state in ['failed', 'logged_out']:
raise Exception(f"Session in {state} state")
print(f"Session state: {state}, waiting...")
time.sleep(5)
raise Exception("Session not ready after timeout")
# Usage
ensure_session_ready(whatsapp)
result = whatsapp.send_text('919876543210', 'Hello!')
Best Practices
- Always Handle Errors - Never ignore exceptions
- Implement Retries - For transient errors
- Log Errors - For debugging and monitoring
- Validate Input - Before making API calls
- Check Session State - Before sending messages
- Monitor Rate Limits - To avoid hitting limits
- Use Timeouts - Prevent hanging requests
- Graceful Degradation - Have fallback options