#pinho-paymentelement-php
1 messages ยท Page 1 of 1 (latest)
Hi ๐ what's your question?
Hi
I'm using the following approach to create a checkout process: https://stripe.com/docs/payments/accept-a-payment?platform=web&ui=elements&html-or-react=html#web-submit-payment
In this point:
const {error} = await stripe.confirmPayment({ //Elements instance that was used to create the Payment Element elements, confirmParams: { return_url: 'https://example.com/order/123/complete', }, });
The documentation says:
"Make sure the return_url corresponds to a page on your website that provides the status of the payment. When Stripe redirects the customer to the return_url, we provide the following URL query parameters:"
However, when stripe redirects, the URL does not contain any query parameters
So I thought about adding the parameter manually, like such:
confirmParams: { return_url: window.location.href = Helper.getBaseUrl() + app/cart/${storeId}/checkout/finish/${orderId}?payment_intent_token=${stripePaymentIntentToken}, },
Which works, but when validating in PHP if the payment has been succeeded:
`public function getPaymentIntent(string $paymentIntentToken): array
{
$result = $this->stripe->paymentIntents->retrieve($paymentIntentToken);
return $result;
}`
I get the error: "You passed a string that looks like a client secret as the PaymentIntent ID, but you must provide a valid PaymentIntent ID. Please use the value in the id field of the PaymentIntent."
Taking a look now
Ok, I solved by passing the paymentIntentID and not the "client_secret".
Tell me other thing please:
Ah, okay. That was the first thing I was going to ask
is this the correct way to check if certain intent has been paid?
Yeah, you would check the status on the Payment Intent in order to decide what to show the customer
Status says
"requires_payment_method"
Stripe\PaymentIntent JSON: {
"id": "pi_3M7N2NCENMAgnvaD0PdAYR0E",
"object": "payment_intent",
"amount": 97090,
"amount_capturable": 0,
"amount_details": {
"tip": []
},
"amount_received": 0,
"application": null,
"application_fee_amount": null,
"automatic_payment_methods": null,
"canceled_at": null,
"cancellation_reason": null,
"capture_method": "automatic",
"charges": {
"object": "list",
"data": [],
"has_more": false,
"total_count": 0,
"url": "/v1/charges?payment_intent=pi_3M7N2NCENMAgnvaD0PdAYR0E"
},
"client_secret": "pi_3M7N2NCENMAgnvaD0PdAYR0E_secret_BVIZD3KeJ58zTVEGQv2UBf9vg",
"confirmation_method": "automatic",
"created": 1669225627,
"currency": "eur",
"customer": null,
"description": null,
"invoice": null,
"last_payment_error": null,
"livemode": false,
"metadata": [],
"next_action": null,
"on_behalf_of": null,
"payment_method": null,
"payment_method_options": {
"card": {
"installments": null,
"mandate_options": null,
"network": null,
"request_three_d_secure": "automatic"
}
},
"payment_method_types": [
"card"
],
"processing": null,
"receipt_email": null,
"review": null,
"setup_future_usage": null,
"shipping": null,
"source": null,
"statement_descriptor": null,
"statement_descriptor_suffix": null,
"status": "requires_payment_method",
"transfer_data": null,
"transfer_group": null
}
"requires_payment_method" is the status.
This doesn't tell me the user has indeed paid
My main problem is that the flow is the following:
Redirect URL = https://mywebsite.com/store/2921/checkout/finish/2919
Checkout > Confirm Payment > Paid > Redirect URL > Set order as paid
However, the user can try to hack the system and directly access the RedirectURL manually without paying. This is why I need to check the status of the IntentToken created, to see if indeed the user has paid certain order before proceeding to tell that the order is paid.
I'm not sure I understand the problem here though. If you're checking the status of the Payment Intent during the redirect (e.g. before the return_url page renders), isn't this a non-issue?
It's after the redirect.
Again, the process is the following:
return_url = https://mywebsite.com/store/2921/checkout/finish/2919
Checkout page > Confirm payment (stripe.confirmPayment() javascript function) > Goes to return_url > Sets order as paid
What prevents the user from acessing the return_url directly? Nothing.
๐ taking over as there are 20 people asking questions in parallel
The URL is client-side so it's normal that anyone can see it and visit it. What you need to do is when someone visits that page, you check their PaymentIntent and its status, either in the API or in your own database
pinho-paymentelement-php
Yes, the status of payment intent for the ID "pi_3M7N2NCENMAgnvaD0PdAYR0E" is returning "requires_payment_method".
I'm using the TEST Cards 4242..
How did I never confirmed if the redirect has been made by await stripe.confirmPayment() ?
this is you calling confirm with no info
server-side with a secret key
so doesn't look like you confirmed that specific PaymentIntent client-side at least
Do you see any error here?
The stripeElements is OK?
Because the stripeelements is later used on the confirmation
Also, if there was a problem with the confirmation, supposedly, stripe wouldn't redirect to redirect_url, right? It's redirecting just fine.
Please don't share pictures of code. We're both devs, way easier to read code as text. Right now I don't follow what you need really. Step 1 is to debug what is going on since you clearly never called confirmPayment() on the PaymentIntent you think you did
So I'd recommend adding clear logs to see the PaymentIntent client_secret you're using, what the API returns, etc.
if it redirects fine, it means the confirmPayment() call worked. And so my guess is that you are looking at the wrong PaymentIntent afterwards
if you look at your logs in your Dashboard at https://dashboard.stripe.com/test/logs you should see it all
did you figure it out @dusty junco ?
Kind of...I'm making two requests simultaneously, I saw that in the logs, because the number of seconds between them is too low. And I just figure out it was a fucking chrome extension that was calling the page twice without me even noticing!
Im gonna test it now again
Ok, now I know that only one request was made and it's ok.
I confirmed the payment by using the Stripe 4242 Test Card > Stripe redirected to my url > I checked the status of the intent_id and it is still requires_payment_method
If the payment has not been done, stripe wouldn't redirect me.
ah gotcha so you were creating two PIs by mistake and caching the wrong one
yes, it was a problem that I wasn't aware. However, still doesn't work..or at least the status is always requires_payment_method and I believe at this point I should be getting succeeded
I mean minutes ago you duplicated the PI. So it's likely the same problem here again. You need to carefully log all data and see what happens. It's almost certain that you confirm the PI pi_123 but then look at the PI pi_ABC
Can you please see the attached video?
As you can see the ID's are correct now.
(I believe....)
Please try to provide actionable inforamtion in pure text. Sorry but Discord is really busy right now and you're rushing through too quickly
1/ Create a PI
2/ Confirm it client-side
3/ Look in the Dashboard and check if you had a payment or an error
I mean what happens client-side? Are you really calling confirmPayment()?
or are you mistakenly just redirecting/submitting the page on click with your submit button
What d'hell is "Customer has not enterered their payment method"?
I submitted the credit card details
I mean you didnt
if you look at your logs you can see you never called anything but POST /v1/payment_intents
my guess is that your code is incorrectly redirecting when you click the submit button without ever calling confirmPayment()
Add some console.log() before/after the call to confirmPayment() and you'll see it's likely never called
omfg
The return_url is filled like this: "return_url: window.location.href = Helper.getBaseUrl() + app/cart/${storeId}/checkout/finish/${orderId}?payment_intent_id=${stripePaymentIntentId}"
do you see the problem? I'm using window.location.href !!!!
oh lol I saw this earlier and I thought it'd just crash so it was just "pseudocode" ๐น
browsers and javascript can be the weirdest sometimes, why wouldn't you immediately crash on code like this!!!
I'm receiving now the error In order to create a payment element, you must pass a valid PaymentIntent or SetupIntent client secret when creating the Elements group.
My stripe instance is created like such:
`const options =
{
locale: 'pt',
fonts: [{ cssSrc: 'https://fonts.googleapis.com/css?family=Poppins:400,500' }],
appearance:
{
theme: 'stripe',
variables:
{
fontFamily: 'Poppins, sans-serif',
fontWeightNormal: 500,
fontSizeBase: '14px',
fontSizeSm: '14px',
}
},
};
stripeElements = stripe.elements({ stripePaymentIntentToken, options });
const paymentElement = stripeElements.create('payment');`
Yes, I double checked and the value of stripePaymentIntentToken is pi_3M7OcMCENMAgnvaD1nHUAm7V_secret_x7Flf6OmQkhFpg05FAvucusKv
If I follow strictly the documentation:
stripeElements = stripe.elements({ stripePaymentIntentToken }); const paymentElement = stripeElements.create('payment');
I get the error: "In order to create a payment element, you must pass a valid PaymentIntent or SetupIntent client secret when creating the Elements group."
I mean that simply means you don't
log that secret and you will see it's not there
sorry to push back but server is really busy and this is an introductory question, if you clearly log the parameter/options you give to Elements you'll see if it works
clientSecret: '{{CLIENT_SECRET}}',
};
// Set up Stripe.js and Elements to use in checkout form, passing the client secret obtained in step 3
const elements = stripe.elements(options);```
like are you passing the right option with the right name? You see to pass something called stripePaymentIntentToken for some reason
Thats just the variable name, I just did a console.log(stripePaymentIntentToken); and it matches the logs
someone
please
kill me
ffs
you guys require the variable names
to be exactly like in the documentation
!!!!
even the elements variable, can't be called anythingElse !!!
It's working man. Thanks for your extensive help, much appreciated. I just gained 100 white hairs.
๐
@dusty junco I think you might just misunderstand some parts of javascript
When you create the PaymentElement we have an option/parameter named clientSecret. We need that value, if you pass { blablabla: 'random value', } how would we know that you meant to pass this in clientSecret? Naming matters
what you can do is this stripeElements = stripe.elements({ clientSecret: stripePaymentIntentToken, });
like you use whatever variable name you want and you explicitly pass it as the right parameter. The short hand version you used {stripePaymentIntentToken} assumes that you pass an option named stripePaymentIntentToken with the value of that variable, that's a JS behaviour, not a Stripe specific thing