HTTP Status Codes
| Status Code | Meaning | Action |
|---|
| 200 | OK | Request succeeded |
| 201 | Created | Resource created successfully |
| 400 | Bad Request | Fix request parameters or body |
| 401 | Unauthorized | Check API token or credentials |
| 403 | Forbidden | Account suspended or insufficient permissions |
| 404 | Not Found | Resource does not exist |
| 429 | Rate Limited | Slow down, retry after X-RateLimit-Reset |
| 500 | Internal Error | Server error, retry with exponential backoff |
All errors return a JSON object with a human-readable message:
{
"error": "to, from, and body are required"
}
Common Errors
| Error Message | Cause | Solution |
|---|
to, from, and body are required | Missing required fields in request | Include all required parameters |
invalid username or password | Authentication failed | Verify credentials or API token |
account is not active | Account suspended or disabled | Contact support to reactivate account |
pipeline processing failed | Routing or billing configuration issue | Check gateway and billing settings |
invalid phone number format | Phone number not in E.164 format | Use format: +[country_code][number] |
insufficient balance | Account balance too low | Add credits to your account |
rate limit exceeded | Too many requests | Wait for reset or upgrade rate limit |
Message-Level Errors
Some requests succeed with HTTP 200 but individual messages may fail. Check the error_code and error_message fields on each Message object.
Example: Bulk send with partial failures
{
"messages": [
{
"id": "msg_abc123",
"to": "+8801712345678",
"status": "delivered",
"error_code": null,
"error_message": null
},
{
"id": "msg_def456",
"to": "+1234567890",
"status": "failed",
"error_code": "INVALID_NUMBER",
"error_message": "Phone number is invalid or unreachable"
}
]
}
Error Code Categories
Search for specific error codes to understand failure reasons:
curl -X GET "https://api-message.nativehub.live/api/v1/error-codes/search?q=invalid" \
-H "Authorization: Bearer YOUR_API_TOKEN"
const response = await fetch(
'https://api-message.nativehub.live/api/v1/error-codes/search?q=invalid',
{
headers: {
'Authorization': 'Bearer YOUR_API_TOKEN'
}
}
);
const errorCodes = await response.json();
console.log(errorCodes);
response = requests.get(
'https://api-message.nativehub.live/api/v1/error-codes/search',
headers={'Authorization': 'Bearer YOUR_API_TOKEN'},
params={'q': 'invalid'}
)
error_codes = response.json()
print(error_codes)
Common error code patterns:
| Code Pattern | Category | Examples |
|---|
INVALID_* | Validation failures | INVALID_NUMBER, INVALID_FORMAT |
INSUFFICIENT_* | Resource limitations | INSUFFICIENT_BALANCE, INSUFFICIENT_PERMISSIONS |
CARRIER_* | Carrier/network issues | CARRIER_REJECTED, CARRIER_TIMEOUT |
BLOCKED_* | Spam/compliance blocks | BLOCKED_SPAM, BLOCKED_OPTED_OUT |
Retry Strategies
Do NOT retry client errors (400, 401, 403, 404). These indicate problems with your request that will not resolve automatically.
Retry these status codes:
- 429 Rate Limited: Wait until
X-RateLimit-Reset timestamp, then retry
- 500 Internal Error: Exponential backoff (1s, 2s, 4s, 8s…)
- 503 Service Unavailable: Exponential backoff
Implementation example:
async function sendWithRetry(message, maxRetries = 3) {
let delay = 1000; // Start with 1 second
for (let attempt = 0; attempt < maxRetries; attempt++) {
const response = await fetch('https://api-message.nativehub.live/api/v1/messages', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_TOKEN',
'Content-Type': 'application/json'
},
body: JSON.stringify(message)
});
if (response.ok) {
return await response.json();
}
// Don't retry client errors
if (response.status >= 400 && response.status < 500 && response.status !== 429) {
const error = await response.json();
throw new Error(error.error);
}
// Retry with exponential backoff for 429 and 5xx
if (response.status === 429 || response.status >= 500) {
if (attempt < maxRetries - 1) {
await new Promise(resolve => setTimeout(resolve, delay));
delay *= 2; // Exponential backoff
continue;
}
}
throw new Error(`Request failed with status ${response.status}`);
}
}
import time
import requests
def send_with_retry(message, max_retries=3):
delay = 1 # Start with 1 second
for attempt in range(max_retries):
response = requests.post(
'https://api-message.nativehub.live/api/v1/messages',
headers={
'Authorization': 'Bearer YOUR_API_TOKEN',
'Content-Type': 'application/json'
},
json=message
)
if response.ok:
return response.json()
# Don't retry client errors
if 400 <= response.status_code < 500 and response.status_code != 429:
raise Exception(response.json()['error'])
# Retry with exponential backoff for 429 and 5xx
if response.status_code == 429 or response.status_code >= 500:
if attempt < max_retries - 1:
time.sleep(delay)
delay *= 2 # Exponential backoff
continue
raise Exception(f'Request failed with status {response.status_code}')
Idempotency
Prevent duplicate message sends by using the batch_id parameter for deduplication:
const batchId = crypto.randomUUID();
const response = await fetch('https://api-message.nativehub.live/api/v1/messages', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_TOKEN',
'Content-Type': 'application/json'
},
body: JSON.stringify({
from: '+8801712345678',
to: '+8801812345679',
body: 'Your OTP is 123456',
batch_id: batchId // Same batch_id will deduplicate
})
});
Messages with identical batch_id values sent within 24 hours are treated as duplicates and only processed once.
Debugging Checklist
When troubleshooting API errors:
- Check HTTP status code category (4xx vs 5xx)
- Read the
error field in the response body
- For message-level failures, check
error_code and error_message
- Search error codes via
/error-codes/search
- Verify phone numbers are in E.164 format
- Check account balance and active status
- Review rate limit headers
- Test with a known-good number (e.g., your own phone)