How to add Stripe payment to NestJS

Updated: January 7, 2024 By: Guest Contributor Post a comment

Overview

Integrating payment systems into modern web applications is central to enabling e-commerce and monetizing services. One of the most popular payment gateways today is Stripe, known for its simplicity and robust API. In this guide, we’ll learn how to seamlessly integrate Stripe’s payment processing features into a NestJS application, an emerging JavaScript backend framework that leverages Node.js.

Setting Up NestJS

Before we delve into Stripe, ensure you have Node.js installed on your system. Create a new NestJS project by running npx @nestjs/cli new payment-app. Once inside your new ‘payment-app’ directory, install the Stripe NPM package with npm install stripe.

Establishing Stripe as a Service in NestJS

It’s best practice in NestJS to encapsulate external services as injectable providers. Let’s create a Stripe service.

import { Inject, Injectable } from '@nestjs/common';
import Stripe from 'stripe';

@Injectable()
export class StripeService {
  private stripe: Stripe;

  constructor() {
    this.stripe = new Stripe(process.env.STRIPE_SECRET_KEY, {
      apiVersion: '2024-08-27',
    });
  }
}

Take notice of the environment variable STRIPE_SECRET_KEY. You’ll need to retrieve your secret key from the Stripe dashboard and include it in your application’s environment variables.

Processing a Payment

To handle payments, we’ll need to create endpoints that interact with the Stripe API. A basic payment flow involves creating a charge.

@Injectable()
export class StripeService {
  // ... existing code ...

  async createCharge(amount: number, currency: string, source: string): Promise {
    return this.stripe.charges.create({
      amount,
      currency,
      source,
    });
  }
}

Add a controller to handle requests for payment:

@Post('charge')
async chargeCard(@Body() paymentData: PaymentDto) {
  return this.stripeService.createCharge(paymentData.amount, paymentData.currency, paymentData.source);
}

Above, we assume a PaymentDto class is already defined to handle the payment data input.

Working with Webhooks

Stripe uses webhooks to notify your application of events happening on your Stripe account. Setting up a webhook endpoint involves validating Stripe events.

@Post('webhook')
@Header('Content-Type', 'application/json')
async webhook(@Req() request: Request, @Res() response: Response) {
  const sig = request.headers['stripe-signature'];

  let event;

  try {
    event = this.stripe.webhooks.constructEvent(request.body, sig, process.env.STRIPE_ENDPOINT_SECRET);
  } catch (err) {
    return response.status(400).send(`Webhook Error: ${err.message}`);
  }

  // Handle the event...
  response.status(200).send({ received: true });
}

Don’t forget to replace STRIPE_ENDPOINT_SECRET with your actual endpoint signing secret obtained from Stripe’s webhook settings.

Advanced Features

Although a simple charge creation was covered, complex applications may require subscriptions, and customer management, amongst other features. Stripe’s API is vast, and fortunately, NestJS’s modular structure allows for easy expansion of services.

To manage subscriptions:

//... stripe service methods ...

async createSubscription(customerId: string, priceId: string): Promise {
  return this.stripe.subscriptions.create({
    customer: customerId,
    items: [{ price: priceId }],
  });
}

Customer management:

//... stripe service methods ...

async createCustomer(email: string): Promise {
  return this.stripe.customers.create({ email });
}

Conclusion

In the stream of transactions, your NestJS reeds must be nimble enough to sway with the ebb and flow of commerce. Sprinkle the magic of Stripe within your NestJS pond, and your application will hum with the currents of financial exchange. This guide paddled you through the silent waters of beginning the integration, may your journey downstream handle the complexities your business demands.