#DeMe
1 messages ยท Page 1 of 1 (latest)
How do you integrate with Stripe currently? Are you using Checkout Session or Payment Element?
Next JS with tRPC using CheckoutSession
Thanks for sharing! You may include the URL in the metadata. Metadata is the field for your own internal reference: https://stripe.com/docs/api/products/create#create_product-metadata
Complete reference documentation for the Stripe API. Includes code snippets and examples for our Python, Java, PHP, Node.js, Go, Ruby, and .NET libraries.
Thanks! I appreciate it
No problem! Happy to help ๐
One more question, using createCheckout that takes in a priceID, how can I get the metadata from the product to show on the confirmation page.
More specifically how can I tell stripe what product to retrieve the metadata for I am taken to the success url page?
Which confirmation page are you referring to? Are you referring to the Stripe one, or your own page that is set in success_url?
Can you share how your expected flow should look like?
For sure, here's my stripe related router that runs the createCheckoutSession:
createCheckoutSession: publicProcedure
.input(
z.object({
priceId: z.string(),
// productName: z.string(),
})
)
.mutation(async ({ ctx, input }) => {
const { stripe, userId, prisma, req } = ctx;
if (!userId) {
throw new Error("No user id");
}
const customerId = await getOrCreateStripeCustomerIdForUser({
prisma,
stripe,
userId,
});
console.log(customerId, "customerId");
if (!customerId) {
throw new Error("Could not create customer");
}
// the base url is different depending on if we are in development or production
const baseUrl =
env.NODE_ENV === "development"
? `http://${req.headers.host ?? "localhost:3000"}`
: `https://${req.headers.host ?? env.NEXTAUTH_URL}`;
// Stripe Checkout Session
const checkoutSession = await stripe.checkout.sessions.create({
customer: customerId as string,
client_reference_id: userId!,
payment_method_types: ["card"],
mode: "payment",
// if using subscriptions
// mode: "subscription",
line_items: [
{
// price: env.STRIPE_PRICE_ID,
price: input.priceId,
quantity: 1,
},
],
// lead the user to the stripe confirmed page if they successfully purchase
// success_url: `${baseUrl}/store/orderSuccessful/${input.productName}`,
success_url: `${baseUrl}/store/orderSuccessful`,
// redirect the user back to the item page if they cancel the purchase
cancel_url: `${baseUrl}/store`,
// if using subscriptions
// subscription_data: {
// metadata: {
// userId: userId,
// },
// },
});
if (!checkoutSession) {
throw new Error("Could not create checkout session");
}
return { checkoutUrl: checkoutSession.url };
}),
My button that runs the trpc call:
<button
className="btn-primary btn bg-primary"
onClick={async () => {
if (!user.isSignedIn) {
handleBuyNow();
} else if (user.isSignedIn) {
// create a checkout session
const { checkoutUrl } = await createCheckoutSession({
priceId: product.default_price,
});
if (checkoutUrl) {
void push(checkoutUrl);
}
}
}}
>
Leave a Tip
</button>
And then the orderSuccessful page which I get the url from in the trpc call "success_url":
import React from "react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faCheckCircle } from "@fortawesome/free-solid-svg-icons";
import { useRouter } from "next/router";
import { GetStaticProps } from "next";
import { generateSSGHelper } from "~/server/helpers/ssgHelper";
import { api } from "~/utils/api";
import { usePathname } from "next/navigation";
const OrderSuccessful = () => {
const pathname = usePathname();
// I want everything after the /`${baseUrl}/store/orderSuccessful
const path = pathname.split("/").pop();
console.log(path, "path");
const { data: downloadUrls } = api.store.getS3DownloadUrl.useQuery();
console.log(downloadUrls, "s3BucketDownloadLink");
// const postPurchaseDownloadLink = downloadUrls;
const router = useRouter();
return (
<div className="flex min-h-screen flex-col justify-center bg-gray-100 py-6 sm:py-12">
<div className="relative mx-auto py-3 text-center sm:max-w-xl">
<span className="text-6xl text-green-500">
<FontAwesomeIcon icon={faCheckCircle} />
</span>
<h1 className="text-2xl font-semibold text-gray-900">
Purchase Successful!
</h1>
<p className="text-gray-500">
Thank you for your order. We hope you enjoy your purchase!
</p>
<p>Here's your download link: {url}</p>
<div className="mt-6">
<button
onClick={() => {
router.push("/");
}}
className="btn-primary btn mx-2"
>
Back to Home
</button>
<button
onClick={() => {
router.push("/store");
}}
className="btn-secondary btn mx-2"
>
Continue Shopping
</button>
</div>
</div>
<div className="mt-12">
<h2 className="mb-4 text-center text-xl font-semibold text-gray-900">
Other users also bought:
</h2>
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
{mappedProducts.map((product) => (
<div key={product.id} className="rounded-lg bg-white p-4 shadow-md">
<img
className="mb-4 h-48 w-full rounded object-cover"
src={product.images}
alt={product.title}
/>
<h3 className="text-lg font-semibold text-gray-900">
{product.name}
</h3>
</div>
))}
</div>
</div>
</div>
);
};
export default OrderSuccessful;
export const getStaticProps: GetStaticProps = async ({ req, res }: any) => {
// use SSG to get the data from the server
const ssg = generateSSGHelper(req, res);
// get recent store activities for the carousel's top news
await ssg.homePage.getRecentStoreActivities.prefetch();
// return the props
return {
props: {
trpcState: ssg.dehydrate(),
},
};
};
So button -> tRPC that runs createCheckoutSession that ends up return a success_url -> orderSuccessful Page
Yup, so how does this s3 link come into place? Where do you expect from it?
If I end up using metadata for the stripe product I'd place it in there, and then I would need to retrieve it to be able to use it in the orderSuccess Page
Thanks for sharing! Is there only one s3 link per Checkout Session or it's possible to have multiple s3 link in a single Checkout Session?
Just one s3 link for now.
Later on I plan to let users purchase multiple items at a time so there could be multiple s3 links, or a list. But for now, just one link is fine
There are 2 ways I can think of:
- Store the s3 links and the corresponding Checkout Session ID in your database. When the customer is returned to your
success_url, your system will retrieve the s3 link with the given Checkout Session ID - Set s3 link(s) in the metadata in the Checkout Session creation request (not product or price). When the customer is returned to
success_url, your system will make a Checkout Session retrieval request to get themetadatastored on the Checkout Session.