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 Response Structure
{
  "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 CodeMeaningDescription
200OKRequest succeeded (GET, PATCH, DELETE)
201CreatedResource created successfully (POST)
400Bad RequestInvalid request syntax or parameters
401UnauthorizedMissing or invalid API key
403ForbiddenAPI key doesn't have permission
404Not FoundResource doesn't exist
422Unprocessable EntityValidation failed (see details)
429Too Many RequestsRate limit exceeded
500Internal Server ErrorUnexpected server error
503Service UnavailableTemporary downtime or maintenance

Common Error Codes

These error codes appear in the error.code field and help you identify the specific issue.

Error CodeStatusDescription
unauthorized401Invalid or missing API key
forbidden403API key lacks required scope
not_found404Resource ID doesn't exist
validation_error422Request failed validation rules
rate_limit_exceeded429Too many requests in time window
resource_conflict409Duplicate resource or constraint violation
internal_error500Unexpected server error (contact support)
service_unavailable503Temporary downtime (retry with backoff)

Example Error Responses

401 Unauthorized

Returned when the API key is missing, invalid, or expired.

Missing API Key
{
  "error": {
    "code": "unauthorized",
    "message": "Missing Authorization header"
  }
}
Invalid API Key
{
  "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.

Missing Scope
{
  "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.

Resource Not Found
{
  "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.

Validation Errors
{
  "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.

Rate Limit Exceeded
{
  "error": {
    "code": "rate_limit_exceeded",
    "message": "Rate limit exceeded. Retry after 60 seconds."
  }
}
Response Headers
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1705756920
Retry-After: 60

How 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.

Server Error
{
  "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

Node.js - Comprehensive Error Handling
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;
  }
}
Python - Error Handling with Retry
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.ok or status code before parsing JSON
  • Parse error.code for handling - Use the machine-readable error.code field, 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-After header 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

Related Documentation