Error Handling

Learn how to handle errors effectively when working with the Metigan API. This guide covers error types, response formats, and best practices for robust error handling.

Error Response Types

Metigan API uses consistent error response formats to help you handle errors gracefully:

API Error Response

error-response.tsTypeScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Generic API Error Response
interface ApiErrorResponse {
  success: false;
  error: string;
  message?: string;
  statusCode?: number;
}

// Example error responses
{
  success: false,
  error: "invalid_api_key",
  message: "The provided API key is invalid",
  statusCode: 401
}

{
  success: false,
  error: "rate_limit_exceeded",
  message: "You have exceeded your rate limit. Please try again later.",
  statusCode: 429
}

Validation Error Response

validation-error.tsTypeScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// Validation Error Response
interface ValidationErrorResponse {
  success: false;
  error: "validation_error";
  message: string;
  validationErrors?: Array<{
    field: string;
    message: string;
  }>;
}

// Example validation error
{
  success: false,
  error: "validation_error",
  message: "Invalid request parameters",
  validationErrors: [
    {
      field: "recipients",
      message: "At least one recipient is required"
    },
    {
      field: "subject",
      message: "Subject cannot be empty"
    }
  ]
}

Handling Errors

Here's how to properly handle errors in your application:

error-handling.tsTypeScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
import Metigan from 'metigan';
import type { EmailApiResponse } from 'metigan';

const metigan = new Metigan({
  apiKey: process.env.METIGAN_API_KEY!
});

async function sendEmailWithErrorHandling() {
  try {
    const result = await metigan.email.sendEmail({
      from: 'sender@example.com',
      recipients: ['recipient@example.com'],
      subject: 'Test Email',
      content: '<p>Hello!</p>'
    });

    // Check if the response indicates success
    if ('success' in result && result.success === true) {
      console.log('✅ Email sent successfully!');
      console.log('Tracking ID:', result.successfulEmails[0]?.trackingId);
      return result;
    } else {
      // Handle API errors
      handleApiError(result);
      return null;
    }
  } catch (error) {
    // Handle exceptions (network errors, timeouts, etc.)
    handleException(error);
    return null;
  }
}

function handleApiError(error: EmailApiResponse) {
  if (!('success' in error) || error.success !== false) {
    return;
  }

  switch (error.error) {
    case 'invalid_api_key':
      console.error('❌ Authentication failed. Check your API key.');
      break;
    
    case 'rate_limit_exceeded':
      console.error('❌ Rate limit exceeded. Please wait before retrying.');
      // Implement retry logic with exponential backoff
      break;
    
    case 'validation_error':
      console.error('❌ Validation error:', error.message);
      if ('validationErrors' in error && error.validationErrors) {
        error.validationErrors.forEach(err => {
          console.error(`  - ${err.field}: ${err.message}`);
        });
      }
      break;
    
    case 'insufficient_quota':
      console.error('❌ Insufficient quota. Please upgrade your plan.');
      break;
    
    default:
      console.error('❌ API Error:', error.error, error.message);
  }
}

function handleException(error: unknown) {
  if (error instanceof Error) {
    console.error('❌ Exception:', error.message);
    
    // Check for network errors
    if (error.message.includes('network') || error.message.includes('fetch')) {
      console.error('Network error. Check your internet connection.');
    }
    
    // Check for timeout errors
    if (error.message.includes('timeout')) {
      console.error('Request timeout. The server may be overloaded.');
    }
  } else {
    console.error('❌ Unknown error:', error);
  }
}

Error Codes Reference

Common error codes you may encounter:

Error CodeHTTP StatusDescription
invalid_api_key401The API key is invalid or missing
validation_error400Request validation failed
rate_limit_exceeded429Rate limit exceeded
insufficient_quota402Email quota exceeded
server_error500Internal server error
service_unavailable503Service temporarily unavailable

Retry Logic

For transient errors like rate limits or network issues, implement retry logic with exponential backoff:

retry-logic.tsTypeScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
async function sendEmailWithRetry(
  emailParams: EmailParams,
  maxRetries: number = 3,
  initialDelay: number = 1000
): Promise<EmailApiResponse | null> {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      const result = await metigan.email.sendEmail(emailParams);
      
      if ('success' in result && result.success === true) {
        return result;
      }

      // Check if error is retryable
      if ('error' in result) {
        const retryableErrors = ['rate_limit_exceeded', 'server_error', 'service_unavailable'];
        
        if (retryableErrors.includes(result.error) && attempt < maxRetries - 1) {
          const delay = initialDelay * Math.pow(2, attempt);
          console.log(`Retrying after ${delay}ms... (attempt ${attempt + 1}/${maxRetries})`);
          await new Promise(resolve => setTimeout(resolve, delay));
          continue;
        }
      }

      return result;
    } catch (error) {
      if (attempt < maxRetries - 1) {
        const delay = initialDelay * Math.pow(2, attempt);
        console.log(`Retrying after ${delay}ms... (attempt ${attempt + 1}/${maxRetries})`);
        await new Promise(resolve => setTimeout(resolve, delay));
        continue;
      }
      
      throw error;
    }
  }

  return null;
}
Important

Always validate and sanitize user input before sending API requests. Never expose API keys in client-side code. Use environment variables to store your API keys securely.