CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-stripe

Stripe API wrapper for Node.js providing comprehensive payment processing, subscription management, and financial services integration.

Pending
Overview
Eval results
Files

configuration.mddocs/

Configuration

Stripe's Node.js library provides comprehensive configuration options for authentication, request handling, error management, and advanced features. This documentation covers all configuration aspects from basic setup to advanced customization.

Basic Configuration

API Key Authentication

The primary method for authenticating with Stripe:

import Stripe from 'stripe';

// Basic initialization with API key
const stripe = new Stripe('sk_test_...', {
  apiVersion: '2025-08-27.basil',
  typescript: true
});

// Environment-based configuration
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
  apiVersion: '2025-08-27.basil',
  typescript: true
});

// Different keys for different environments
const apiKey = process.env.NODE_ENV === 'production' 
  ? process.env.STRIPE_LIVE_SECRET_KEY 
  : process.env.STRIPE_TEST_SECRET_KEY;

const stripe = new Stripe(apiKey!, {
  apiVersion: '2025-08-27.basil',
  typescript: true
});

Configuration Interface

Complete configuration options available:

interface StripeConfig {
  // API Configuration
  apiVersion?: '2025-08-27.basil';          // Latest stable API version
  typescript?: true;                        // Enable TypeScript support
  
  // Network Configuration  
  maxNetworkRetries?: number;              // Default: 1, max: 10
  timeout?: number;                        // Request timeout in ms (default: 80000)
  httpAgent?: HttpAgent;                   // Custom HTTP agent for proxies
  httpClient?: HttpClient;                 // Custom HTTP client implementation
  
  // Host Configuration
  host?: string;                          // API host override (default: api.stripe.com)
  port?: string | number;                 // API port override (default: 443)
  protocol?: 'http' | 'https';           // Protocol override (default: https)
  
  // Feature Configuration
  telemetry?: boolean;                    // Enable/disable telemetry (default: true)
  appInfo?: AppInfo;                      // Plugin identification
  
  // Account Configuration
  stripeAccount?: string;                 // Connect account for all requests
  stripeContext?: string;                 // Context for all requests
}

// Advanced configuration example
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
  apiVersion: '2025-08-27.basil',
  typescript: true,
  maxNetworkRetries: 3,
  timeout: 30000, // 30 seconds
  telemetry: false,
  appInfo: {
    name: 'MyApp',
    version: '1.0.0',
    url: 'https://myapp.com'
  }
});

Network Configuration

HTTP Agents and Proxies

Configure HTTP agents for proxy support and connection pooling:

import { HttpsAgent } from 'agentkeepalive';
import { Agent as HttpAgent } from 'http';
import { Agent as HttpsProxyAgent } from 'https-proxy-agent';

// Keep-alive agent for better performance
const keepAliveAgent = new HttpsAgent({
  keepAlive: true,
  maxSockets: 100,
  maxFreeSockets: 10,
  timeout: 60000,
  freeSocketTimeout: 30000
});

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
  httpAgent: keepAliveAgent,
  apiVersion: '2025-08-27.basil'
});

// Proxy configuration
const proxyAgent = new HttpsProxyAgent('http://proxy.company.com:8080');

const stripeWithProxy = new Stripe(process.env.STRIPE_SECRET_KEY!, {
  httpAgent: proxyAgent,
  apiVersion: '2025-08-27.basil'
});

// Custom HTTP client implementation
class CustomHttpClient {
  makeRequest(
    host: string,
    port: number,
    path: string,
    method: string,
    headers: { [key: string]: string },
    requestData: string,
    protocol: string,
    timeout: number
  ): Promise<any> {
    // Custom implementation with logging, metrics, etc.
    return fetch(`${protocol}://${host}:${port}${path}`, {
      method,
      headers,
      body: requestData,
      signal: AbortSignal.timeout(timeout)
    }).then(response => ({
      status: response.status,
      headers: Object.fromEntries(response.headers.entries()),
      body: response.text()
    }));
  }
}

const stripeWithCustomClient = new Stripe(process.env.STRIPE_SECRET_KEY!, {
  httpClient: new CustomHttpClient(),
  apiVersion: '2025-08-27.basil'
});

Retry Configuration

Configure automatic retry behavior for failed requests:

// Global retry configuration
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
  maxNetworkRetries: 5, // Retry up to 5 times
  apiVersion: '2025-08-27.basil'
});

// Per-request retry override
const customer = await stripe.customers.create({
  email: 'customer@example.com'
}, {
  maxNetworkRetries: 2 // Override global setting
});

// Custom retry logic with exponential backoff
class RetryableHttpClient {
  async makeRequest(...args: any[]): Promise<any> {
    const maxRetries = 3;
    let attempt = 0;
    
    while (attempt <= maxRetries) {
      try {
        return await this.performRequest(...args);
      } catch (error) {
        if (attempt === maxRetries || !this.shouldRetry(error)) {
          throw error;
        }
        
        const delay = Math.pow(2, attempt) * 1000; // Exponential backoff
        await new Promise(resolve => setTimeout(resolve, delay));
        attempt++;
      }
    }
  }
  
  private shouldRetry(error: any): boolean {
    // Retry on network errors and 5xx status codes
    return error.code === 'ECONNRESET' || 
           error.code === 'ENOTFOUND' ||
           (error.statusCode >= 500 && error.statusCode < 600);
  }
  
  private async performRequest(...args: any[]): Promise<any> {
    // Actual HTTP request implementation
  }
}

Timeout Configuration

Configure request timeouts at various levels:

// Global timeout configuration
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
  timeout: 15000, // 15 seconds for all requests
  apiVersion: '2025-08-27.basil'
});

// Per-request timeout
const paymentIntent = await stripe.paymentIntents.create({
  amount: 2000,
  currency: 'usd'
}, {
  timeout: 30000 // 30 seconds for this specific request
});

// Different timeouts for different operations
class TimeoutManager {
  private readonly timeouts = {
    create: 30000,   // 30s for creates
    update: 20000,   // 20s for updates
    list: 10000,     // 10s for lists
    retrieve: 5000   // 5s for retrievals
  };
  
  getTimeout(operation: keyof typeof this.timeouts): number {
    return this.timeouts[operation];
  }
}

const timeoutManager = new TimeoutManager();

// Use operation-specific timeouts
const customer = await stripe.customers.create({
  email: 'customer@example.com'
}, {
  timeout: timeoutManager.getTimeout('create')
});

Request Options

Per-Request Configuration

Override global settings for individual requests:

interface RequestOptions {
  apiKey?: string;                        // Override API key
  idempotencyKey?: string;               // Idempotency key for safe retries
  stripeAccount?: string;                // Connect account
  stripeContext?: string;                // Request context
  apiVersion?: string;                   // API version override
  maxNetworkRetries?: number;            // Retry limit override
  timeout?: number;                      // Timeout override
  host?: string;                         // Host override
}

// API key override for multi-tenant applications
const platformCustomer = await stripe.customers.create({
  email: 'platform@example.com'
}, {
  apiKey: process.env.PLATFORM_SECRET_KEY
});

// Connect account operations
const connectedAccountCharge = await stripe.charges.create({
  amount: 2000,
  currency: 'usd',
  source: 'tok_visa'
}, {
  stripeAccount: 'acct_connected_account_id'
});

// Idempotency for safe retries
const idempotentPayment = await stripe.paymentIntents.create({
  amount: 2000,
  currency: 'usd'
}, {
  idempotencyKey: `payment_${orderId}_${timestamp}`
});

// Context for request tracking
const contextualRequest = await stripe.customers.create({
  email: 'customer@example.com'
}, {
  stripeContext: 'signup_flow_step_3'
});

Idempotency Management

Implement robust idempotency for reliable operations:

class IdempotencyManager {
  private generateKey(prefix: string, data: any): string {
    const hash = require('crypto')
      .createHash('sha256')
      .update(JSON.stringify(data))
      .digest('hex')
      .substring(0, 16);
    
    return `${prefix}_${Date.now()}_${hash}`;
  }
  
  async createPaymentIntent(params: Stripe.PaymentIntentCreateParams): Promise<Stripe.PaymentIntent> {
    const idempotencyKey = this.generateKey('pi', params);
    
    return stripe.paymentIntents.create(params, {
      idempotencyKey
    });
  }
  
  async createCustomer(params: Stripe.CustomerCreateParams): Promise<Stripe.Customer> {
    // Use email as part of idempotency key for customers
    const keyData = { email: params.email, name: params.name };
    const idempotencyKey = this.generateKey('cus', keyData);
    
    return stripe.customers.create(params, {
      idempotencyKey
    });
  }
}

Error Handling

Error Types and Handling

Comprehensive error handling for different Stripe error types:

// All Stripe error types
interface StripeErrorTypes {
  StripeError: typeof Stripe.errors.StripeError;
  StripeCardError: typeof Stripe.errors.StripeCardError;
  StripeInvalidRequestError: typeof Stripe.errors.StripeInvalidRequestError;
  StripeAPIError: typeof Stripe.errors.StripeAPIError;
  StripeAuthenticationError: typeof Stripe.errors.StripeAuthenticationError;
  StripePermissionError: typeof Stripe.errors.StripePermissionError;
  StripeRateLimitError: typeof Stripe.errors.StripeRateLimitError;
  StripeConnectionError: typeof Stripe.errors.StripeConnectionError;
  StripeSignatureVerificationError: typeof Stripe.errors.StripeSignatureVerificationError;
  StripeIdempotencyError: typeof Stripe.errors.StripeIdempotencyError;
  StripeInvalidGrantError: typeof Stripe.errors.StripeInvalidGrantError;
  StripeUnknownError: typeof Stripe.errors.StripeUnknownError;
}

// Comprehensive error handling function
async function handleStripeOperation<T>(operation: () => Promise<T>): Promise<T> {
  try {
    return await operation();
  } catch (error) {
    if (error instanceof stripe.errors.StripeCardError) {
      // Card was declined
      throw new PaymentError(
        'Card declined',
        error.decline_code,
        error.code,
        error.payment_intent?.id
      );
    } else if (error instanceof stripe.errors.StripeInvalidRequestError) {
      // Invalid parameters
      throw new ValidationError(
        'Invalid request',
        error.param,
        error.code
      );
    } else if (error instanceof stripe.errors.StripeAuthenticationError) {
      // Authentication failed
      throw new AuthError('Authentication failed', error.code);
    } else if (error instanceof stripe.errors.StripePermissionError) {
      // Insufficient permissions
      throw new AuthorizationError('Insufficient permissions', error.code);
    } else if (error instanceof stripe.errors.StripeRateLimitError) {
      // Rate limited
      throw new RateLimitError('Rate limit exceeded', error.code);
    } else if (error instanceof stripe.errors.StripeConnectionError) {
      // Network error
      throw new NetworkError('Network error', error.code);
    } else if (error instanceof stripe.errors.StripeAPIError) {
      // API error
      throw new APIError('API error', error.code, error.statusCode);
    } else {
      // Unknown error
      throw new UnknownError('Unknown error', error);
    }
  }
}

// Usage example with proper error handling
async function processPayment(paymentIntentId: string): Promise<PaymentResult> {
  return handleStripeOperation(async () => {
    const paymentIntent = await stripe.paymentIntents.retrieve(paymentIntentId);
    
    if (paymentIntent.status === 'requires_payment_method') {
      throw new Error('Payment method required');
    }
    
    const confirmed = await stripe.paymentIntents.confirm(paymentIntentId);
    
    return {
      success: true,
      paymentIntent: confirmed
    };
  });
}

Retry Logic for Errors

Implement intelligent retry logic based on error types:

class StripeRetryHandler {
  private readonly retryableErrors = [
    'rate_limit',
    'api_connection_error',
    'api_error'
  ];
  
  async withRetry<T>(
    operation: () => Promise<T>,
    maxRetries: number = 3
  ): Promise<T> {
    let attempt = 0;
    
    while (attempt <= maxRetries) {
      try {
        return await operation();
      } catch (error) {
        if (!this.shouldRetry(error) || attempt === maxRetries) {
          throw error;
        }
        
        const delay = this.calculateDelay(attempt, error);
        await this.delay(delay);
        attempt++;
      }
    }
    
    throw new Error('Max retries exceeded');
  }
  
  private shouldRetry(error: any): boolean {
    if (error instanceof stripe.errors.StripeRateLimitError) {
      return true;
    }
    
    if (error instanceof stripe.errors.StripeAPIError) {
      return error.statusCode >= 500;
    }
    
    if (error instanceof stripe.errors.StripeConnectionError) {
      return true;
    }
    
    return false;
  }
  
  private calculateDelay(attempt: number, error: any): number {
    // Use Stripe's Retry-After header if available
    if (error instanceof stripe.errors.StripeRateLimitError) {
      const retryAfter = error.headers?.['retry-after'];
      if (retryAfter) {
        return parseInt(retryAfter) * 1000;
      }
    }
    
    // Exponential backoff with jitter
    const baseDelay = Math.pow(2, attempt) * 1000;
    const jitter = Math.random() * 1000;
    return baseDelay + jitter;
  }
  
  private delay(ms: number): Promise<void> {
    return new Promise(resolve => setTimeout(resolve, ms));
  }
}

// Usage
const retryHandler = new StripeRetryHandler();

const customer = await retryHandler.withRetry(() => 
  stripe.customers.create({
    email: 'customer@example.com'
  })
);

Advanced Configuration

App Information

Configure application metadata for better support:

interface AppInfo {
  name: string;
  version?: string;
  url?: string;
  partner_id?: string;
}

// Plugin/framework identification
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
  apiVersion: '2025-08-27.basil',
  appInfo: {
    name: 'MyEcommercePlugin',
    version: '2.1.0',
    url: 'https://github.com/mycompany/ecommerce-plugin',
    partner_id: 'pp_partner_123'
  }
});

// Dynamic app info based on environment
const getAppInfo = (): AppInfo => {
  const packageJson = require('./package.json');
  
  return {
    name: packageJson.name,
    version: packageJson.version,
    url: packageJson.homepage
  };
};

const stripeWithDynamicInfo = new Stripe(process.env.STRIPE_SECRET_KEY!, {
  apiVersion: '2025-08-27.basil',
  appInfo: getAppInfo()
});

Telemetry Configuration

Control telemetry data collection:

// Disable telemetry for privacy-sensitive applications
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
  apiVersion: '2025-08-27.basil',
  telemetry: false
});

// Conditional telemetry based on environment
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
  apiVersion: '2025-08-27.basil',
  telemetry: process.env.NODE_ENV === 'production'
});

Event Monitoring

Set up request/response monitoring:

// Request monitoring
stripe.on('request', (event: Stripe.RequestEvent) => {
  console.log('Request made:', {
    method: event.method,
    url: event.url,
    requestId: event.request_id
  });
  
  // Log to monitoring service
  monitoring.logRequest({
    method: event.method,
    path: event.path,
    requestId: event.request_id,
    timestamp: new Date()
  });
});

// Response monitoring
stripe.on('response', (event: Stripe.ResponseEvent) => {
  console.log('Response received:', {
    status: event.status_code,
    requestId: event.request_id,
    elapsed: event.elapsed
  });
  
  // Track performance metrics
  metrics.timing('stripe.request_duration', event.elapsed, {
    status_code: event.status_code.toString(),
    method: event.method
  });
  
  // Alert on errors
  if (event.status_code >= 400) {
    alerting.notifyError('Stripe API Error', {
      statusCode: event.status_code,
      requestId: event.request_id,
      elapsed: event.elapsed
    });
  }
});

// One-time event listeners
stripe.once('request', (event) => {
  console.log('First request made:', event.request_id);
});

// Remove event listeners
const requestHandler = (event: Stripe.RequestEvent) => {
  console.log('Request:', event.request_id);
};

stripe.on('request', requestHandler);
// Later...
stripe.off('request', requestHandler);

Environment-Specific Configuration

Multi-Environment Setup

Configure Stripe for different environments:

interface StripeEnvironmentConfig {
  apiKey: string;
  webhookSecret: string;
  publishableKey: string;
  connectClientId?: string;
}

class StripeConfigManager {
  private configs: Record<string, StripeEnvironmentConfig> = {
    development: {
      apiKey: process.env.STRIPE_TEST_SECRET_KEY!,
      webhookSecret: process.env.STRIPE_TEST_WEBHOOK_SECRET!,
      publishableKey: process.env.STRIPE_TEST_PUBLISHABLE_KEY!,
      connectClientId: process.env.STRIPE_TEST_CONNECT_CLIENT_ID
    },
    staging: {
      apiKey: process.env.STRIPE_STAGING_SECRET_KEY!,
      webhookSecret: process.env.STRIPE_STAGING_WEBHOOK_SECRET!,
      publishableKey: process.env.STRIPE_STAGING_PUBLISHABLE_KEY!,
      connectClientId: process.env.STRIPE_STAGING_CONNECT_CLIENT_ID
    },
    production: {
      apiKey: process.env.STRIPE_LIVE_SECRET_KEY!,
      webhookSecret: process.env.STRIPE_LIVE_WEBHOOK_SECRET!,
      publishableKey: process.env.STRIPE_LIVE_PUBLISHABLE_KEY!,
      connectClientId: process.env.STRIPE_LIVE_CONNECT_CLIENT_ID
    }
  };
  
  createStripeInstance(environment: string = process.env.NODE_ENV || 'development'): Stripe {
    const config = this.configs[environment];
    
    if (!config) {
      throw new Error(`No Stripe configuration found for environment: ${environment}`);
    }
    
    return new Stripe(config.apiKey, {
      apiVersion: '2025-08-27.basil',
      typescript: true,
      maxNetworkRetries: environment === 'production' ? 3 : 1,
      timeout: environment === 'production' ? 30000 : 10000,
      telemetry: environment === 'production',
      appInfo: {
        name: 'MyApp',
        version: process.env.APP_VERSION || '1.0.0'
      }
    });
  }
  
  getConfig(environment: string = process.env.NODE_ENV || 'development'): StripeEnvironmentConfig {
    return this.configs[environment];
  }
}

// Usage
const configManager = new StripeConfigManager();
const stripe = configManager.createStripeInstance();
const config = configManager.getConfig();

Security Best Practices

Implement security best practices for configuration:

// Secure configuration loading
class SecureStripeConfig {
  private static instance: SecureStripeConfig;
  private stripe: Stripe;
  
  private constructor() {
    // Validate required environment variables
    this.validateEnvironment();
    
    // Create Stripe instance with security measures
    this.stripe = new Stripe(this.getSecureApiKey(), {
      apiVersion: '2025-08-27.basil',
      typescript: true,
      telemetry: this.isTelemetryEnabled(),
      timeout: this.getTimeout(),
      maxNetworkRetries: this.getMaxRetries()
    });
    
    // Set up security monitoring
    this.setupSecurityMonitoring();
  }
  
  static getInstance(): SecureStripeConfig {
    if (!SecureStripeConfig.instance) {
      SecureStripeConfig.instance = new SecureStripeConfig();
    }
    return SecureStripeConfig.instance;
  }
  
  getStripe(): Stripe {
    return this.stripe;
  }
  
  private validateEnvironment(): void {
    const required = ['STRIPE_SECRET_KEY'];
    const missing = required.filter(key => !process.env[key]);
    
    if (missing.length > 0) {
      throw new Error(`Missing required environment variables: ${missing.join(', ')}`);
    }
    
    // Validate API key format
    const apiKey = process.env.STRIPE_SECRET_KEY!;
    if (!apiKey.startsWith('sk_')) {
      throw new Error('Invalid Stripe API key format');
    }
    
    // Warn about test keys in production
    if (process.env.NODE_ENV === 'production' && apiKey.includes('test')) {
      throw new Error('Test API key detected in production environment');
    }
  }
  
  private getSecureApiKey(): string {
    const apiKey = process.env.STRIPE_SECRET_KEY!;
    
    // Additional security checks
    if (apiKey.length < 32) {
      throw new Error('API key appears to be invalid');
    }
    
    return apiKey;
  }
  
  private setupSecurityMonitoring(): void {
    // Monitor for suspicious patterns
    this.stripe.on('request', (event) => {
      // Log all API requests for security audit
      securityLogger.log('stripe_request', {
        method: event.method,
        url: event.url,
        requestId: event.request_id,
        timestamp: new Date(),
        userAgent: event.user_agent
      });
    });
  }
  
  private isTelemetryEnabled(): boolean {
    return process.env.STRIPE_TELEMETRY !== 'false';
  }
  
  private getTimeout(): number {
    return parseInt(process.env.STRIPE_TIMEOUT || '30000');
  }
  
  private getMaxRetries(): number {
    return parseInt(process.env.STRIPE_MAX_RETRIES || '3');
  }
}

// Usage
const secureConfig = SecureStripeConfig.getInstance();
const stripe = secureConfig.getStripe();

This comprehensive configuration system provides the foundation for robust, secure, and maintainable Stripe integrations across all environments and use cases.

Install with Tessl CLI

npx tessl i tessl/npm-stripe

docs

billing.md

checkout.md

configuration.md

core-resources.md

identity.md

index.md

issuing.md

radar.md

subscriptions.md

tax.md

terminal.md

treasury.md

webhooks.md

tile.json