Stripe API wrapper for Node.js providing comprehensive payment processing, subscription management, and financial services integration.
—
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.
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
});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'
}
});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'
});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
}
}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')
});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'
});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
});
}
}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
};
});
}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'
})
);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()
});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'
});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);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();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