Note
All error responses follow the same envelope shape. Your code should read the
code field to branch on specific error types rather than parsing the human-readable message.Error envelope
Every error response has this shape:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Query parameter \"q\" is required",
"status": 400
}
}
Some error codes include additional fields alongside code, message, and status:
-
KEY_SUSPENDEDincludes areasonfield explaining why the key was suspended. -
RATE_LIMITED(hard limit) includessoftLimitandhardLimitvalues. -
VALIDATION_ERRORfor unknown config types includes avalidTypesarray listing all accepted types. -
RATE_LIMIT_EXCEEDED(health check frequency) includes aretryAftervalue in seconds. -
IP_BLOCKEDincludes aretryAftervalue in seconds.
All error codes
| Code | HTTP status | Description | Common causes | Resolution |
|---|---|---|---|---|
INVALID_API_KEY |
401 | Missing, malformed, or unrecognised API key. | No Authorization header, wrong prefix, expired key. |
Check your key starts with cly_ and is sent as Bearer cly_.... |
KEY_REVOKED |
401 | API key has been permanently revoked. | Key was revoked in the Configly settings. | Generate a new key. Revocation cannot be undone. |
KEY_SUSPENDED |
403 | API key is temporarily suspended. | Hard rate limit exceeded, or manually suspended by an admin. | Reactivate the key in Configly connection settings. Review the reason field for details. |
IP_NOT_ALLOWED |
403 | Request IP not in the key's allowlist. | IP allowlisting is enabled and the request came from an unlisted address. | Add the IP to the key's allowlist, or remove the allowlist to allow any IP. |
CORS_DENIED |
403 | Browser-origin request from a disallowed domain. | Calling the API from a browser that is not the Configly application. | The API is designed for server-to-server use. Move your API calls to a backend service. |
FORBIDDEN |
403 | API key does not have access to the requested resource. | The connectionId in the request does not match the key's scoped connection. |
Use the connection ID returned by GET /v1/connections. |
WRITE_SCOPE_REQUIRED |
403 | Operation requires a read/write API key. | Using a read-only key on a mutating endpoint (POST, PUT, DELETE). | Generate a new key with read/write permission. |
RATE_LIMITED |
429 or 403 | Rate limit exceeded. | Too many requests in the current hour. 429 = soft limit; 403 = hard limit (key suspended). | Wait for the Retry-After period. See Rate limits and usage quotas for tier details. |
IP_BLOCKED |
429 | Too many failed authentication attempts from this IP. | Repeated invalid API key submissions from the same IP address. | Wait for the Retry-After period. Fix the API key in your integration. |
VALIDATION_ERROR |
400 | Request failed validation. | Missing required field, invalid parameter value, malformed JSON, unknown config type. | Check the message field for the specific validation failure. |
NOT_FOUND |
404 | Requested resource does not exist. | Invalid item ID, report ID, or version string. Also returned for subscription IDs on a different connection. | Verify the resource identifier. Use the relevant list endpoint to check for valid IDs. |
PREVIEW_REQUIRED |
400 | Must call preview before the first apply. | Calling POST /v1/apply without a preceding POST /v1/apply/preview for this API key. |
Call the preview endpoint first. See Apply changes. |
NO_SNAPSHOT |
409 | No snapshot data available. | Running a health check before the connection has been synced. | Trigger a sync first, then run the health check. |
NO_CHANGES |
400 | No virtual changes to analyse. | Calling AI analysis when no virtual changes exist for the connection. | Create virtual changes first. See Virtual changes. |
CONFLICT |
409 | Apply conflict detected. | Another apply operation is in progress, or drift was detected between the virtual change and the current Zendesk state. | Wait for the current operation to complete, then retry. Review drift warnings in the preview. |
LIMIT_EXCEEDED |
400 | Resource limit reached. | Attempting to create more than 10 webhook subscriptions per connection. | Delete unused subscriptions before creating new ones. |
REQUEST_TOO_LARGE |
413 | Request body exceeds 1 MB. | Sending an oversized payload. | Reduce the request body size. For large batch operations, split into smaller requests. |
GITHUB_ERROR |
502 | GitHub API returned an error. | GitHub is unavailable, repository permissions changed, or rate-limited by GitHub. | Retry after a short delay. If persistent, check the GitHub connection status. |
SERVICE_UNAVAILABLE |
503 | AI analysis service not configured. | AI analysis is not available on this instance. | This feature may not be enabled for your account. Contact support if you expected it to be available. |
INTERNAL_ERROR |
500 | Unexpected server error. | An unhandled error occurred. | Retry after a short delay. If the error persists, contact support with the request details. |
RATE_LIMIT_EXCEEDED |
429 | Health check frequency limit reached. | Running health checks too frequently for your subscription tier. | Wait for the retryAfter period. This is separate from the API rate limit. |
Status code summary
| Status | Meaning | Error codes |
|---|---|---|
| 400 | Bad request |
VALIDATION_ERROR, PREVIEW_REQUIRED, NO_CHANGES, LIMIT_EXCEEDED
|
| 401 | Unauthorised |
INVALID_API_KEY, KEY_REVOKED
|
| 403 | Forbidden |
KEY_SUSPENDED, IP_NOT_ALLOWED, CORS_DENIED, FORBIDDEN, WRITE_SCOPE_REQUIRED, RATE_LIMITED (hard) |
| 404 | Not found | NOT_FOUND |
| 409 | Conflict |
NO_SNAPSHOT, CONFLICT
|
| 413 | Payload too large | REQUEST_TOO_LARGE |
| 429 | Too many requests |
RATE_LIMITED (soft), IP_BLOCKED, RATE_LIMIT_EXCEEDED
|
| 500 | Internal error | INTERNAL_ERROR |
| 502 | Bad gateway | GITHUB_ERROR |
| 503 | Service unavailable | SERVICE_UNAVAILABLE |
Handling errors in code
Read the error.code field to determine the specific error type. The message field is human-readable and may change; do not parse it programmatically.
response=$(curl -s -w "\n%{http_code}" \
-H "Authorization: Bearer cly_your_key" \
https://api.configly.app/v1/connections)
http_code=$(echo "$response" | tail -1)
body=$(echo "$response" | head -1)
if [ "$http_code" -ge 400 ]; then
error_code=$(echo "$body" | jq -r '.error.code')
echo "Error: $error_code"
fi
For rate limit errors, always respect the Retry-After header rather than using a fixed delay. For full details on rate limiting behaviour, see Rate limits and usage quotas.
Comments
0 comments
Please sign in to leave a comment.