#alxizr
1 messages ยท Page 1 of 1 (latest)
Hi ๐ this forum is staffed by Stripe, I'll answer as best as I can ๐
I'm doing alright, how about yourself?
im loosing my mind bro
honestly
nothing makes sense anymore
i will tell you what is the issue
and you tell me how to solve it please
if you can of course
need to develop a feature in that integrates Stripe in our project
we sell subscriptions
via the online platform
i created via the dashboard couple of test products
i am using react in the frontend
the requirement is to have the billing inside the project and not use the stripe checkout
we want to control the flow
we are using the Elements and the PaymentElement components
here is where the problem begins
the Elements component is a context provider that wraps the Payment Element component and also enables us to use the useStripe and useElements hook
the issue is that there is no way to render the PaymentElement component without having a client secret
in order to get a client secret, we need to create a payment intent
but the payment intent is not what we need because we are trying to create subscriptions
and not a one time payment
@hazy yacht do you understand what is wrong until this point ?
the docs are wrong
and not updated
there is plenty more to tell you
i want ot do it in mild steps
This all sounds expected so far. You do want to use a Payment Intent, you just won't create it directly. Instead you create the Subscription, which will create an Invoice, which will create a Payment Intent that you can use to initialize the Payment Element.
This guide walks through the process of using the Payment Element with Subscriptions, is the guide that you're using as your reference?
https://stripe.com/docs/billing/subscriptions/build-subscriptions?ui=elements
i have this link to the docs
what is written there is wrong
you cannot render the payment element without a client secret
it is needed beforehand
so the react app will not crash
if i am trying to create the subscription just as it showing in the link
the payment intent inside the subscription object is null
subscription.latest_invoice.payment_intent
is null
i can show you the code if you like
Can you share the ID of the Subscription and Invoice?
what do you mean
?
i am not saving them right now
they are created on the fly
i can generate a new one
customer id = cus_N4d2pEomXjz1fO
subscription id = sub_1MKTmXDWmnCCjaSNTNnYw7iO
latest_invoice id = in_1MKTmXDWmnCCjaSNGmeIEIpc
Ah, since you're creating the Subscription with a trial period, the first Invoice that gets generated is a zero-dollar Invoice, and since there is no payment to be processed for that no Payment Intent is created.
Do you plan to consistently provide trials, or will you have a mixture of Subscriptions where some have trials and some don't?
??? WHAT ???
all subscriptions have trials
some are 14 days and some 30 days
but even if i remove the trial, it still won't work
and the react project crashes
Why does it crash? Your React code should be making a request to your backend server that provides it with a client secret, then once it has that client secret your React app can initialize the Payment Element.
If you're going to consistently be offering trials, then your Subscription object should include the ID of a Setup Intent in the pending_setup_intent field. You can use the client secret of that Setup Intent to initialize the Payment Element and use it to collect payment method details:
https://stripe.com/docs/api/subscriptions/object#subscription_object-pending_setup_intent
Complete reference documentation for the Stripe API. Includes code snippets and examples for our Python, Java, PHP, Node.js, Go, Ruby, and .NET libraries.
the react app crashes because the elements instance is lacking the client secret and it cannot mount the Payment Element nor other elements
@marsh topaz Hi there ๐ taking over for @hazy yacht
Can you step through your code and find out where the client-secret is being left without getting sent to the client?
hi
give me a minute
i will paste the code
app.post("/api/create-customer", async (req, res, next) => {
const { email } = req.body;
const customer = await stripe?.customers?.create({
email,
name: "test customer " + Date.now().toLocaleString(),
description: "first test customer",
});
return res.status(200).json({
...customer,
});
});
this is the nodejs express code for creating a customer
app.post("/api/create-subscription", async (req, res, next) => {
try {
const { customer } = req.body; // customer id !!!
const { data } = await stripe?.products?.list();
const targetPlan = data[0]; //?.default_price;
const subscription = await stripe?.subscriptions?.create({
customer,
items: [
{
price: targetPlan?.default_price,
quantity: 1,
metadata: targetPlan?.metadata,
},
],
currency: "usd",
payment_settings: {
payment_method_types: ["card"],
payment_method_options: {
card: {
request_three_d_secure: "automatic",
},
},
save_default_payment_method: "on_subscription",
},
expand: ["latest_invoice.payment_intent", "pending_setup_intent"],
payment_behavior: "default_incomplete",
trial_period_days: 14,
});
return res.status(200).json({
...subscription,
});
} catch (error) {
return res.status(555).json({
...error,
});
}
});
this is the nodejs express code for creating subscription
you can see that i now added the pending_setup_intent value to the expand property as toby pointed out
export const StripeSubscriptionPage = () => {
const [stripePromise, setStripePromise] = useState(null);
// const [clientSecret, setClientSecret] = useState("");
// stripe promise
useEffect(() => {
setStripePromise(loadStripe(PUBLIC_KEY));
}, []);
if (!stripePromise) {
return null;
}
// if (!clientSecret) {
// return null;
// }
return (
<div className="flex flex-col w-full">
<header className={clsx("text-black font-medium text-xl p-5")}>
<h1>Stripe Subscription Page </h1>
</header>
<Elements
options={{
appearance: {
theme: "stripe",
},
}}
stripe={stripePromise}
>
<p>Stripe subscription form goes here </p>
<StripeSubscriptionForm />
</Elements>
</div>
);
};
react Page component for this example that renders the Elements context provider
react component for this example that renders the Payment Elements component with the requests to create customer & subscription as per the docs
this is obviously not very clean and structured but for the sake of the development with all the issues i wrote it tis way until everything is working
the idea is that it is going to be a multi step form
user will provide the details to create the customer object, then press next ( subscription checkout) then payment elements component will render and fills in the card details and then press submit ( subscription checkout 2)
So, the code isn't very helpful for me to see, I just meant: can you do an incremental step-through of the code on your own and add a console.log(); to find out why the client secret is not being sent to the client
That seems like the root of the issue, because the Element should be mounted with a client secret
oh, yes, i know why this is happening
the thing is this
payment element cannot be rendered without the secret key
in order to get secret key we need to create customer and subscription
the FORM part of the code is not rendered because of this reason until we create the subscription
we can now get the secret key after toby explained that the payment intent returns null because we have free trial days
so i added the pending_setup_intent to the expand property in the nodejs api code responsible for creating the subscription
once this HTTP request comes back to the client, i have a local state for secretKey and i set it
the issue is that it all happens AFTER the original page load / render and we are using the elements hook
so at this point i am manually setting the secret key inside the elements
but it does not matter because all the components are rendered and the elements instance is already created
and what happens is that the elements that are rendered in the page are not binded to the elements instance
so the next step to create the payment is crashing at the method stripe.confirmPayment
i will give you the error, one second please
payment element cannot be rendered without the secret key
in order to get secret key we need to create customer and subscription
This doesn't make any sense. What secret key are you talking about? Why can't you get it without creating a Customer or Subscription?
It sounds like you need to choose either to (a) re-render the page asynchronously, or (b) not render the page until you have all the information you need up front
no no no
this is react js no react ssr like next or gatsby
like i said
the target is to create subscriptions
using the payment element
payment element will render ONLY within an Elements context provider that must have a client secret from an intent
either payment intent or setup intent
this is what the docs say
and the subscription integration in the docs is just wrong
this is the error that i am talking about
"Invalid value for stripe.confirmPayment(): elements should have a mounted Payment Element or Pay Button Element. "
after you press the button you get the client secret from the intent
then you see the payment element
ignore the other elements, i put it in the component to check that it works
as you can see i also have google pay enables
now if you press the second button which is the PAY button essentially
we get the error
"Invalid value for stripe.confirmPayment(): elements should have a mounted Payment Element or Pay Button Element. "
btw
it is all the same with the CARD element
@vivid valley are you here ?
Do you have a URL for a test-mode payment page that we can look at to see this behavior in real-time? I'm still failing to understand what's causing your Payment Element to throw that error.
Is it possible you need to update the Payment Element at some point after the page renders, using element.update()? Like, is this a race condition? Why is confirmPayment() not aware of the mounted Payment Element?
Here's the JS method for updating the Payment Element btw, in case that solves your issue: https://stripe.com/docs/js/elements_object/update_payment_element
i can show you the code
and i can deploy it somewhere so you can see it first hand
i have already setup in vercel
i explained why confirmPayment is not aware of the elements
it is because there is no client secret
to begin with
it is because there is no client secret
to begin with
Why can't you create the Payment Intent ahead of rendering the Payment Element?
choose subscription in the top nav
Apologies if this has been gone over before, but I'm just failing to see why you don't have a client secret to begin with.
payment element cannot be rendered without the secret key
in order to get secret key we need to create customer and subscriptio
because this is how you designed it
i guess for better security or something
Wait, back up. When you say "secret key" do you mean the secret API key?
no
just a second
Complete reference documentation for the Stripe API. Includes code snippets and examples for our Python, Java, PHP, Node.js, Go, Ruby, and .NET libraries.
@vivid valley if you go there now. you can see for yourself
the deployment is ready
open the dev tools in your browser
i added console logs where needed
Alright, will circle back in a couple minutes
๐
Sorry, this code is really hard to read and I'm going in circles. It feels like you're trying to pass a promise in to the elements instance, but the promise hasn't resolved yet. If I had to guess, I'd say that's what's happening. This is mentioned briefly here: https://stripe.com/docs/stripe-js/react#useelements-hook
Did you try using elements.update() to see if that gets the Element instance to a non-null state?
i looked at it, this is no help. the object is null and you cannot use it for anything
the promise is resolved. trust me on this one. this is as per the docs. if that promise was not resolved then nothing would work
what code are you trying to read ?
i didnt send you the code repo
just the link for a version that you can experience yourself
I was looking at the code you sent earlier in the thread, plus what I can see in the dev tools
ok
you want link to the repo
?
it will be easier
this is the react code, this is what we are talking about for the past 3 hours
this is the nodejs express code, you need to look from line 77 and onwards