# Error Handling

Handle errors gracefully with HivePay's typed error system.

---

## HivePayError

All API errors are thrown as `HivePayError` instances:

+++ TypeScript
```typescript
import { HivePay, HivePayError, isHivePayError } from '@hivepay/client';

try {
  await hivepay.payments.get('invalid-id');
} catch (error) {
  if (isHivePayError(error)) {
    console.log(error.code);       // Error code
    console.log(error.statusCode); // HTTP status
    console.log(error.message);    // Error message
  }
}
```
+++

### Properties

| Property | Type | Description |
|----------|------|-------------|
| `code` | `ErrorCode` | Error type identifier |
| `statusCode` | `number` | HTTP status code |
| `message` | `string` | Human-readable message |

---

## Error Codes

| Code | Status | Description |
|------|--------|-------------|
| `NETWORK_ERROR` | - | Network request failed or timed out |
| `API_ERROR` | varies | General API error |
| `AUTHENTICATION_ERROR` | 401 | Invalid or missing API key |
| `FORBIDDEN_ERROR` | 403 | Insufficient permissions or AML limit reached |
| `NOT_FOUND_ERROR` | 404 | Resource not found |
| `VALIDATION_ERROR` | 400 | Invalid request parameters |
| `RATE_LIMIT_ERROR` | 429 | Too many requests |
| `SERVER_ERROR` | 5xx | Server-side error |

---

## Type Guard

Use `isHivePayError` to safely check error type:

+++ TypeScript
```typescript
import { isHivePayError } from '@hivepay/client';

try {
  await hivepay.payments.create({ ... });
} catch (error) {
  if (isHivePayError(error)) {
    // TypeScript knows error is HivePayError
    handleHivePayError(error);
  } else {
    // Unknown error
    throw error;
  }
}
```
+++

---

## Error Type Methods

`HivePayError` provides methods to check error type:

+++ TypeScript
```typescript
if (isHivePayError(error)) {
  if (error.isNotFound()) {
    // 404 - Resource not found
    console.log('Payment not found');
  } else if (error.isAuthError()) {
    // 401 - Authentication failed
    console.log('Invalid API key');
  } else if (error.isValidation()) {
    // 400 - Validation error
    console.log('Invalid data:', error.message);
  } else if (error.isRateLimited()) {
    // 429 - Rate limited
    console.log('Too many requests, retry later');
  } else if (error.isForbidden()) {
    // 403 - Forbidden
    console.log('Access denied');
  } else if (error.isServerError()) {
    // 5xx - Server error
    console.log('Server error, retry later');
  }
}
```
+++

### Available Methods

| Method | Returns `true` for |
|--------|-------------------|
| `isNotFound()` | `NOT_FOUND_ERROR` (404) |
| `isAuthError()` | `AUTHENTICATION_ERROR` (401) |
| `isValidation()` | `VALIDATION_ERROR` (400) |
| `isRateLimited()` | `RATE_LIMIT_ERROR` (429) |
| `isForbidden()` | `FORBIDDEN_ERROR` (403) |
| `isServerError()` | `SERVER_ERROR` (5xx) |
| `isNetworkError()` | `NETWORK_ERROR` |

---

## Handling Specific Errors

### Authentication Errors

+++ TypeScript
```typescript
try {
  await hivepay.payments.create({ ... });
} catch (error) {
  if (isHivePayError(error) && error.isAuthError()) {
    // API key is invalid or expired
    // Redirect to login or refresh key
    await refreshApiKey();
  }
}
```
+++

### AML Limit Errors

+++ TypeScript
```typescript
try {
  await hivepay.payments.create({ ... });
} catch (error) {
  if (isHivePayError(error) && error.isForbidden()) {
    if (error.message.includes('AML limit reached')) {
      // Merchant account is AML-flagged
      // Contact aml@hivepay.me for KYC verification
      console.error('AML verification required:', error.message);
    } else {
      // Other forbidden errors (e.g., inactive account)
      console.error('Access denied:', error.message);
    }
  }
}
```
+++

### Not Found Errors

+++ TypeScript
```typescript
try {
  const payment = await hivepay.payments.get(paymentId);
} catch (error) {
  if (isHivePayError(error) && error.isNotFound()) {
    // Payment doesn't exist
    return null;
  }
  throw error;
}
```
+++

### Validation Errors

+++ TypeScript
```typescript
try {
  await hivepay.payments.create({
    amount: 'invalid',
    currency: 'USD',  // Invalid currency
    description: ''
  });
} catch (error) {
  if (isHivePayError(error) && error.isValidation()) {
    // Show error to user
    showError(error.message);
  }
}
```
+++

### Rate Limiting

+++ TypeScript
```typescript
async function createPaymentWithRetry(data: CreatePaymentData, maxRetries = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      return await hivepay.payments.create(data);
    } catch (error) {
      if (isHivePayError(error) && error.isRateLimited()) {
        if (attempt < maxRetries) {
          // Wait before retry (exponential backoff)
          await sleep(1000 * Math.pow(2, attempt));
          continue;
        }
      }
      throw error;
    }
  }
}
```
+++

### Network Errors

+++ TypeScript
```typescript
try {
  await hivepay.payments.create({ ... });
} catch (error) {
  if (isHivePayError(error) && error.isNetworkError()) {
    // Connection failed or timed out
    showError('Unable to connect. Please check your internet connection.');
  }
}
```
+++

---

## Complete Example

+++ TypeScript
```typescript
import {
  HivePay,
  isHivePayError,
  type CreatePaymentOptions
} from '@hivepay/client';

const hivepay = new HivePay({ apiKey: process.env.HIVEPAY_API_KEY! });

async function createPayment(options: CreatePaymentOptions) {
  try {
    const payment = await hivepay.payments.create(options);
    return { success: true, payment };
  } catch (error) {
    if (!isHivePayError(error)) {
      // Unknown error - rethrow
      throw error;
    }

    // Handle specific error types
    if (error.isAuthError()) {
      return {
        success: false,
        error: 'Authentication failed. Check your API key.'
      };
    }

    if (error.isValidation()) {
      return {
        success: false,
        error: `Invalid data: ${error.message}`
      };
    }

    if (error.isRateLimited()) {
      return {
        success: false,
        error: 'Too many requests. Please wait and try again.'
      };
    }

    if (error.isForbidden()) {
      return {
        success: false,
        error: error.message.includes('AML limit reached')
          ? 'AML verification required. Contact aml@hivepay.me.'
          : 'Access denied.'
      };
    }

    if (error.isServerError()) {
      return {
        success: false,
        error: 'Server error. Please try again later.'
      };
    }

    if (error.isNetworkError()) {
      return {
        success: false,
        error: 'Network error. Check your connection.'
      };
    }

    // Fallback for unhandled error codes
    return {
      success: false,
      error: error.message
    };
  }
}
```
+++

---

## TypeScript Types

```typescript
type ErrorCode =
  | 'NETWORK_ERROR'
  | 'API_ERROR'
  | 'AUTHENTICATION_ERROR'
  | 'FORBIDDEN_ERROR'
  | 'NOT_FOUND_ERROR'
  | 'VALIDATION_ERROR'
  | 'RATE_LIMIT_ERROR'
  | 'SERVER_ERROR';

class HivePayError extends Error {
  readonly code: ErrorCode;
  readonly statusCode: number;

  isNotFound(): boolean;
  isAuthError(): boolean;
  isValidation(): boolean;
  isRateLimited(): boolean;
  isForbidden(): boolean;
  isServerError(): boolean;
  isNetworkError(): boolean;
}

function isHivePayError(error: unknown): error is HivePayError;
```
