5 min read

Handle Stripe Errors

This guide explains best practices for handling errors in your Stripe integration.

Error Handling Strategy

  1. Validate Early

    • Check inputs before API calls
    • Verify required fields
    • Validate formats
  2. Handle Gracefully

    • Show user-friendly messages
    • Log errors for debugging
    • Provide recovery options
  3. Recover Automatically

    • Refresh expired keys
    • Retry failed operations
    • Fall back gracefully

Implementation Examples

Basic Error Handler

class StripeErrorHandler {
  static async handle(error: any) {
    // 1. Convert to standard format
    const standardError = this.standardizeError(error);
    
    // 2. Log error
    this.logError(standardError);
    
    // 3. Try recovery
    await this.attemptRecovery(standardError);
    
    // 4. Show user message
    return this.getUserMessage(standardError);
  }

  static standardizeError(error: any): ErrorResponse {
    if (error.code) return error;
    return {
      status: error.status || 500,
      code: error.code || 6778099,
      message: error.message || 'Unknown error'
    };
  }
}

Checkout Error Handling

async function handleCheckout() {
  try {
    // 1. Validate inputs
    validateCheckoutData(data);
    
    // 2. Create checkout
    const response = await iaptic.createStripeCheckout(data);
    
    // 3. Store access key
    localStorage.setItem('stripe_access_key', response.accessKey);
    
    // 4. Redirect
    window.location.href = response.url;
  }
  catch (error) {
    const message = await StripeErrorHandler.handle(error);
    showErrorToUser(message);
  }
}

Webhook Error Handling

async function handleWebhook(req: Request, res: Response) {
  try {
    // 1. Verify signature
    const event = verifyWebhookSignature(req);
    
    // 2. Process event
    await processStripeEvent(event);
    
    // 3. Return success
    res.json({ ok: true });
  }
  catch (error) {
    // Log error details
    logger.error('Webhook error:', {
      error,
      body: req.body,
      headers: req.headers
    });
    
    // Return appropriate status
    const status = error.code === 6778005 ? 401 : 500;
    res.status(status).json({
      error: error.message
    });
  }
}

Common Error Scenarios

1. Invalid Access Key

try {
  await iaptic.getPurchases();
} catch (error) {
  if (error.code === 6778003) {
    // Clear invalid key
    localStorage.removeItem('stripe_access_key');
    
    // Redirect to login
    window.location.href = '/login';
  }
}

2. Configuration Error

try {
  await iaptic.createStripeCheckout(data);
} catch (error) {
  if (error.code === 6778030) {
    // Show admin message
    showAdminAlert('Stripe configuration missing');
    
    // Log details
    logger.error('Stripe config error:', error);
  }
}

3. Network Error

class RetryHandler {
  static async withRetry<T>(
    operation: () => Promise<T>,
    maxRetries = 3
  ): Promise<T> {
    for (let i = 0; i < maxRetries; i++) {
      try {
        return await operation();
      } catch (error) {
        if (!this.isRetryable(error) || i === maxRetries - 1) {
          throw error;
        }
        await this.delay(Math.pow(2, i) * 1000);
      }
    }
    throw new Error('Max retries exceeded');
  }
}

Best Practices

  1. Error Logging

    • Log with context
    • Include request details
    • Use structured format
    • Set appropriate levels
  2. User Experience

    • Show clear messages
    • Provide next steps
    • Maintain context
    • Enable self-recovery
  3. Monitoring

    • Track error rates
    • Set up alerts
    • Monitor recovery
    • Analyze patterns
  4. Testing

    • Test error paths
    • Verify recovery
    • Check logging
    • Validate messages