<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Sachith Wickramasekara</title>
    <description>The latest articles on DEV Community by Sachith Wickramasekara (@sachith_wickramasekara_3c).</description>
    <link>https://dev.to/sachith_wickramasekara_3c</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1984306%2Fe1bb3540-de91-4bd9-8012-ff528088adf9.jpg</url>
      <title>DEV Community: Sachith Wickramasekara</title>
      <link>https://dev.to/sachith_wickramasekara_3c</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sachith_wickramasekara_3c"/>
    <language>en</language>
    <item>
      <title>🚀 Stripe Integration with NestJS + TypeORM: Let's Make It Happen! 💳💻</title>
      <dc:creator>Sachith Wickramasekara</dc:creator>
      <pubDate>Sun, 06 Oct 2024 18:02:06 +0000</pubDate>
      <link>https://dev.to/sachith_wickramasekara_3c/stripe-integration-with-nestjs-typeorm-lets-make-it-happen-3b</link>
      <guid>https://dev.to/sachith_wickramasekara_3c/stripe-integration-with-nestjs-typeorm-lets-make-it-happen-3b</guid>
      <description>&lt;p&gt;Hey there, dev community! 👋 Are you building a cool app and want to handle payments like a pro? Look no further! Today, we’re diving into Stripe integration with NestJS (using TypeORM 🗄️), and I’ll walk you through the steps to get everything up and running smoothly 😉. Let's dive right in! 🚀&lt;/p&gt;

&lt;p&gt;Step 1: First Things First — Stripe Keys 🔐&lt;br&gt;
Before we do anything, you’ll need to grab your Stripe Public and Secret Keys from the &lt;a href="https://dashboard.stripe.com" rel="noopener noreferrer"&gt;Stripe Dashboard&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;🎟️ These keys are important because:&lt;/p&gt;

&lt;p&gt;Public Key: This is used on the frontend to securely send card details to Stripe.&lt;br&gt;
Secret Key: This stays in the backend and allows us to perform actions like creating customers, payment intents, etc. (💰 we don't want this to leak!)&lt;br&gt;
How to connect them in NestJS? Well, let’s use .env to store these keys securely!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# In .env
STRIPE_PUBLIC_KEY=pk_test_123
STRIPE_API_KEY=sk_test_456
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, you can inject this into your NestJS project using @nestjs/config. We’ll use this in our StripeModule. Keep reading! 😉&lt;/p&gt;

&lt;p&gt;Step 2: Setting Up Stripe in NestJS ⚙️&lt;br&gt;
Alright, let’s install what we need in our NestJS project!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install @nestjs/config stripe @types/stripe
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, create a Stripe module. Here’s the code to get that rolling:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Module({
  imports: [TypeOrmModule.forFeature([UserDetails])],
  controllers: [StripeController],
  providers: [
    StripeService,
    {
      provide: 'STRIPE_API_KEY',
      useFactory: async (configService: ConfigService) =&amp;gt;
        configService.get('STRIPE_API_KEY'),
      inject: [ConfigService],
    },
  ],
  exports: [StripeService],
})
export class StripeModule {}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We import the UserDetails entity because we’ll be linking payments to users later! 🙌&lt;/p&gt;

&lt;p&gt;Step 3: The Flow of Payments 💳&lt;br&gt;
Stripe payments follow a simple but powerful flow. Here's a bird's eye view of what we'll be doing:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Be a Stripe customer 🧑‍💼&lt;/li&gt;
&lt;li&gt;Create a payment intent 💡&lt;/li&gt;
&lt;li&gt;Attach payment methods 💳&lt;/li&gt;
&lt;li&gt;Confirm the payment intent 🔒&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let’s break these steps down further! 📝👇&lt;/p&gt;

&lt;p&gt;Step 4: Creating the Stripe Service 🛠️&lt;br&gt;
First, we’ll initialize Stripe in our service by creating a stripe instance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import Stripe from 'stripe';

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

  constructor(
    @Inject('STRIPE_API_KEY') private readonly apiKey: string,
  ) {
    this.stripe = new Stripe(this.apiKey, {
      apiVersion: '2024-06-20',
    });
  }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s it! 🎉 Now our service is ready to handle all Stripe-related operations!&lt;/p&gt;

&lt;p&gt;Step 5: Be a Stripe Customer 👥&lt;br&gt;
Before you can make any payments, you need to create a customer in Stripe! Here's a neat way to do it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const stripeCustomer = await this.stripe.customers.create({
  email: 'john.doe@example.com',
  name: 'John Doe',
  phone: '555-555-5555',
  address: {
    line1: '123 NestJS St.',
    city: 'Codingville',
    country: 'US',
  },
  metadata: {
    userId: '12345', // Store anything you like here!
  },
});

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can save the stripeCustomer.id to your database (in the UserDetails table or elsewhere). Don’t worry, you can always edit the details later! ✏️&lt;/p&gt;

&lt;p&gt;Step 6: Creating Payment Intents 🎯&lt;br&gt;
Now that you're a Stripe customer, let’s talk about creating a payment intent. The payment intent will tell Stripe how much to charge, which currency to use, and which payment methods are acceptable (we’ll use 'card' in this case 💳).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;async createPaymentIntent(
  amount: number,
  currency: string,
): Promise&amp;lt;Stripe.PaymentIntent&amp;gt; {
  try {
    const paymentIntent = await this.stripe.paymentIntents.create({
      amount,
      currency,
      payment_method_types: ['card'],
    });
    this.logger.log('Payment Intent created successfully');
    return paymentIntent;
  } catch (error) {
    this.logger.error('Failed to create Payment Intent', error.stack);
    throw new Error('Unable to create Payment Intent');
  }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Post('create-payment-intent')
  async createPaymentIntent(
    @Body('amount') amount: number,
    @Body('currency') currency: string,
  ): Promise&amp;lt;{ paymentIntentId: string }&amp;gt; {
    try {
      const paymentIntent = await this.stripeService.createPaymentIntent(
        amount,
        currency,
      );
      this.logger.log('Payment Intent created successfully');
      return { paymentIntentId: paymentIntent.id };
    } catch (error) {
      this.logger.error('Failed to create Payment Intent', error.stack);
      throw new HttpException(
        'Failed to create Payment Intent',
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don't forget! After creating the intent, Stripe gives you a paymentIntent.id — store this in local storage or your database for future use! 📦&lt;/p&gt;

&lt;p&gt;Step 7: Adding Payment Methods 💳&lt;br&gt;
Once you have a payment intent, you'll need a payment method. This links the customer’s payment details (like a card) to their account.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;async addingPaymentMethod(
    userId: string,
    paymentMethodId: string,
  ): Promise&amp;lt;Stripe.PaymentMethod&amp;gt; {
    try {
      const userDetails = await this.userDetailsRepository.findOne({
        where: { userID: userId },
      });

      const paymentMethod = await this.stripe.paymentMethods.attach(
        paymentMethodId,
        {
          customer: userDetails.stripeCustomerId,
        },
      );

       return paymentMethod;
    } catch (error) {
      this.logger.error('Failed to add payment method', error.stack);
      throw error;
    }
  }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; @Post('add-payment-method')
  async addPaymentMethod(
    @AuthenticatedUser() user: any,
    @Body('paymentMethodId') paymentMethodId: string,
  ): Promise&amp;lt;Stripe.PaymentMethod&amp;gt; {
    try {
      const paymentMethod = await this.stripeService.addPaymentMethod(
        user.sub,
        paymentMethodId,
      );
      this.logger.log('Payment method added successfully');
      return paymentMethod;
    } catch (error) {
      this.logger.error('Failed to add payment method', error.stack);
      throw new HttpException(
        'Failed to add payment method',
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;👉 Note: You’ll need the Stripe customer ID (from Step 5) to attach a payment method!&lt;/p&gt;

&lt;p&gt;Step 8: Retrieving Payment Methods 📝&lt;br&gt;
Want to see all payment methods a customer has? You can easily fetch them using the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;async retrievePaymentMethods(
    userId: string,
  ): Promise&amp;lt;Stripe.PaymentMethod[]&amp;gt; {
    try {
      const userDetails = await this.userDetailsRepository.findOne({
        where: { userID: userId },
      });
      const paymentMethods = await this.stripe.paymentMethods.list({
        customer: userDetails.stripeCustomerId,
        type: 'card',
      });
      return paymentMethods.data;
    } catch (error) {
      this.logger.error('Failed to fetch payment methods', error.stack);
      throw error;
    }
  }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  @Get('get-payment-methods')
  async retrievePaymentMethods(
    @AuthenticatedUser() user: any,
  ): Promise&amp;lt;Stripe.PaymentMethod[]&amp;gt; {
    try {
      const paymentMethods = await this.stripeService.retrievePaymentMethods(
        user.sub,
      );
      this.logger.log('Payment methods fetched successfully');
      return paymentMethods;
    } catch (error) {
      this.logger.error('Failed to fetch payment methods', error.stack);
      throw new HttpException(
        'Failed to fetch payment methods',
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Stripe will return a payment method ID for every card added. 🛠️ Use it to confirm payments!&lt;/p&gt;

&lt;p&gt;Step 9: Confirming the Payment Intent ✅&lt;br&gt;
The final piece is to confirm the payment intent. To do this, you need both the paymentIntentId and the paymentMethodId.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;async paymentConfirmation(
    paymentIntentId: string,
    paymentMethodId: string,
  ): Promise&amp;lt;Stripe.PaymentIntent&amp;gt; {
    try {
      const confirmedPaymentIntent = await this.stripe.paymentIntents.confirm(
        paymentIntentId,
        {
          payment_method: paymentMethodId,
        },
      );
      return confirmedPaymentIntent;
    } catch (error) {
      this.logger.error('Failed to confirm Payment Intent', error.stack);
      throw new Error('Unable to confirm Payment Intent');
    }
  }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  @Post('confirm-payment-intent')
  async confirmPaymentIntent(
    @Body('paymentIntentId') paymentIntentId: string,
    @Body('paymentMethodId') paymentMethodId: string,
    @AuthenticatedUser() user: any,
  ): Promise&amp;lt;Stripe.PaymentIntent&amp;gt; {
    try {
      const paymentIntent = await this.stripeService.confirmPaymentIntent(
        paymentIntentId,
        paymentMethodId,
        user.sub,
      );
      this.logger.log('Payment Intent confirmed successfully');
      return paymentIntent;
    } catch (error) {
      this.logger.error('Failed to confirm Payment Intent', error.stack);
      throw new HttpException(
        'Failed to confirm Payment Intent',
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the payment is confirmed, you can remove the paymentIntentId from local storage and redirect the user to a success screen! 🎉&lt;/p&gt;

&lt;p&gt;🎬 Wrapping It Up&lt;/p&gt;

&lt;p&gt;And that’s a wrap! 🎁 Integrating Stripe with NestJS isn’t rocket science, but with this guide, you’ll have a smooth ride from start to finish. 🌟 You'll be able to handle payments like a boss, and your users will love the seamless experience!&lt;/p&gt;

&lt;p&gt;Have fun coding, and happy transactions! 💸&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
