Errors
The API uses standard HTTP status codes and returns a consistent JSON error format.
All error responses follow this structure:
{
"success": false,
"error": {
"code": "NOT_FOUND",
"message": "Equipment not found"
}
}
| Field | Type | Description |
|---|
success | false | Always false for errors |
error.code | string | Machine-readable error code |
error.message | string | Human-readable description |
Status codes
| Status | Code | Meaning |
|---|
400 | BAD_REQUEST | Invalid request parameters or body |
401 | UNAUTHORIZED | Missing or invalid API key |
403 | FORBIDDEN | Valid key but insufficient scopes |
404 | NOT_FOUND | Resource doesn’t exist or isn’t accessible |
429 | RATE_LIMITED | Too many requests — see Rate Limiting |
500 | INTERNAL_ERROR | Unexpected server error |
For security, requesting a resource that exists but belongs to another organization returns 404 (not 403). This prevents ID enumeration attacks.
Handling errors
const response = await fetch('https://api.dronelist.io/v1/equipment/eq_abc123', {
headers: { 'X-API-Key': 'dl_your_key_here' }
});
if (!response.ok) {
const error = await response.json();
switch (response.status) {
case 401:
// Invalid or expired API key
throw new Error('Authentication failed');
case 403:
// Key lacks required scope
throw new Error(`Insufficient permissions: ${error.error.message}`);
case 404:
// Resource not found
return null;
case 429:
// Rate limited — retry after reset
const resetAt = Number(response.headers.get('X-RateLimit-Reset'));
// ... wait and retry
break;
default:
throw new Error(`API error: ${error.error.message}`);
}
}
const data = await response.json();
Tips
- Always check
success in the response body, not just the HTTP status
- Log the full error response in production for debugging
- Implement retries for
429 and 5xx errors with exponential backoff
- Don’t retry
400, 401, 403, or 404 errors — they require code or configuration changes