Errors
The API uses conventional HTTP status codes and returns a consistent JSON body for every error, with a human-readable message and a stable machine-readable code.
Error Format
HTTP/1.1 404 Not Found
Content-Type: application/json
{
"error": "VM not found",
"code": "NOT_FOUND"
}
Requests rejected by schema validation additionally include a
details array describing each failed field:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": "Validation error",
"code": "VALIDATION_ERROR",
"details": [
{
"path": ["name"],
"message": "Required"
}
]
} Error Codes
| HTTP Status | Code | Meaning |
|---|---|---|
| 400 | VALIDATION_ERROR | The request body or parameters are invalid. Check details if present. |
| 401 | AUTHENTICATION_ERROR | Missing, invalid, expired, or revoked API key. |
| 403 | AUTHORIZATION_ERROR | Authenticated, but not permitted to perform this action. |
| 404 | NOT_FOUND | The resource doesn't exist or belongs to a different account. |
| 409 | CONFLICT | The request conflicts with current state (e.g. duplicate name). |
| 429 | RATE_LIMIT | Too many requests. Back off and retry after Retry-After seconds. |
| 500 | INTERNAL_ERROR | Something went wrong on our side. Safe to retry with backoff. |
Individual endpoints may return more specific codes (e.g. SCRIPT_NOT_FOUND)
— always branch on the HTTP status first and treat code as a refinement.
Rate Limits
The API allows 600 requests per minute per IP, measured over a sliding window. Every response carries rate-limit headers so clients can pace themselves:
| Header | Meaning |
|---|---|
| X-RateLimit-Limit | Maximum requests allowed in the window |
| X-RateLimit-Remaining | Requests remaining in the current window |
| Retry-After | Seconds to wait before retrying (on 429 responses only) |
HTTP/1.1 429 Too Many Requests
Retry-After: 12
X-RateLimit-Limit: 600
X-RateLimit-Remaining: 0
{
"error": "Too many requests. Try again in 12s.",
"code": "RATE_LIMIT"
}