<?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>Forem: Antwi Isaac</title>
    <description>The latest articles on Forem by Antwi Isaac (@okraks).</description>
    <link>https://forem.com/okraks</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%2F1099480%2F8033e6f8-38e4-4fd0-b870-a47ac8b7632e.JPG</url>
      <title>Forem: Antwi Isaac</title>
      <link>https://forem.com/okraks</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/okraks"/>
    <language>en</language>
    <item>
      <title>Yet Another Article to Dockerizing An App — But with a twist</title>
      <dc:creator>Antwi Isaac</dc:creator>
      <pubDate>Sun, 31 Aug 2025 11:12:16 +0000</pubDate>
      <link>https://forem.com/okraks/yet-another-article-to-dockerizing-an-app-but-with-a-twist-ii9</link>
      <guid>https://forem.com/okraks/yet-another-article-to-dockerizing-an-app-but-with-a-twist-ii9</guid>
      <description>&lt;p&gt;Do-cker... doc-ker…. dock-er. You’ve probably heard this term so much and you’re wondering what the fuss is. What is it? Do I need it? Does it make a difference? I’ve been building apps without Docker just fine… I hear you. Just hold my mug.…&lt;/p&gt;

&lt;p&gt;Officially, “docker is a tool that helps you develop, ship and run applications within lightweight containers.” Okay.. but what does this mean?&lt;/p&gt;

&lt;p&gt;Say you’re building the next billion dollar app with your friend. You’re using a windows laptop while he’s using a mac. You make some changes to the code and push your updates to Github. He then pulls your updates and tries to run the application — damn, it doesn’t work. Ei? You jump on a Zoom call and show him that it works fine on your laptop; he then shares his screen and shows you a weird error… well, that’s awkward. It works fine on your machine, but it doesn’t on his. Why?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxwszyw8o5irop1zz0bei.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxwszyw8o5irop1zz0bei.gif" alt="It doesn't work on his machine" width="248" height="200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For some kinds of apps, this wouldn’t have been an issue. Your todo app built using HTML, CSS and JavaScript maybe fine ;). However, other apps, for example, a NodeJS service that requires specific OS-level drivers / packages to work would easily run into compatibility issues — Windows and MacOS are fundamentally different. Also remember that the server your application would be deployed on might come with a different OS, setup and environment.&lt;/p&gt;

&lt;p&gt;That’s where docker comes into play. What if in building, testing and deploying, you can have the same “configuration” used everywhere? You share that “configuration” with your friend, deploy it on your production server and it runs — just like magic, except that it’s not magic *wink.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lets dive into Docker: Concepts
&lt;/h2&gt;

&lt;p&gt;To get started with Docker, download Docker Desktop here: &lt;a href="https://www.docker.com/get-started" rel="noopener noreferrer"&gt;https://www.docker.com/get-started&lt;/a&gt;. It installs a GUI you can use as well as the command line tools.&lt;/p&gt;

&lt;p&gt;At the core of docker, there are three concepts to understand: Dockerfile, Images and Containers.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Dockerfile
&lt;/h3&gt;

&lt;p&gt;It is text file with instructions on how to build a Docker image. Think of the Dockerfile as a recipe or a blueprint. It contains all the instructions — step by step — to set up your application. You specify everything your app needs and how to run / start it in the Dockerfile.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Image
&lt;/h3&gt;

&lt;p&gt;Using the recipe (Dockerfile), you bake a cake (Image). Docker images are immutable, which means if you make any change to the Dockerfile and rebuild, you create a new image and do not modify the existing one (if any exist). Versions of an image are managed using tags.&lt;/p&gt;

&lt;p&gt;Images can be shared with other developers anywhere — just think of it as giving a file to someone. Many developers use DockerHub to share images. &lt;/p&gt;

&lt;p&gt;As an example, here’s the official MongoDB Image on Docker: &lt;a href="https://hub.docker.com/_/mongo" rel="noopener noreferrer"&gt;https://hub.docker.com/_/mongo&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3.Container
&lt;/h3&gt;

&lt;p&gt;A container is running instance of a Docker image. This is like eating or serving the cake to your guests. The image is static, but the container is a live process running inside of an isolated environment.&lt;/p&gt;

&lt;p&gt;Now that we’re clear with the basic concepts and rationale behind using docker, lets dockerize (create a Dockerfile, build an image and use that to spin up a container).&lt;/p&gt;

&lt;p&gt;Here’s the repo of what we’re building: &lt;a href="https://github.com/okraks/dockerizing-app-example" rel="noopener noreferrer"&gt;https://github.com/okraks/dockerizing-app-example&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a Dockerfile
&lt;/h2&gt;

&lt;p&gt;Create a Dockerfile in the root of your application. The Dockerfile contains instructions (remember the recipe?) on how to package and run your app.&lt;/p&gt;

&lt;p&gt;1.Set the base image: This command sets the base image (think of it as a minimal OS that can run processes, libraries, networking and a filesystem). In this command, I use the official NodeJS image from Docker hub (it has nodejs and npm already installed)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM node:18.11.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Set working directory: It’s usually good practice to set the working directory inside the container. All subsequent commands (COPY, RUN, etc.) will be executed inside /app. If /app doesn’t exist, it will be created automatically.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WORKDIR /app 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Copy package.json and yarn.lock into the /app directory: This is a common optimization. You copy dependency files first, then run yarn install, so Docker can cache that layer if your dependencies haven’t changed everytime you rebuild the image.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;COPY ./package.json ./yarn.lock /app/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Install Dependencies: RUN executes a command at build time (in contrast to CMD which runs at container start). This installs all dependencies listed in package.json using yarn.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;RUN yarn install --frozen-lockfile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Copy code in src folder into docker: Copies your app’s source code from your local ./src folder into the container’s /app/src directory.
The syntax means COPY “from”  “into” 
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;COPY ./src /app/src
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Start the application. Similar to running yarn dev to invoke the dev script in package.json. CMD defines the default command that runs when the container starts. For production builds, you’d use “yarn start”
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CMD ["yarn", "dev"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Build the Image
&lt;/h2&gt;

&lt;p&gt;Now that we have our instructions (Dockerfile), we can build our image using the command bellow. The flag -t assigns a name (and optionally a tag using syntax name:tag) to the image you’re building. The full stop is to point to the current folder we’re in.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker build -t our_awesome_app .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So now we have an image called “our_awesome_app” and we can start a container using it, or even share it.&lt;/p&gt;

&lt;p&gt;Here’s the example image shared on DockerHub: &lt;a href="https://hub.docker.com/r/okraks/dockerizing-app-example" rel="noopener noreferrer"&gt;https://hub.docker.com/r/okraks/dockerizing-app-example&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Start a Container using the Image
&lt;/h2&gt;

&lt;p&gt;This command tells docker take the image “our_awesome_app” and start a new container using it. If the image doesn’t exist locally, it would try to pull it from DockerHub or any other registry.&lt;br&gt;
“-p” is the port mapping flag. It connects a port inside the container to a port on your machine (the host). In our app, we started our server on PORT 8080 so we expose that same PORT from our container to our host machine. The syntax is &lt;br&gt;
&lt;code&gt;-p &amp;lt;host_port&amp;gt;:&amp;lt;container_port&amp;gt;&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run -p 8080:8080 our_awesome_app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s it! Your application is running now and is available on your laptop on port 8080. In another article, we’d explore a setup of several applications (for example, a frontend, a database server and a backend service) using a popular library: docker-compose.&lt;/p&gt;

&lt;p&gt;Enough talk. Time to build.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;Resources&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Learn Docker in 7 Easy Steps — Full Beginner’s Tutorial&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=gAkwW2tuIqE" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=gAkwW2tuIqE&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Only Docker Tutorial You Need To Get Started &lt;a href="https://youtu.be/DQdB7wFEygo" rel="noopener noreferrer"&gt;https://youtu.be/DQdB7wFEygo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Docker Docs&lt;br&gt;
&lt;a href="https://docs.docker.com/get-started/docker-overview/" rel="noopener noreferrer"&gt;https://docs.docker.com/get-started/docker-overview/&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Seamless Payments with Stripe: A Developer’s Guide to Easy Integration</title>
      <dc:creator>Antwi Isaac</dc:creator>
      <pubDate>Sat, 16 Aug 2025 17:35:16 +0000</pubDate>
      <link>https://forem.com/okraks/seamless-payments-with-stripe-a-developers-guide-to-easy-integration-23h5</link>
      <guid>https://forem.com/okraks/seamless-payments-with-stripe-a-developers-guide-to-easy-integration-23h5</guid>
      <description>&lt;p&gt;Stripe has firmly established itself as a leader in payment processing, simplifying the payment acceptance process for developers. In this guide, we’ll walk through setting up a Node.js Express service integrated with Stripe using Checkout Sessions. We’ll focus solely on Checkout Sessions for a hands-on introduction. For other integration options, view the docs here: Stripe Payment Options&lt;/p&gt;




&lt;h2&gt;
  
  
  High Level Design &amp;amp; Flow
&lt;/h2&gt;

&lt;p&gt;Before diving into the code, here’s a high-level overview of the integration process.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Gotchas &amp;amp; Things to Note&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Handle Currency and Amount Formatting&lt;/strong&gt;: Stripe expects amounts in minor units (e.g., $10.00 should be passed as 1000 cents).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use Webhooks for Reliable Payment Confirmation&lt;/strong&gt;: Don’t rely on the client-side redirect for payment status.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Ensure Metadata is Passed Correctly&lt;/strong&gt;: To track payments efficiently&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Enable Webhook Signature Verification&lt;/strong&gt;: Always verify Stripe webhook signatures to prevent unauthorized or spoofed events.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fv2%2Fresize%3Afit%3A2000%2Fformat%3Awebp%2F1%2AJvooLNaIt3BNcvAzZTBz-Q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fv2%2Fresize%3Afit%3A2000%2Fformat%3Awebp%2F1%2AJvooLNaIt3BNcvAzZTBz-Q.png" alt="image" width="800" height="565"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Let’s Code 🚀
&lt;/h2&gt;

&lt;p&gt;1.Initialise a package.json file&lt;br&gt;
&lt;code&gt;yarn init -y&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;2.Install dependencies&lt;br&gt;
&lt;code&gt;yarn add express stripe dotenv&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;3.Install dev dependencies.&lt;br&gt;
&lt;code&gt;yarn add -D nodemon typescript @types/express @types/node&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;4.Initialise Typescript&lt;br&gt;
This would create a new tsconfig.json file that tells typescript how to transpile our app&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npx tsc --init&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;5.Update your scripts in package.json&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"scripts": {
    "build": "yarn install &amp;amp;&amp;amp; tsc",
    "dev": "nodemon src/server.ts",
    "start": "node dist/server.js"
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your package.json should look like this&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fv2%2Fresize%3Afit%3A1290%2Fformat%3Awebp%2F1%2A7QztoZHbB_reV6iV-kg7vQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fv2%2Fresize%3Afit%3A1290%2Fformat%3Awebp%2F1%2A7QztoZHbB_reV6iV-kg7vQ.png" alt="package.json" width="645" height="499"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;6.Create your src folder and create a server.ts file in it&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import express, { Request, Response } from "express";
import dotenv from "dotenv";
import Stripe from "stripe";

// Environment config
dotenv.config();

// Stripe initialization
let _stripe: Stripe | null = null;
export const getStripe = (): Stripe =&amp;gt; {
  if (!_stripe) {
    _stripe = new Stripe(process.env.STRIPE_TEST_KEY as string);
  }
  return _stripe;
};

// create an express app
const app = express();

// Express Middleware setup
app.use(express.json());

const port = process.env.PORT || 3001;

// Default Route
app.get("/", (_, res) =&amp;gt; {
  res.status(200).json({
    success: true,
    message: "Our express app is live!",
  });
});

// Start Server
app.listen(port, () =&amp;gt; {
  console.log(`🚀 Server up and running on port: ${port}`);
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;7.Create an .env file in the root of your project&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PORT=8080
STRIPE_TEST_KEY=your_stripe_test_key
STRIPE_WEBHOOK_SECRET=stripe_webhook_secret
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Follow this guide to obtain your Stripe Test Key: &lt;a href="https://docs.stripe.com/keys" rel="noopener noreferrer"&gt;https://docs.stripe.com/keys&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;8.Our app is ready... well almost. Run yarn dev to start the server. You should get this feedback.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fv2%2Fresize%3Afit%3A1324%2Fformat%3Awebp%2F1%2AMhWOn0hAsaBN62rOeA9kKQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fv2%2Fresize%3Afit%3A1324%2Fformat%3Awebp%2F1%2AMhWOn0hAsaBN62rOeA9kKQ.png" alt="app ready" width="662" height="178"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lets Handle Payment Requests&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now that our server is running. We’re going to do two things.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Accepting incoming payment requests from the client.&lt;/li&gt;
&lt;li&gt;Listen for Stripe webhook events and process them&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  1.Accepting Incoming Payment Requests
&lt;/h2&gt;

&lt;p&gt;When a payment request arrives, calculate the total amount to be paid. For example, in an e-commerce app, send the product_id and quantity, then retrieve the product price and compute the final amount. (Calculate the total amount in the backend, not the frontend, to ensure security and prevent tampering.)&lt;/p&gt;

&lt;p&gt;When creating a Checkout Session with Stripe:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Specify the currency in lowercase (e.g. “usd”).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Convert the price to cents (e.g. $10.00 → 1000).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Include relevant metadata (e.g. order_id, productName, productId).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Set success and cancel URLs for proper redirection after payment.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Learn more about Checkout Sessions here: &lt;a href="https://docs.stripe.com/api/checkout/sessions" rel="noopener noreferrer"&gt;Stripe Checkout Sessions&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// POST  /checkout to process incoming payment requests from client
app.post("/checkout", async (req: Request, res: Response) =&amp;gt; {
  /*  
    Retreive cart from request, calculate final amount to be paid.
    In this example we're purchasing only one product with quantity 1
  */

  const product: { id: number; name: string; priceInCents: number } = {
    id: 1,
    name: "Sunglasses",
    priceInCents: 4500,
  };

  // Create an order, store it on your database with paymentStatus "unpaid"
  // This article is focused on stripe so I'm not doing that fully.
  const orderId = Math.floor(Math.random() * 1000);

  try {
    const session = await getStripe().checkout.sessions.create({
      currency: "usd",
      metadata: {
        productName: product?.name,
        productId: product?.id,
        orderId: orderId,
      },
      line_items: [
        {
          price_data: {
            currency: "usd",
            product_data: {
              name: product?.name,
              metadata: product,
            },
            unit_amount: product.priceInCents,
          },
          quantity: 1,
        },
      ],
      mode: "payment", // other modes are 'subscription' and 'setup'
      success_url: `http://localhost:3000/checkout?status=failed`,
      cancel_url: `http://localhost:3000/checkout?status=failed`,
    });

    res.status(200).json({ checkoutUrl: session.url });
  } catch (e) {
    console.log("e", e);
    res.status(500).json({ error: "Something went wrong" });
  }
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2.Listen for events strom Stripe via Webhook
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Add this code block before the app.use(express.json()) line. This is because, for Stripe to validate the signature of your webhook, it has to be raw without any json parsing.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Stripe webhook to listen for events
app.post(
  "/stripe-webhook",
  express.raw({ type: "application/json" }),
  async (req: Request, res: Response) =&amp;gt; {
    const endpointSecret = process.env.STRIPE_WEBHOOK_SECRET;

    try {
      if (endpointSecret) {
        // Get the signature sent by Stripe
        const signature = req.headers["stripe-signature"];

        if (!signature) {
          throw new Error("Missing Stripe signature");
        }

        const event = getStripe().webhooks.constructEvent(
          req.body,
          signature,
          endpointSecret
        );

        switch (event.type) {
          case "checkout.session.completed": {
            const checkoutSession = event.data.object;

            const {
              currency,
              subscription,
              amount_total,
              status,
              payment_status,
              metadata,
              created,
            } = checkoutSession;

            // Get order ID from metadata since it was passed
            const orderId = metadata?.orderId;

            /*
             Mark order as complete based on the payment_status
             You have access ti other information from the checkout session
             including the amount_total, date created, currency and so much more
             checkoout the Checkout session object in stripe docs: https://docs.stripe.com/api/checkout/sessions/object
            */

            // handle your database updates and any other logic
            if (payment_status == "paid") {
              //
            }

            break;
          }

          default:
            console.log(`⚡️ Unhandled Stripe Webhook -&amp;gt;  ${event.type}`);
        }

        res.json({ received: true });
      } else {
        res.status(500).json({ message: "Something went wrong" });
      }
    } catch (error: any) {
      console.error(`Webhook error: ${error?.message}`);
      res.status(400).send(`Webhook error: ${error?.message}`);
    }
  }
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Forwarding Stripe Events to your local machine&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Add your local event listener in the Stripe dashboard. Ensure that your webhook endpoint has been configured with the “checkout.session.completed” event included.&lt;/p&gt;

&lt;p&gt;View the docs here: &lt;a href="https://docs.stripe.com/webhooks/quickstart" rel="noopener noreferrer"&gt;Webhooks&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Install the Stripe CLI, login and run this command. This would listen to webhook events and forward them to the endpoint we specified.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;stripe listen --forward-to localhost:8080/stripe-webhook
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we’re ready to test our setup.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Interactive Testing With Stripe Test Keys&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When testing interactively, use a card number, such as 4242 4242 4242 4242 to simulate a successful payment.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use a valid future date, such as 12/34.&lt;/li&gt;
&lt;li&gt;Use any three-digit CVC (four digits for American Express cards).&lt;/li&gt;
&lt;li&gt;Use any value you like for other form fields.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Read More About Testing Cards: &lt;a href="https://docs.stripe.com/testing?testing-method=card-numbers#testing-interactively" rel="noopener noreferrer"&gt;Stripe Testing&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Full Code for this tutorial is available on Github&lt;/p&gt;

&lt;p&gt;You can view the full code on Github: &lt;a href="https://github.com/okraks/stripe-integration-guide" rel="noopener noreferrer"&gt;https://github.com/okraks/stripe-integration-guide&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Related Articles &amp;amp; Resources&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;WebDev Simplified: How to Accept Payments with Stripe: &lt;a href="https://youtu.be/1r-F3FIONl8" rel="noopener noreferrer"&gt;https://youtu.be/1r-F3FIONl8&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://docs.stripe.com/checkout/quickstart?client=next&amp;amp;lang=node" rel="noopener noreferrer"&gt;https://docs.stripe.com/checkout/quickstart?client=next&amp;amp;lang=node&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>programming</category>
      <category>payments</category>
      <category>stripe</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
