Skip to main content
Proper error handling is essential for building robust integrations with the G-Tateth API. This guide covers all error types, status codes, and best practices.

HTTP Status Codes

The G-Tateth API uses standard HTTP status codes to indicate success or failure:

Success Codes

  • 200 OK - Request succeeded
  • 201 Created - Resource created successfully
  • 204 No Content - Request succeeded, no content to return

Client Error Codes

  • 400 Bad Request - Invalid request parameters or malformed JSON
  • 401 Unauthorized - Missing or invalid authentication
  • 403 Forbidden - Insufficient permissions
  • 404 Not Found - Resource doesn’t exist
  • 409 Conflict - Resource conflict (e.g., duplicate entry)
  • 422 Unprocessable Entity - Validation errors
  • 429 Too Many Requests - Rate limit exceeded

Server Error Codes

  • 500 Internal Server Error - Unexpected server error
  • 502 Bad Gateway - Upstream service error
  • 503 Service Unavailable - Service temporarily unavailable
  • 504 Gateway Timeout - Request timeout

Error Response Format

All error responses follow a consistent format:
{
  "success": false,
  "error": {
    "code": "ERROR_CODE",
    "message": "Human-readable error message",
    "details": {
      "field": "Additional error details",
      "validation": "Specific validation errors"
    },
    "requestId": "req_1234567890",
    "timestamp": "2024-01-15T10:30:00Z"
  }
}

Common Error Codes

Authentication Errors

Always check authentication before making requests.

AUTH_REQUIRED

Status: 401 Unauthorized
{
  "success": false,
  "error": {
    "code": "AUTH_REQUIRED",
    "message": "Authentication required",
    "details": {
      "hint": "Include a valid API key or Bearer token in the Authorization header"
    }
  }
}
Solution:
// Add Authorization header
headers: {
  'Authorization': `Bearer ${apiKey}`
}

AUTH_INVALID

Status: 401 Unauthorized
{
  "success": false,
  "error": {
    "code": "AUTH_INVALID",
    "message": "Invalid API key or token"
  }
}
Solution: Verify your API key is correct and hasn’t been revoked.

AUTH_EXPIRED

Status: 401 Unauthorized
{
  "success": false,
  "error": {
    "code": "AUTH_EXPIRED",
    "message": "Token has expired",
    "details": {
      "expiredAt": "2024-01-15T10:00:00Z"
    }
  }
}
Solution: Refresh your token or generate a new API key.

Validation Errors

VALIDATION_ERROR

Status: 422 Unprocessable Entity
{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Validation failed",
    "details": {
      "fields": {
        "email": ["Email is required", "Email format is invalid"],
        "phone": ["Phone number must be in E.164 format"]
      }
    }
  }
}
Solution: Fix the validation errors and retry the request.

Rate Limiting

RATE_LIMIT_EXCEEDED

Status: 429 Too Many Requests
{
  "success": false,
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Rate limit exceeded",
    "details": {
      "limit": 100,
      "remaining": 0,
      "resetAt": "2024-01-15T11:00:00Z"
    }
  }
}
Solution: Wait until resetAt or upgrade your plan for higher limits.

Resource Errors

RESOURCE_NOT_FOUND

Status: 404 Not Found
{
  "success": false,
  "error": {
    "code": "RESOURCE_NOT_FOUND",
    "message": "Conversation not found",
    "details": {
      "resource": "conversation",
      "id": "conv_123"
    }
  }
}
Solution: Verify the resource ID exists and you have access to it.

RESOURCE_CONFLICT

Status: 409 Conflict
{
  "success": false,
  "error": {
    "code": "RESOURCE_CONFLICT",
    "message": "Resource already exists",
    "details": {
      "resource": "api_key",
      "conflict": "Key with this name already exists"
    }
  }
}
Solution: Use a different identifier or update the existing resource.

Permission Errors

PERMISSION_DENIED

Status: 403 Forbidden
{
  "success": false,
  "error": {
    "code": "PERMISSION_DENIED",
    "message": "Insufficient permissions",
    "details": {
      "required": "write:conversations",
      "granted": ["read:conversations"]
    }
  }
}
Solution: Use an API key with the required permissions or contact your administrator.

Plan Limits

PLAN_LIMIT_EXCEEDED

Status: 403 Forbidden
{
  "success": false,
  "error": {
    "code": "PLAN_LIMIT_EXCEEDED",
    "message": "Plan limit exceeded",
    "details": {
      "limit": 1000,
      "current": 1001,
      "resource": "api_calls_per_month"
    }
  }
}
Solution: Upgrade your plan or wait for the next billing cycle.

Error Handling Examples

JavaScript/TypeScript

async function handleApiRequest(url: string, options: RequestInit) {
  try {
    const response = await fetch(url, options);
    const data = await response.json();
    
    if (!response.ok) {
      throw new ApiError(data.error, response.status);
    }
    
    return data;
  } catch (error) {
    if (error instanceof ApiError) {
      // Handle API errors
      switch (error.code) {
        case 'AUTH_REQUIRED':
        case 'AUTH_INVALID':
        case 'AUTH_EXPIRED':
          // Redirect to login or refresh token
          await refreshAuth();
          break;
        case 'RATE_LIMIT_EXCEEDED':
          // Wait and retry
          await waitForRateLimit(error.details.resetAt);
          break;
        case 'VALIDATION_ERROR':
          // Show validation errors to user
          showValidationErrors(error.details.fields);
          break;
        default:
          // Show generic error
          showError(error.message);
      }
    } else {
      // Handle network errors
      showError('Network error. Please check your connection.');
    }
    throw error;
  }
}

class ApiError extends Error {
  constructor(
    public error: {
      code: string;
      message: string;
      details?: any;
    },
    public status: number
  ) {
    super(error.message);
    this.name = 'ApiError';
  }
  
  get code() {
    return this.error.code;
  }
  
  get details() {
    return this.error.details;
  }
}

Python

import requests
from typing import Dict, Any

class ApiError(Exception):
    def __init__(self, error: Dict[str, Any], status_code: int):
        self.code = error.get('code')
        self.message = error.get('message')
        self.details = error.get('details', {})
        self.status_code = status_code
        super().__init__(self.message)

def handle_api_request(url: str, method: str = 'GET', **kwargs) -> Dict:
    try:
        response = requests.request(method, url, **kwargs)
        data = response.json()
        
        if not response.ok:
            raise ApiError(data.get('error', {}), response.status_code)
        
        return data
    except requests.exceptions.RequestException as e:
        # Handle network errors
        raise Exception(f'Network error: {str(e)}')

# Usage with error handling
try:
    result = handle_api_request(
        'https://api.g-tateth.com/api/v1/conversations',
        headers={'Authorization': f'Bearer {api_key}'}
    )
except ApiError as e:
    if e.code == 'AUTH_REQUIRED':
        # Refresh authentication
        refresh_auth()
    elif e.code == 'RATE_LIMIT_EXCEEDED':
        # Wait and retry
        wait_for_rate_limit(e.details.get('resetAt'))
    else:
        print(f'API Error: {e.message}')

PHP

<?php

class ApiError extends Exception {
    public $code;
    public $details;
    public $statusCode;
    
    public function __construct($error, $statusCode) {
        $this->code = $error['code'] ?? 'UNKNOWN_ERROR';
        $this->details = $error['details'] ?? [];
        $this->statusCode = $statusCode;
        parent::__construct($error['message'] ?? 'Unknown error');
    }
}

function handleApiRequest($url, $options = []) {
    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER => $options['headers'] ?? [],
        CURLOPT_CUSTOMREQUEST => $options['method'] ?? 'GET',
        CURLOPT_POSTFIELDS => isset($options['body']) ? json_encode($options['body']) : null,
    ]);
    
    $response = curl_exec($ch);
    $statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    
    $data = json_decode($response, true);
    
    if ($statusCode >= 400) {
        throw new ApiError($data['error'] ?? [], $statusCode);
    }
    
    return $data;
}

// Usage
try {
    $result = handleApiRequest(
        'https://api.g-tateth.com/api/v1/conversations',
        [
            'headers' => [
                'Authorization: Bearer ' . $apiKey,
                'Content-Type: application/json'
            ]
        ]
    );
} catch (ApiError $e) {
    switch ($e->code) {
        case 'AUTH_REQUIRED':
            refreshAuth();
            break;
        case 'RATE_LIMIT_EXCEEDED':
            waitForRateLimit($e->details['resetAt']);
            break;
        default:
            echo "API Error: " . $e->getMessage();
    }
}

Retry Logic

Implement exponential backoff for retryable errors:
async function retryRequest(fn, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (i === maxRetries - 1) throw error;
      
      // Only retry on specific errors
      const retryableErrors = [
        'RATE_LIMIT_EXCEEDED',
        'SERVER_ERROR',
        'TIMEOUT'
      ];
      
      if (!retryableErrors.includes(error.code)) {
        throw error;
      }
      
      // Exponential backoff: 1s, 2s, 4s
      const delay = Math.pow(2, i) * 1000;
      await new Promise(resolve => setTimeout(resolve, delay));
    }
  }
}

Best Practices

1. Always Check Response Status

// ❌ Bad
const data = await response.json();

// ✅ Good
if (!response.ok) {
  const error = await response.json();
  throw new ApiError(error.error, response.status);
}
const data = await response.json();

2. Handle Network Errors

try {
  const response = await fetch(url);
} catch (error) {
  if (error instanceof TypeError) {
    // Network error
    console.error('Network error:', error.message);
  } else {
    // Other error
    throw error;
  }
}

3. Log Errors for Debugging

catch (error) {
  console.error('API Error:', {
    code: error.code,
    message: error.message,
    details: error.details,
    requestId: error.requestId,
    url: error.url
  });
  throw error;
}

4. Provide User-Friendly Messages

const errorMessages = {
  'AUTH_REQUIRED': 'Please log in to continue',
  'RATE_LIMIT_EXCEEDED': 'Too many requests. Please try again later.',
  'VALIDATION_ERROR': 'Please check your input and try again.',
  'RESOURCE_NOT_FOUND': 'The requested item could not be found.'
};

function getUserMessage(error) {
  return errorMessages[error.code] || error.message;
}

5. Use Request IDs for Support

Always include the requestId when contacting support:
catch (error) {
  if (error.requestId) {
    console.error(`Request ID: ${error.requestId}`);
    // Include in support ticket
  }
}

Testing Error Handling

Test your error handling with different scenarios:
// Test authentication errors
test('handles invalid API key', async () => {
  const response = await apiRequest('/conversations', {
    headers: { 'Authorization': 'Bearer invalid' }
  });
  expect(response.status).toBe(401);
});

// Test validation errors
test('handles validation errors', async () => {
  const response = await apiRequest('/conversations', {
    method: 'POST',
    body: { invalid: 'data' }
  });
  expect(response.status).toBe(422);
});

// Test rate limiting
test('handles rate limits', async () => {
  // Make many requests
  for (let i = 0; i < 100; i++) {
    await apiRequest('/conversations');
  }
  const response = await apiRequest('/conversations');
  expect(response.status).toBe(429);
});

Support

If you encounter an error that isn’t documented here:
  1. Check the error requestId in the response
  2. Review the error details for additional context
  3. Contact support with the requestId and error details
  4. Check our status page for service issues
Support Email: support@g-tateth.com