Reference
Error Codes
Complete reference of all error codes returned by the HMS Sovereign API with explanations and recommended actions.
This reference lists all error codes returned by the HMS Sovereign API with explanations and recommended actions.
| Code | Name | Description |
|---|
200 | OK | Request succeeded |
201 | Created | Resource created successfully |
204 | No Content | Request succeeded, no content returned (delete operations) |
| Code | Name | Description |
|---|
400 | Bad Request | Invalid request format or validation error |
401 | Unauthorized | Missing or invalid API key |
402 | Payment Required | Insufficient credits balance |
403 | Forbidden | Valid API key but no access to this resource |
404 | Not Found | Resource doesn't exist |
409 | Conflict | Resource already exists (duplicate) |
422 | Unprocessable Entity | Request understood but cannot be processed |
429 | Too Many Requests | Rate limit exceeded |
| Code | Name | Description |
|---|
500 | Internal Server Error | Unexpected server error |
502 | Bad Gateway | Upstream service unavailable |
503 | Service Unavailable | Server temporarily unavailable |
504 | Gateway Timeout | Upstream service timeout |
All errors follow this format:
{
"error": {
"code": "error_code",
"message": "Human readable message",
"param": "field_name",
"type": "error_type"
}
}
| Field | Description |
|---|
code | Machine-readable error code |
message | Human-readable description |
param | The field that caused the error (if applicable) |
type | Error category |
| Code | Message | Solution |
|---|
unauthorized | Invalid or missing API key | Check your API key is correct and included in the Authorization header |
api_key_expired | API key has expired | Generate a new API key in the dashboard |
api_key_revoked | API key has been revoked | Generate a new API key |
| Code | Message | Solution |
|---|
invalid_request | Request body is invalid | Check JSON syntax and required fields |
missing_field | Missing required field | Include all required fields |
invalid_field | Field value is invalid | Check field format (e.g., E.164 for phone numbers) |
invalid_phone_number | Phone number format invalid | Use E.164 format: +31612345678 |
invalid_uuid | Invalid UUID format | Provide a valid UUID |
invalid_url | Invalid URL format | Provide a valid HTTPS URL |
| Code | Message | Solution |
|---|
not_found | Resource not found | Verify the resource ID exists |
already_exists | Resource already exists | The phone number or resource is already registered |
conflict | Resource conflict | Another resource is using this identifier |
| Code | Message | Solution |
|---|
insufficient_credits | Insufficient credits balance | Add credits in the billing dashboard |
payment_required | Payment required | Add credits to make outbound calls |
| Code | Message | Solution |
|---|
rate_limit_exceeded | Too many requests | Wait and retry with exponential backoff |
call_control_limit | Too many call control commands | Limit to 10 commands per minute per call |
| Code | Message | Solution |
|---|
provider_error | External provider error | Check BYOK configuration and provider status |
provider_timeout | Provider request timeout | Retry the request |
invalid_api_key | BYOK API key invalid | Update the API key via BYOK endpoint |
| Code | Message | Solution |
|---|
call_not_found | Call not found | Verify the call ID |
call_not_active | Call is not in-progress | Call control only works on active calls |
invalid_destination | Invalid destination number | Check phone number format |
async function callApi(endpoint, options = {}) {
const response = await fetch(`https://api.hmsovereign.com/api/v1${endpoint}`, {
...options,
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
...options.headers
}
});
if (!response.ok) {
const error = await response.json();
switch (response.status) {
case 401:
throw new Error('Invalid API key. Check your credentials.');
case 402:
throw new Error('Insufficient credits. Add credits to continue.');
case 404:
throw new Error(`Resource not found: ${error.error?.message}`);
case 429:
// Implement retry with backoff
const retryAfter = response.headers.get('Retry-After') || 60;
throw new Error(`Rate limited. Retry after ${retryAfter} seconds.`);
default:
throw new Error(error.error?.message || 'Unknown error');
}
}
return response.json();
}
For transient errors (429, 502, 503, 504), implement exponential backoff:
async function retryWithBackoff(fn, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await fn();
} catch (error) {
if (i === maxRetries - 1) throw error;
const delay = Math.min(1000 * Math.pow(2, i), 30000);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}