Razorpay Subscription Based Model Integration in CrossPostHub

CrossPostHub is a platform that allows users to cross-post content to multiple social media platforms. In this guide, we will walk through the process of integrating a subscription-based model in CrossPostHub using Razorpay. To implement this, I saved all the subscription plans in the database and fetched them on the client side to display to the user. Once a user selects a plan, a subscription is created on the server side using the Razorpay API. Additionally, I set up a webhook to listen to subscription events and update the user's subscription status in the database.

Integration

So there are three main parts to this integration:

  1. Displaying Subscription Plans: Fetch the subscription plans from the database and display them to the user.
  2. Creating a Subscription: When a user selects a plan, create a subscription using the Razorpay API.
  3. Webhook for Subscription Events: Set up a webhook to listen to subscription events and update the user's subscription status in the database.

Displaying Subscription Plans

To display the subscription plans, I fetched them from the database and rendered them on the client side. Here's a code example what it looks like:

// Fetch subscription plans from the server side and cache them for 24 hours using Redis for faster retrieval
export async function GET(request: NextRequest) {
  try {
    const cachedPricingPlansKey = "pricingPlans";
    const cachedPricingPlans = await redis.get(cachedPricingPlansKey);

    if (cachedPricingPlans) {
      console.log("Returning cached pricing plans");
      return NextResponse.json(
        { pricingPlans: JSON.parse(cachedPricingPlans) },
        { status: 200 }
      );
    }

    const pricingPlans = await prisma.plan.findMany();

    // Cache the pricing plans for 24 hours
    await redis.set(cachedPricingPlansKey, JSON.stringify(pricingPlans), {
      EX: 24 * 60 * 60,
    });

    return NextResponse.json({ pricingPlans }, { status: 200 });
  } catch (error) {
    return NextResponse.json({ error: "An error occurred" }, { status: 500 });
  }
}
// Fetch subscription plans from the client side

fetchPricingPlans: async () => {
    try {
      const { data } = await axios.get("/api/payment/pricing");
      set({ pricingPlans: data.pricingPlans });
    } catch (error: any) {
      console.error("Fetch Pricing Plan Error:", error);
    } finally {
      set({ isFetchingPlans: false });
    }
},

Creating a Subscription

I Created a SubscriptionButton component that accepts planId as a prop and when user clicks on it, it creates a subscription using the Razorpay API.

const response = await axios.post("/api/payment/subscribe", {
  planId,
  userId: data.user.id,
});

const { short_url, subscriptionId } = response.data;

if (!short_url) {
  toast({
    title: "An error occurred",
    description:
      response.data.error ||
      "Failed to initiate subscription. Please try again.",
  });
  router.push("/payment/failed");
  return;
}

// Redirect the user to the Razorpay checkout page
window.location.href = short_url;

Webhook for Subscription Events

I set up a webhook to listen to subscription events from Razorpay and update the user's subscription status in the database. The events I listened to were: subscription.activated, subscription.charged, subscription.completed, subscription.failed, subscription.pending