#Truu
1 messages · Page 1 of 1 (latest)
You are close. Just don't change your frontend and React code. When you create the Subscription on backend, takes its latest_invoice.payment_intent 's client_secret and pass back to frontend as if you were created a PaymentIntent
Look at this step https://stripe.com/docs/billing/subscriptions/build-subscriptions?ui=elements#create-subscription
that's what I have I think, the backend now has the line:
$output = [
'subscriptionId' => $subscription->id,
'clientSecret' => $subscription->latest_invoice->payment_intent->client_secret
];
so it has that more thorough 'clientSecret' taken from deeper within the $subscription object
the original line from the previous paymentIntent example was:
$output = [
'clientSecret' => $paymentIntent->client_secret,
];
Just so I know I'm on the right track, I started with the link you posted above
in it I see the line:
$subscription = $stripe->subscriptions->create(
I changed that in my project to be:
$subscription = \Stripe\Subscription::create(
is that the right thing to do for PHP? it better matches the first PaymentIntent example that worked before
I think you should trust the Doc for $stripe->subscriptions->create
Does it not work for you?
that project that you sent in the link has a bunch of variables I'm not familiar with that are not in my project
$app, Request $request, Response $response,
$stripe
Um sorry, it's general idea but it's the official Doc
like, in that example, what is $app at the very top?
is this a standalone PHP page that generates the entire form?
or does it still call back to the client side React
That's framework specific code. You can ignore and focus on the call to create Subscription
https://stripe.com/docs/api/subscriptions/create?lang=php this could be easier to convert
Complete reference documentation for the Stripe API. Includes code snippets and examples for our Python, Java, PHP, Node.js, Go, Ruby, and .NET libraries.
I feel like my php is working
when I go to www.mywebsite.com/create.php
it echoes this as output:
{"subscriptionId":"sub_1MHirEFtGvcbRuR6pmlVvWyk","clientSecret":"pi_3MHirEFtGvcbRuR61QBwZbK7_secret_MIaExdLDLNityCrfZ1EM72JoF"}
so I feel like it's passing through the php correctly, creating the subscription, and the incomplete subscription shows up for the new customer on my Stripe Dashboard
but then the React has that error:
Uncaught IntegrationError: In order to create a payment element, you must pass a valid PaymentIntent or SetupIntent client secret when creating the Elements group.
You should compare with when you were creating PaymentIntent and returns its client_secret, vs. when you are currently creating Subscription and returns its latest_invoice.payment_intent.client_secret
Are you returning the same format? like pi_xxx_secret_yyy
I didn't check what the paymentIntent example was producing
So, let double check what value you supply to the Payment Element. It should be the Payment Intent client_secret
ok I just ran it, the PaymentIntent old example
it produced:
{"clientSecret":"pi_3MHjaDFtGvcbRuR60879eSDK_secret_XmkzOEfzOPZciswghtDPO1l21"}
So it depends on how your frontend takes that response and parse to the React app
same way the old example worked
const stripeElementsOptionsAppearanceObj = {
theme: 'stripe',
};
const stripeElementsOptionsObj = {
clientSecretStringFromServer,
stripeElementsOptionsAppearanceObj
};
return(
<Elements options={stripeElementsOptionsObj} stripe={stripePromise}>
<CheckoutForm />
</Elements>
);
Elements takes in the stripePromise and options contains the clientSecret
CheckoutForm is just like the example, where it has:
<form id="payment-form" onSubmit={functionOnSubmitPaymentForm}>
<PaymentElement id="payment-element" options={stripePaymentElementOptionsObj} />...
a PaymentElement wrapped in a Form
does the exact wording of the 'id' fields in those HTML tags matter?
What produces clientSecretStringFromServer
like, does it have to be 'payment-form' and 'payment-element' exactly
const [clientSecretStringFromServer, f_setClientSecretString] = useState("");
useEffect(() => {
// Create PaymentIntent as soon as the page loads
fetch(k_sgtCreatePhpFileLoc, {
method: "POST",
headers: {"Content-Type":"application/json"},
body: JSON.stringify({ items: [{ id: "xl-tshirt" }] }),
})
.then((res) => res.json())
.then((data) => f_setClientSecretString(data.clientSecret));
}, []);
same as the example code, a useEffect() takes 'clientSecret' passed from PHP and stores it into clientSecretStringFromServer
I may have found it
there's a line in the original that I still have here:
const clientSecretStringFromServer = new URLSearchParams(window.location.search).get("payment_intent_client_secret");
(client side React inside of <CheckoutForm>)
that "payment_intent_client_secret", is it a different set of GET variable names that appear in the URL bar for subscriptions?
Not sure if I follow the last question, but yes looks like you want to make sure f_setClientSecretString(data.clientSecret) got the correct value for you
Probably console.log the clientSecretStringFromServer variable
I do have that printing and it all seems to be set ok with those examples I pasted above
I want to reask my last question
does the exact wording of the 'id' fields in those HTML tags matter?
like, does it have to be 'payment-form' and 'payment-element' exactly
also thanks for getting back to me on this, I've been changing and retesting constantly and still getting the same error over and over, even when going back to my original script that used to work
I don't think the Id matters, looking at our Doc here: https://stripe.com/docs/payments/accept-a-payment?platform=web&ui=elements&client=react#add-the-payment-element-component
The Id only matters in non-React approach, when we need the id to mount the HTML element
ok thanks, I'll keep working at this, thanks for your help and responses
Good luck!
I figured it out in case someone else needs help
this page shows the example for the 'options' prop different from the other example
const options = {
clientSecret: '{{CLIENT_SECRET}}',
};
return (
<Elements stripe={stripePromise} options={options}>
<CheckoutForm />
</Elements>
);
that led me to this page:
which clearly spelled out that the options prop needs 2 properties: 'clientSecret' and 'appearance'
yes it's different if you're using the PaymentElement (which needs a PaymentIntent upfront) versus using other components like CardElement
so, to be clear, the example link that I posted above, has the correct definition for <Element>
but this link:
for React-PHP
has this code
const appearance = {
theme: 'stripe',
};
const options = {
clientSecret,
appearance,
};
return (
<div className="App">
{clientSecret && (
<Elements options={options} stripe={stripePromise}>
<CheckoutForm />
</Elements>
)}
</div>
);
which seems to be the wrong way to put 'clientSecret' as a property into the js object that goes into the 'options' prop
just want to point this out and help, if this guide needs to be updated on your developer website, or if I'm missing some simple javascript way of defining objects {}
but thanks for all your and orakaro's help, I'm all good moving forward here!
it's just https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#property_definitions , you can pass object = {foo, bar} and it's the same as saying object = {foo: foo, bar: bar} to reference existing variables