Error Codes
Hook Mesh uses standard HTTP status codes and structured error responses. This reference helps you understand and handle API errors effectively.
Error Response Format
All error responses follow a consistent JSON structure with a code and message field for easy programmatic handling.
{
"error": {
"code": "validation_error",
"message": "Validation failed for the request",
"details": {
"url": ["The url field must be a valid HTTPS URL"]
}
}
}Fields
- error.codestring
- Machine-readable error code for programmatic handling
- error.messagestring
- Human-readable description of the error
- error.detailsobject | null
- Additional context (e.g., validation errors by field)
HTTP Status Codes
Hook Mesh uses standard HTTP status codes to indicate success or failure of requests.
| Status Code | Meaning | Description |
|---|---|---|
| 200 | OK | Request succeeded (GET, PATCH, DELETE) |
| 201 | Created | Resource created successfully (POST) |
| 400 | Bad Request | Invalid request syntax or parameters |
| 401 | Unauthorized | Missing or invalid API key |
| 403 | Forbidden | API key doesn't have permission |
| 404 | Not Found | Resource doesn't exist |
| 422 | Unprocessable Entity | Validation failed (see details) |
| 429 | Too Many Requests | Rate limit exceeded |
| 500 | Internal Server Error | Unexpected server error |
| 503 | Service Unavailable | Temporary downtime or maintenance |
Common Error Codes
These error codes appear in the error.code field and help you identify the specific issue.
| Error Code | Status | Description |
|---|---|---|
| unauthorized | 401 | Invalid or missing API key |
| forbidden | 403 | API key lacks required scope |
| not_found | 404 | Resource ID doesn't exist |
| validation_error | 422 | Request failed validation rules |
| rate_limit_exceeded | 429 | Too many requests in time window |
| resource_conflict | 409 | Duplicate resource or constraint violation |
| internal_error | 500 | Unexpected server error (contact support) |
| service_unavailable | 503 | Temporary downtime (retry with backoff) |
Example Error Responses
401 Unauthorized
Returned when the API key is missing, invalid, or expired.
{
"error": {
"code": "unauthorized",
"message": "Missing Authorization header"
}
}{
"error": {
"code": "unauthorized",
"message": "Invalid API key"
}
}How to Fix
Verify your API key is correct and included in the Authorization header as Bearer YOUR_KEY.
403 Forbidden
Returned when the API key doesn't have the required scope or permission.
{
"error": {
"code": "forbidden",
"message": "API key does not have the required scope: webhooks:write"
}
}How to Fix
Create a new API key with the required scopes, or update the existing key's permissions.
404 Not Found
Returned when the requested resource doesn't exist.
{
"error": {
"code": "not_found",
"message": "Application not found: app_invalid123"
}
}How to Fix
Verify the resource ID is correct. The resource may have been deleted, or the ID may be from a different organization.
422 Unprocessable Entity
Returned when request validation fails. The details field shows which fields failed and why.
{
"error": {
"code": "validation_error",
"message": "Validation failed for the request",
"details": {
"url": ["The url field must be a valid HTTPS URL"],
"event_type": ["The event_type field is required"],
"timeout_ms": ["The timeout_ms must be between 1000 and 120000"]
}
}
}How to Fix
Review the details object to see which fields failed validation. Fix each error and retry the request.
429 Too Many Requests
Returned when you exceed the API rate limit. Check the Retry-After header for when to retry.
{
"error": {
"code": "rate_limit_exceeded",
"message": "Rate limit exceeded. Retry after 60 seconds."
}
}HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1705756920
Retry-After: 60How to Fix
Wait for the duration specified in Retry-After before retrying. Implement exponential backoff in your code.
500 Internal Server Error
Returned when an unexpected error occurs on our servers.
{
"error": {
"code": "internal_error",
"message": "An unexpected error occurred. Please contact support with request ID: req_abc123"
}
}How to Fix
Retry the request after a brief delay. If the error persists, contact support with the request ID from the error message.
Error Handling Best Practices
async function createWebhookJob(data: any) {
try {
const response = await fetch('https://api.hookmesh.com/v1/webhook-jobs', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.HOOKMESH_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
// Success
if (response.ok) {
return await response.json();
}
// Parse error response
const error = await response.json();
// Handle specific errors
switch (response.status) {
case 401:
throw new Error('Invalid API key - check your credentials');
case 403:
throw new Error(`Missing permission: ${error.error.message}`);
case 404:
throw new Error(`Resource not found: ${error.error.message}`);
case 422:
// Validation errors - extract field-specific messages
const validationErrors = error.error.details;
const fieldErrors = Object.entries(validationErrors)
.map(([field, messages]) => `${field}: ${messages.join(', ')}`)
.join('; ');
throw new Error(`Validation failed: ${fieldErrors}`);
case 429:
// Rate limit - check Retry-After header
const retryAfter = response.headers.get('Retry-After');
throw new Error(`Rate limit exceeded. Retry after ${retryAfter} seconds`);
case 500:
case 503:
// Server errors - retry with exponential backoff
throw new Error(`Server error (${response.status}). Please retry.`);
default:
throw new Error(`API error (${response.status}): ${error.error.message}`);
}
} catch (err) {
console.error('Failed to create webhook job:', err);
throw err;
}
}import requests
import time
from typing import Dict, Any
def create_webhook_job(data: Dict[str, Any], max_retries: int = 3) -> Dict[str, Any]:
"""Create a webhook job with automatic retry on server errors."""
for attempt in range(max_retries):
try:
response = requests.post(
'https://api.hookmesh.com/v1/webhook-jobs',
headers={
'Authorization': f'Bearer {os.environ["HOOKMESH_API_KEY"]}',
'Content-Type': 'application/json'
},
json=data
)
# Success
if response.ok:
return response.json()
# Parse error
error = response.json()
# 401/403/404/422 - Don't retry (permanent errors)
if response.status_code in [401, 403, 404, 422]:
if response.status_code == 422:
# Format validation errors
details = error['error'].get('details', {})
field_errors = '; '.join(
f'{field}: {", ".join(msgs)}'
for field, msgs in details.items()
)
raise ValueError(f'Validation failed: {field_errors}')
raise ValueError(f'{response.status_code}: {error["error"]["message"]}')
# 429 - Rate limit
if response.status_code == 429:
retry_after = int(response.headers.get('Retry-After', 60))
if attempt < max_retries - 1:
print(f'Rate limited. Waiting {retry_after} seconds...')
time.sleep(retry_after)
continue
raise ValueError(f'Rate limit exceeded: {error["error"]["message"]}')
# 500/503 - Server error, retry with backoff
if response.status_code in [500, 503]:
if attempt < max_retries - 1:
backoff = (2 ** attempt) * 1 # 1s, 2s, 4s
print(f'Server error. Retrying in {backoff}s...')
time.sleep(backoff)
continue
raise RuntimeError(f'Server error after {max_retries} attempts')
# Other errors
raise RuntimeError(f'{response.status_code}: {error["error"]["message"]}')
except requests.RequestException as e:
# Network errors - retry
if attempt < max_retries - 1:
backoff = (2 ** attempt) * 1
print(f'Network error: {e}. Retrying in {backoff}s...')
time.sleep(backoff)
continue
raise RuntimeError(f'Network error after {max_retries} attempts: {e}')
raise RuntimeError('Max retries exceeded')Best Practices
- ✓Check HTTP status first - Use
response.okor status code before parsing JSON - ✓Parse error.code for handling - Use the machine-readable
error.codefield, not the message - ✓Don't retry 4xx errors - 400, 401, 403, 404, 422 are permanent failures (except 429 rate limits)
- ✓Retry 5xx errors with backoff - Server errors are temporary, use exponential backoff (1s, 2s, 4s, 8s)
- ✓Respect rate limits - Check
Retry-Afterheader and wait before retrying 429 errors - ✓Log error details - Include request ID, error code, and full error message in logs
- ✓Show user-friendly messages - Translate technical errors into actionable messages for end users
- ✓Monitor error rates - Track 4xx/5xx error rates to identify integration issues early