Errors
When an API request fails, Horizon returns an appropriate HTTP status code along with a JSON error body that describes what went wrong. This page documents the error format and lists common error responses.
Error Object Structure
Section titled “Error Object Structure”All error responses follow a consistent JSON format:
{ "error": "error_code", "message": "A human-readable description of what went wrong."}| Field | Type | Description |
|---|---|---|
error | string | A machine-readable error code that you can match against in your code. |
message | string | A human-readable explanation of the error, suitable for logging or debugging. |
Some error responses include additional fields with context-specific details:
{ "error": "validation_error", "message": "Request body validation failed.", "details": [ { "field": "cron_expression", "issue": "Invalid cron expression format" }, { "field": "agent_id", "issue": "Required field missing" } ]}HTTP Status Codes
Section titled “HTTP Status Codes”Horizon uses standard HTTP status codes to indicate the result of an API request.
Success Codes
Section titled “Success Codes”| Status | Meaning | When Used |
|---|---|---|
200 OK | The request succeeded. | Standard GET, PUT, PATCH, DELETE responses. |
201 Created | A resource was created successfully. | POST responses that create a new resource. |
202 Accepted | The request was accepted for processing. | Skill execution and async webhook triggers. |
204 No Content | The request succeeded with no response body. | Some DELETE operations. |
Client Error Codes
Section titled “Client Error Codes”| Status | Meaning | When Used |
|---|---|---|
400 Bad Request | The request body or parameters are invalid. | Missing required fields, malformed JSON, invalid parameter values. |
401 Unauthorized | Authentication failed. | Missing or invalid API key, expired key, invalid admin secret. |
403 Forbidden | The authenticated key lacks permission. | API key does not have the required scope for the requested operation. |
404 Not Found | The requested resource does not exist. | Invalid IDs, non-existent endpoints. |
409 Conflict | The request conflicts with current state. | Attempting to create a duplicate resource. |
422 Unprocessable Entity | The request is well-formed but semantically invalid. | Valid JSON but with logically incorrect values. |
429 Too Many Requests | Rate limit exceeded. | See Rate Limiting for details. |
Server Error Codes
Section titled “Server Error Codes”| Status | Meaning | When Used |
|---|---|---|
500 Internal Server Error | An unexpected error occurred on the server. | Platform bugs, unhandled exceptions. |
502 Bad Gateway | An upstream service is unavailable. | External integration connectivity issues. |
503 Service Unavailable | The service is temporarily unavailable. | Maintenance windows, overload conditions. |
Common Error Responses
Section titled “Common Error Responses”Authentication Errors
Section titled “Authentication Errors”Missing API key:
// 401 Unauthorized{ "error": "authentication_required", "message": "Missing API key. Provide a valid key in the x-api-key header."}Invalid or revoked API key:
// 401 Unauthorized{ "error": "invalid_api_key", "message": "The provided API key is invalid or has been revoked."}Expired API key:
// 401 Unauthorized{ "error": "api_key_expired", "message": "The provided API key has expired."}Invalid admin secret:
// 401 Unauthorized{ "error": "invalid_admin_secret", "message": "The provided admin secret is invalid."}Authorization Errors
Section titled “Authorization Errors”Insufficient scope:
// 403 Forbidden{ "error": "insufficient_scope", "message": "The API key does not have the required scope 'quickbooks' for this operation."}Validation Errors
Section titled “Validation Errors”Missing required field:
// 400 Bad Request{ "error": "validation_error", "message": "The 'client_name' field is required."}Invalid parameter value:
// 400 Bad Request{ "error": "validation_error", "message": "The 'limit' parameter must be between 1 and 200."}Resource Errors
Section titled “Resource Errors”Resource not found:
// 404 Not Found{ "error": "not_found", "message": "Conversation 'conv_nonexistent' not found."}Rate Limiting Errors
Section titled “Rate Limiting Errors”Rate limit exceeded:
// 429 Too Many Requests{ "error": "rate_limit_exceeded", "message": "Rate limit exceeded. Maximum 100 requests per minute.", "retry_after": 23}Handling Errors in Code
Section titled “Handling Errors in Code”# Check the HTTP status code in the responsecurl -s -w "\nHTTP Status: %{http_code}" \ -X GET https://api.horizonplatform.ai/api/conversations/invalid_id \ -H "x-api-key: hz_live_abc123def456"const response = await fetch( 'https://api.horizonplatform.ai/api/conversations/invalid_id', { headers: { 'x-api-key': 'hz_live_abc123def456' } });
if (!response.ok) { const error = await response.json(); console.error(`Error ${response.status}: [${error.error}] ${error.message}`);
switch (response.status) { case 401: // Re-authenticate or refresh API key break; case 403: // Check key scopes break; case 429: // Implement backoff and retry break; default: // Log and alert break; }}import requests
response = requests.get( 'https://api.horizonplatform.ai/api/conversations/invalid_id', headers={'x-api-key': 'hz_live_abc123def456'})
if not response.ok: error = response.json() print(f"Error {response.status_code}: [{error['error']}] {error['message']}")
if response.status_code == 401: # Re-authenticate or refresh API key pass elif response.status_code == 403: # Check key scopes pass elif response.status_code == 429: # Implement backoff and retry pass else: # Log and alert pass