NestJS
Stripe Payment Integration
Integrating Stripe for processing payments and handling webhooks in NestJS.
Stripe Service: Service for initializing Stripe and creating a payment intent.
payment.service.ts
typescript
import { Injectable, ConfigService } from '@nestjs/common';
import Stripe from 'stripe';
@Injectable()
export class PaymentService {
private stripe: Stripe;
constructor(private configService: ConfigService) {
// Initialize Stripe with the secret key
this.stripe = new Stripe(this.configService.get<string>('STRIPE_SECRET_KEY'), {
apiVersion: '2023-10-16', // Use the latest supported API version
});
}
async createPaymentIntent(amount: number, currency: string = 'usd') {
try {
const paymentIntent = await this.stripe.paymentIntents.create({
amount: amount * 100, // Stripe expects amount in cents
currency,
automatic_payment_methods: {
enabled: true,
},
});
return {
clientSecret: paymentIntent.client_secret,
};
} catch (error) {
throw new Error(`Payment processing failed: ${error.message}`);
}
}
constructWebhookEvent(payload: Buffer, signature: string) {
const webhookSecret = this.configService.get<string>('STRIPE_WEBHOOK_SECRET');
return this.stripe.webhooks.constructEvent(payload, signature, webhookSecret);
}
}
Payment Controller: Endpoints for initiating payments and receiving Stripe webhook events.
payment.controller.ts
typescript
import { Controller, Post, Body, Req, Headers, RawBodyRequest, BadRequestException } from '@nestjs/common';
import { PaymentService } from './payment.service';
@Controller('payment')
export class PaymentController {
constructor(private readonly paymentService: PaymentService) {}
@Post('create-intent')
async createPaymentIntent(@Body() body: { amount: number; currency?: string }) {
return await this.paymentService.createPaymentIntent(body.amount, body.currency);
}
@Post('webhook')
async handleWebhook(
@Headers('stripe-signature') signature: string,
@Req() req: RawBodyRequest<Request>,
) {
if (!signature) {
throw new BadRequestException('Missing stripe-signature header');
}
try {
// Must use raw body for webhook signature verification
const event = this.paymentService.constructWebhookEvent(req.rawBody, signature);
// Handle the event
switch (event.type) {
case 'payment_intent.succeeded':
const paymentIntent = event.data.object;
console.log(`PaymentIntent for ${paymentIntent.amount} was successful!`);
// Fulfill order, update database, etc.
break;
case 'payment_intent.payment_failed':
console.log('Payment failed!');
break;
default:
console.log(`Unhandled event type ${event.type}`);
}
return { received: true };
} catch (err) {
throw new BadRequestException(`Webhook Error: ${err.message}`);
}
}
}