#simba-embeddedcheckout-tracking

1 messages · Page 1 of 1 (latest)

honest snowBOT
frigid quest
#

Hello

paper bluff
#

hello

frigid quest
#

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?

paper bluff
#

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?

frigid quest
#

Oh

#

You mean why the example code has clientSecret as a prop

paper bluff
#

yes

frigid quest
#

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

paper bluff
#

aha, that makes sense

frigid quest
#

I can flag that the snippet is confusing

#

But mostly I would ignore it

paper bluff
#

understood, thank you kindly

frigid quest
#

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

paper bluff
#

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?

frigid quest
#

Yep that should work fine I believe

#

Shouldn't take long to test out

paper bluff
#

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?

frigid quest
#

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

paper bluff
#

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

frigid quest
#

Yeah that's up to you really

paper bluff
#

true

#

thank you for your clear explanations

frigid quest
#

Happy to help

paper bluff
#

have a great day

frigid quest
#

You too!

paper bluff
#

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

frigid quest
#

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

paper bluff
#

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

frigid quest
#

What do you mean by "failed session" exactly?

#

Are you talking about when a charge attempt fails?

#

(really declines)

paper bluff
#

I mean that when the checkout has failed for whatever reason and returns to the page with a failure

frigid quest
#

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

paper bluff
#

I mean the session status from:
const session = await stripe.checkout.sessions.retrieve(session_id)

#

aaah ok

#

that makes sense

frigid quest
paper bluff
#

ah ok, makes sense

honest snowBOT
paper bluff
#

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?

frigid quest
#

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.

paper bluff
#

ok, thanks

lavish matrix
#

simba-embeddedcheckout-tracking

paper bluff
#

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?

lavish matrix
#

@paper bluff the error is quite descriptive, what have you tried to fix it?

paper bluff
#

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

lavish matrix
#

So what does your code do? What exact value are you passing to the API?

paper bluff
#
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

lavish matrix
#

price: '{{PRICE_ID}}',

paper bluff
#

yes

lavish matrix
#

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

paper bluff
#

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?

lavish matrix
#

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

paper bluff
#

seems to have worked, thanks for everything so far... I might have questions later, but so far everything is working the way it should