#jesse677_checkout-webhooks-paymentmethod

1 messages ยท Page 1 of 1 (latest)

daring idolBOT
#

๐Ÿ‘‹ Welcome to your new thread!

โฒ๏ธ We'll be here soon! Typically we respond in a few minutes, but sometimes we might take a bit longer if the server is busy or if you have a particularly tricky question.

โฑ๏ธ We close idle threads, which makes them read-only. Once a thread is closed it won't be reopened, but you can always start a new thread if you have another question.

๐Ÿ”— This thread will always be available, even after it's closed. You can find it again using Discord's search, or you can save this link: https://discord.com/channels/841573134531821608/1272596022308376667

๐Ÿ“ Have more to share? Add more details, code, screenshots, videos, etc. below.

granite cove
#

This is all of the code.

"use server";

import { isSignedIn } from "@/utils/auth";
import {
  BillingMethod,
  BillingPlan,
  stripePricingTokens,
} from "@/utils/constants";
import { env } from "@/utils/env";
import { stripeInstance } from "@/utils/stripe";
import { GenericObject } from "@/utils/types";
import { cookies } from "next/headers";

export async function getCheckoutSession(sessionID: string) {
  try {
    const session = await stripeInstance.checkout.sessions.retrieve(sessionID);
    const { email, plan } = session.metadata as GenericObject<string>;

    return {
      status: "Success",
      plan,
      customer_email: email,
      subscription_id: session.subscription,
      customer_id: session.customer as string,
    } as const;
  } catch {
    return {
      status: "Error",
    } as const;
  }
}

export async function getClientSecret(plan: BillingPlan, type: BillingMethod) {
  const token = cookies().get("token")?.value || "";
  const { user, signedIn } = await isSignedIn(token);
  if (!signedIn) return "Unauthorized";

  const session = await stripeInstance.checkout.sessions.create({
    ui_mode: "embedded",
    payment_method_types: ["card", "paypal"],
    metadata: {
      plan,
      email: user.email,
    },
    line_items: [
      {
        price: stripePricingTokens[plan][type],
        quantity: 1,
      },
    ],
    mode: "subscription",
    return_url: `${env.BASE_URL}/purchase-plan/success?code={CHECKOUT_SESSION_ID}`,
  });

  return session.client_secret as string;
}
low imp
#

HI ๐Ÿ‘‹

So you have the Checkout Session ID and you are retrieving the session. How do you know the session has been completed? Are you listening for a webhook event?

granite cove
#

the getCheckoutSession is used in the /purchase-plan/success, which is the return_url of the embedded checkout

#

so it has to be finished in order for you to be at that page

low imp
#

Okay. i will point out that we recommend you listen to webhooks over the return URL, since it's possible your customers could close their browser or there could be bad internet weather that prevents them from landing on your page even though they completed the purchase

https://docs.stripe.com/checkout/fulfillment

#

But, that being said, let's work with what you have

granite cove
#

but I'll look into the webhooks

low imp
#

So you're using a recurring price that creates a Subscription.

granite cove
#

yeah

#

so basically what I've got so far is when you complete the payment and land on the /success page, I run the function at the top (getCheckoutSession), and then through that I make some writes to the database giving the user authorization to the service

#
const redisPipeline = redis.pipeline();
  redisPipeline.json.set(email, "$.plan", JSON.stringify(plan));
  redisPipeline.json.set(email, "$.stripe_customer_id", customerID);
  redisPipeline.json.set(email, "$.stripe_subscription_id", subscriptionID);
  await redisPipeline.exec();
#

I'm hoping to be able to add .stripe_payment_method_id

#

but if not possible I'd just opt for making another call to the stripe API

#

which I'm hoping to avoid as it can be quite expensive and I'm trying to acheive the best UX possible

low imp
#

Yeah unfortunately the payment method isn't going to be available directly on the Checkout Session

#

The first place I would check is if you can retrieve the Subscription and the default_payment_method property

granite cove
#

yh that's what I was thinking

#

ok that's fine

#

thanks for all your help

#

and telling me abt the webhooks

low imp
#

Sure thing, happy to shed what ๐Ÿ’ก I can ๐Ÿ™‚

daring idolBOT