Error Handling
The Tenuo Cloud API uses conventional HTTP response codes and returns detailed error information in JSON format.
Error Response Format
All errors follow this format:
{
"error": {
"code": "error_code",
"message": "Human-readable error message",
"details": {
"field": "additional context"
}
}
}HTTP Status Codes
| Status | Description |
|---|---|
200 | Success |
201 | Created |
400 | Bad Request - Invalid parameters |
401 | Unauthorized - Invalid or missing API key |
403 | Forbidden - Insufficient scope |
404 | Not Found - Resource doesn't exist |
409 | Conflict - Resource already exists or state conflict |
422 | Unprocessable Entity - Validation error |
429 | Too Many Requests - Rate limited |
500 | Internal Server Error |
Error Codes
Authentication Errors
| Code | Status | Description |
|---|---|---|
unauthorized | 401 | Missing Authorization header |
invalid_api_key | 401 | API key is invalid or malformed |
expired_api_key | 401 | API key has expired |
revoked_api_key | 401 | API key has been revoked |
insufficient_scope | 403 | API key lacks required scope |
Validation Errors
| Code | Status | Description |
|---|---|---|
invalid_request | 400 | Request body is malformed |
missing_field | 400 | Required field is missing |
invalid_field | 422 | Field value is invalid |
invalid_id_format | 400 | ID format is invalid |
Resource Errors
| Code | Status | Description |
|---|---|---|
not_found | 404 | Resource not found |
already_exists | 409 | Resource already exists |
conflict | 409 | Operation conflicts with current state |
Key Errors
| Code | Status | Description |
|---|---|---|
key_not_found | 404 | Key does not exist |
key_revoked | 409 | Key is already revoked |
key_suspended | 409 | Key is suspended |
parent_key_required | 400 | Issuer/notary keys require a parent |
invalid_parent_key | 400 | Parent key is invalid or incompatible |
Revocation Errors
| Code | Status | Description |
|---|---|---|
revocation_not_found | 404 | Revocation does not exist |
already_revoked | 409 | Warrant is already revoked |
srl_expired | 400 | SRL has expired and needs regeneration |
Rate Limiting
| Code | Status | Description |
|---|---|---|
rate_limited | 429 | Too many requests |
Rate limit headers:
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1706123456Handling Errors
Retry Strategy
For transient errors (429, 500, 503), implement exponential backoff:
import time
import requests
def request_with_retry(url, headers, max_retries=3):
for attempt in range(max_retries):
response = requests.get(url, headers=headers)
if response.status_code == 429:
# Rate limited - wait and retry
reset_time = int(response.headers.get('X-RateLimit-Reset', 0))
wait_time = max(reset_time - time.time(), 1)
time.sleep(min(wait_time, 60))
continue
if response.status_code >= 500:
# Server error - exponential backoff
time.sleep(2 ** attempt)
continue
return response
raise Exception("Max retries exceeded")