Home > Web Front-end > JS Tutorial > How to add Stripe to Astro

How to add Stripe to Astro

Susan Sarandon
Release: 2024-10-17 20:44:02
Original
1090 people have browsed it

How to add Stripe to Astro

Integrating Stripe with Astro: A Step-by-Step Guide

In this tutorial, I'll show you how to set up Stripe in an Astro project, from creating a new project to handling webhooks and creating checkout sessions.

Step 1: Creating a New Astro Project

To get started, we need to create a new Astro project using the following command:

npm create astro@latest
Copy after login

The version of Astro being used is 4.16.5

Step 2: Installing Stripe

Next, install the Stripe package.

npm i stripe
Copy after login

The version of Stripe being used is 17.2.0

Step 3: Configuring Stripe

Create a file called src/lib/stripe.ts to initialize Stripe and handle its configuration:

import Stripe from 'stripe';

if (!import.meta.env.STRIPE_SECRET_KEY) {
    throw new Error('Missing Stripe secret key');
}

export const stripe = new Stripe(import.meta.env.STRIPE_SECRET_KEY, {
    apiVersion: '2024-09-30.acacia',
});
Copy after login

Nothing fancy here, just the fact that the apiVersion is based on the stripe version ( for 17.2.0 is 2024-09-30.acacia )

After that create a new file in src/lib/get-prices.ts and add the following:

export async function getPrices() {
    const data = [
        {
            id: 1,
            amount: 1000,
            title: 'One time Price 1',
        },
        {
            id: 2,
            amount: 1000,
            title: 'One time Price 2',
        },
        {
            id: 3,
            amount: 1500,
            credits: 10,
            title: '10 credits',
        },
        {
            id: 4,
            amount: 3000,
            credits: 25,
            title: '25 credits',
        },
    ];
    return data;
}
Copy after login

Here, we will configure the prices.

Step 4: Setting Up Stripe CLI for Webhooks

Webhooks allow Stripe to notify your server of events (such as payment completions). To listen to these events on local we need the following:

"stripe:listen": "stripe listen --forward-to http://localhost:4321/api/webhooks/stripe"
Copy after login

You'll also need to install the Stripe CLI, which allows your local server to receive Stripe events. More details on how to install the Stripe CLI can be found at https://docs.stripe.com/stripe-cli.

After that, run:

npm run stripe:listen
Copy after login

It might ask you to login and after that you should see a similar message:

Ready! You are using Stripe API Version. Your webhook signing secret is whsec_something
Copy after login

Step 5: Configuring Environment Variables

In the root of your project, create a .env file with the following content:

STRIPE_SECRET_KEY=your_secret_key_from_stripe
STRIPE_SIGNING_SECRET=signing_key_from_stripe_cli
Copy after login

Step 6: Adding Tailwind CSS and Node.js

For basic styling and to handle the backend requests, add Tailwind CSS and Node.js integrations to your project:

npx astro add tailwind
npx astro add node
Copy after login

Step 7: Creating Stripe Checkout Action

You can read more about actions in Astro at https://docs.astro.build/en/guides/actions/.

We will now create an action to handle the checkout process. Create a file at src/actions/index.ts with the following code:

import { ActionError, defineAction } from "astro:actions";
import { z } from "astro:schema";
import { getPrices } from "../lib/get-prices";
import { stripe } from "../lib/stripe";

export const server = {
  createCheckout: defineAction({
    input: z.object({
      priceId: z.number(),
    }),
    accept: "form",
    handler: async (input) => {
      const prices = await getPrices();
      const price = prices.find((p) => p.id === input.priceId);

      if (!price) {
        throw new ActionError({
          code: "NOT_FOUND",
          message: "Price not found.",
        });
      }

      const baseUrl = 'http://localhost:4321'; // replace with your production URL

      const stripeSession = await stripe.checkout.sessions.create({
        mode: "payment",
        payment_method_types: ["card"],
        line_items: [
          {
            quantity: 1,
            price_data: {
              unit_amount: price.amount,
              currency: "usd",
              product_data: {
                name: price.title,
                description: `Buy ${price.title} product`,
              },
            },
          },
        ],
        metadata: {
          priceId: price.id,
        },
        success_url: `${baseUrl}/?stripe=success`,
        cancel_url: `${baseUrl}/?stripe=cancel`,
      });

      if (!stripeSession.url) {
        throw new ActionError({
          code: "NOT_FOUND",
          message: "Could not create Stripe session",
        });
      }

      return {
        url: stripeSession.url,
      };
    },
  }),
};
Copy after login

Here, we are just taking the priceId from the frontend, look for it inside our prices list. If we find it, we create a stripe checkout session and send the url to the frontend. For the stripe session, we will need to specify a success/cancel url, where the user should be redirected after the payment. Also, we have the possibility to add extra metadata that we will receive into our webhook. Here you usually add the priceId and userId.

Step 8: Rendering the Checkout Form

Now, let's display pricing cards and integrate the checkout button. Add the following code to src/pages/index.astro:

---
import Layout from '../layouts/Layout.astro';
import { getPrices } from '../lib/get-prices';
import { actions } from 'astro:actions';

const prices = await getPrices();

const result = Astro.getActionResult(actions.createCheckout);
if (result && !result.error) {
    return Astro.redirect(result.data.url)
}
---

<Layout title="Welcome to Astro.">
    <h1 class="text-center text-5xl font-bold text-gray-200">Pricing</h1>
    <ul class="mt-12 grid grid-cols-1 gap-10 md:grid-cols-2 lg:grid-cols-3 p-4">
        {
            prices.map((price) => (
                <li class="mx-auto w-full max-w-5xl space-y-4 rounded-lg bg-gray-900 p-8 text-white">
                    <h2 class="text-2xl font-bold">{price.title}</h2>
                    <p class="mt-4 text-3xl font-bold">${price.amount / 100}</p>
                    <form method="POST" action={actions.createCheckout}>
                        <input type="hidden" name="priceId" value={price.id} />
                        <button class="bg-blue-500 text-white hover:bg-blue-600 p-4">
                            Buy
                        </button>
                    </form>
                </li>
            ))
        }
    </ul>
</Layout>
Copy after login

Here, we are fetching the prices on the server, and we create cards for each of the price. Then, for each price, we have a form that calls the previously defined action in order to receive the stripe checkout session. After that, we redirect the user to the stripe page.

Step 9: Creating a Webhook for Stripe

Finally, handle Stripe webhook events. Create the file src/pages/api/webhooks/stripe.ts with the following code:

import type { APIRoute } from 'astro';
import type Stripe from 'stripe';
import { stripe } from '../../../lib/stripe';

type Metadata = {
    priceId: string;
};

export const POST: APIRoute = async ({ request }) => {
    const signature = request.headers.get('stripe-signature');
    if (!signature) {
        return new Response(JSON.stringify({ error: 'Invalid signature' }), {
            status: 400,
            headers: {
                'Content-Type': 'application/json',
            },
        });
    }

    const stripeSigningSecret = import.meta.env.STRIPE_SIGNING_SECRET as string;
    try {
        const event = stripe.webhooks.constructEvent(
            await request.text(),
            signature,
            stripeSigningSecret,
        );

        const completedEvent = event.data.object as Stripe.Checkout.Session & {
            metadata: Metadata;
        };

        if (event.type === 'checkout.session.completed') {
            console.log('Paid', completedEvent.amount_total);
            console.log('Metadata', completedEvent.metadata);

            // Update your database or user status here
        }
        return new Response(JSON.stringify({ success: true, error: null }), {
            status: 200,
            headers: {
                'Content-Type': 'application/json',
            },
        });
    } catch (err) {
        return new Response(
            JSON.stringify({
                success: false,
                error: (err as { message: string }).message,
            }),
            {
                status: 500,
                headers: {
                    'Content-Type': 'application/json',
                },
            },
        );
    }
};

Copy after login

This webhook listens for the checkout.session.completed event from Stripe. Upon receiving the event, you can update your database, apply changes to the user’s account, or trigger any other post-payment action.

Conclusion

That's it! By following these steps, you can successfully integrate Stripe into your Astro project. Pretty easy right?

The above is the detailed content of How to add Stripe to Astro. For more information, please follow other related articles on the PHP Chinese website!

source:dev.to
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Latest Articles by Author
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template