#simba-embeddedcheckout-tracking
1 messages · Page 1 of 1 (latest)
Hello
hello
So yeah, you basically wrap the page with your actual Checkout component within the EmbeddedCheckoutProvider and when you render that you call your backend to create a Checkout Session and a client secret.
Can you clarify what is confusing you exactly?
I'm confused why the example passes the client secret to the app root, shouldn't my checkout page fetch the client secret from my server and send the client secret that way?
yes
Gotcha, yeah that is confusing. Mostly the idea here is that you might create the Checkout Session on page load and then pass that down.
Like from a higher component in the tree
aha, that makes sense
understood, thank you kindly
And just call your backend for a clientSecret on page load and then use that when you are ready to show the actual Checkout Session
awesome, that is all I needed to know, so I can simply wrap the <EmbeddedCheckoutProvider> around my checkout form that comes from a pop up?
when the popup comes up, it should fetch the client secret from the server, send it to the embedded checkout provider and then the magic happens I guess?
what about the return url, I currently am using a pop up on the root app page, should my return url be the same as where my checkout form on the popup lives?
since it's returning a checkout session id?
Yep generally you would have that return URL just be the same page
You want to use it to show success info to your Customer
hmmmm makes sense, I guess since my app is using the app root for most things, I'll use the app root for it, but that does mean I can not show the form on other pages...
I suppose I can create seperate api's for different pages then
Yeah that's up to you really
Happy to help
have a great day
You too!
sorry to respond once more, but do you think this should work?
"use client";
import {useEffect, useState} from "react";
import {ProModal} from "@/components/pro-modal";
import {loadStripe} from '@stripe/stripe-js';
import axios from "axios";
import {
EmbeddedCheckoutProvider,
EmbeddedCheckout
} from '@stripe/react-stripe-js';
import {useRouter} from "next/router";
const stripePromise = loadStripe(process.env.NEXT_PUBLIC_STRIPE_PUBLIC_KEY!)
export const ModalProvider = async () => {
const [isMounted, setIsMounted] = useState(false);
const [clientSecret, setClientSecret] = useState('')
const router = useRouter()
const response = await axios.post("/api/stripe/checkout/create", {path: router.pathname});
if (response.status === 200) {
setClientSecret(response.data)
}
useEffect(()=>{
setIsMounted(true);
},[])
if (!isMounted) {
return null;
}
return (
<EmbeddedCheckoutProvider stripe={stripePromise} options={{clientSecret}}>
<ProModal />
</EmbeddedCheckoutProvider>
)
}
this is my modal provider that will open up a modal. It passes the current url as a parameter to the backend, which is then used as return url
Seems fine from a glance but I really can't tell you from looking at the code. Best thing to do is to test it out.
You may need to conditionally wait for your clientSecret before rendering EmbeddedCheckoutProvider
Like {clientSecret && (<EmbeddedCheckoutProvider ...
But yeah, I'd just test out what you have and see what happens! Then go from there
yeah you're right, I should wait for that clientSecret
thank you, I'm working on getting everything implemented and will then do a test run
do you know if there is a failed session status that can be returned and what the status is called?
I want to show some raindrops when it fails
What do you mean by "failed session" exactly?
Are you talking about when a charge attempt fails?
(really declines)
I mean that when the checkout has failed for whatever reason and returns to the page with a failure
Sorry, you are going to have to be more specific. A Checkout Session doesn't hit the return URL unless it is successful
If there is an error/decline then it is shown within the Checkout Session UI
I mean the session status from:
const session = await stripe.checkout.sessions.retrieve(session_id)
aaah ok
that makes sense
Yeah, the only statuses for a Checkout Session are complete, expired, or open: https://stripe.com/docs/api/checkout/sessions/object#checkout_session_object-status
ah ok, makes sense
so there is no way to show raindrops when the checkout fails due to a charge attenpt fail for example?
or is there a way to hook into that?
Not really with Embedded Checkout, no. You would have to poll the Checkout Session's PaymentIntent. You could use Webhooks but then it won't be synchronous.
Overall I just wouldn't recommend trying to do this.
ok, thanks
simba-embeddedcheckout-tracking
I'm testing out my request to session checkout creation, and it's telling me this:
StripeInvalidRequestError: No such price: '{{PRICE_ID}}'
I took that from the example documentation
I'm pretty sure I need to specify the test product somehow no?
are you still there @frigid quest?
@paper bluff the error is quite descriptive, what have you tried to fix it?
well I understand that there is no price it could fetch, but I have a product and price already in my stripe account under both the test and live
So what does your code do? What exact value are you passing to the API?
import {absoluteUrl} from "@/lib/utils";
import {auth, currentUser} from "@clerk/nextjs";
import {NextResponse} from "next/server";
import {stripe} from "@/lib/stripe";
import prismadb from "@/lib/prismadb";
const settingsUrl = absoluteUrl("/settings");
export async function POST(req: Request) {
try {
const { userId } = auth();
const user = await currentUser();
const body = await req.json();
const { path } = body;
if (!userId || !user) {
return new NextResponse("Unauthorized", {status: 401});
}
const intent = await stripe.checkout.sessions.create({
mode: "subscription",
line_items: [
{
price: '{{PRICE_ID}}',
quantity: 1,
}
],
ui_mode: "embedded",
return_url: process.env.NEXT_PUBLIC_APP_URL + `${path}?session_id={CHECKOUT_SESSION_ID}`
})
const userSubscription = await prismadb.userSubscription.findUnique({
where: {
userId
}
})
if (userSubscription && userSubscription.stripeCustomerId) {
const stripeSession = await stripe.billingPortal.sessions.create({
customer: userSubscription.stripeCustomerId,
return_url: settingsUrl
})
return new NextResponse(JSON.stringify({url: stripeSession.url}), {status: 301});
}
return new NextResponse(JSON.stringify({client_secret: intent.client_secret}), {status: 200});
} catch(error) {
console.log("[STRIPE_ERROR]", error);
return new NextResponse("Internal error", {status: 500});
}
}
I'm only passing the path, not the price, in the doc it says that I have to create a product and price when I hover over {{PRICE_ID}}
I assumed it worked the same as CHECKOUT_SESSION_ID, where it is populated from stripe
price: '{{PRICE_ID}}',
yes
this should be price: 'price_123456
{{PRICE_ID}} is a placeholder for a human (you) to understand what should go in there
so change the code to put a real Price id price_123 from your account
alright, that makes sense... It's a bit confusing to me that {{PRICE_ID}} is a placeholder while {CHECKOUT_SESSION_ID} is not
maybe because of the double brackets?
yeah also in that docs in theory if you hover over the doc it tells you (for Price). The Checkout part is a wy for you to ask our API to put the Checkout Session id when we redirect (since you can't know it yet, you are creating the Session).
Definitely see how the two together are confusing
seems to have worked, thanks for everything so far... I might have questions later, but so far everything is working the way it should