Proper error handling is essential for building robust applications with Notch Pay. This guide explains the key concepts of error handling and best practices for implementing it in your applications.

Understanding API Errors

When an error occurs, the Notch Pay API returns:

  1. An appropriate HTTP status code
  2. A JSON response with details about what went wrong
{
  "code": 400,
  "status": "Bad Request",
  "message": "Error message describing what went wrong",
  "errors": {
    "field_name": ["Error description for this field"]
  }
}

Common Error Categories

Authentication Errors

Status Codes: 401, 403

Occur when there’s an issue with your API keys or permissions.

Common causes:

  • Missing API key
  • Invalid API key
  • Insufficient permissions
  • Missing required headers

Validation Errors

Status Codes: 400, 422

Occur when the request data doesn’t meet the required format or constraints.

Common causes:

  • Missing required fields
  • Invalid field formats
  • Values outside allowed ranges
  • Incompatible parameter combinations

Resource Errors

Status Codes: 404, 409

Occur when the requested resource doesn’t exist or there’s a conflict.

Common causes:

  • Resource not found
  • Resource already exists
  • Resource in incompatible state

System Errors

Status Codes: 429, 500, 503

Occur due to rate limiting or server-side issues.

Common causes:

  • Rate limit exceeded
  • Server error
  • Service unavailable

Best Practices for Error Handling

1

Always Check for Errors

Don’t assume API requests will always succeed. Check for errors in all API responses.

// Example in JavaScript
if (!response.ok) {
  const error = await response.json();
  // Handle error
  console.error(`Error: ${error.message}`);
}
2

Handle Different Error Types

Implement specific handling for different types of errors.

// Example in JavaScript
if (error.code === 401) {
  // Handle authentication errors
  redirectToLogin();
} else if (error.code === 422) {
  // Handle validation errors
  showValidationErrors(error.errors);
} else if (error.code === 429) {
  // Handle rate limiting
  retryWithBackoff(request);
}
3

Implement Retry Logic

For transient errors like rate limiting or temporary server issues, implement retry logic with exponential backoff.

// Simplified example
async function makeRequestWithRetry(url, options, maxRetries = 3) {
  let retries = 0;
  
  while (retries < maxRetries) {
    try {
      const response = await fetch(url, options);
      if (response.status === 429) {
        // Rate limited, wait and retry
        const retryAfter = Math.pow(2, retries);
        await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
        retries++;
        continue;
      }
      
      return await response.json();
    } catch (error) {
      if (retries === maxRetries - 1 || error.code < 500) {
        throw error; // Don't retry client errors or if max retries reached
      }
      
      const delay = Math.pow(2, retries);
      await new Promise(resolve => setTimeout(resolve, delay * 1000));
      retries++;
    }
  }
}
4

Provide User-Friendly Messages

Translate technical error messages into user-friendly messages that help users understand what went wrong and how to fix it.

// Map API errors to user-friendly messages
const errorMessages = {
  'insufficient_funds': 'Your card has insufficient funds. Please use a different card.',
};

// Display appropriate message
const userMessage = errorMessages[error.message] || 'An error occurred. Please try again.';

Logging and Monitoring

Implement a robust logging system that captures:

  • Error codes and messages
  • Request IDs for correlation
  • Timestamps
  • Contextual information (without sensitive data)

Regularly review your error logs to identify patterns and improve your integration.

Next Steps