#codename-mid9it_code
1 messages ยท Page 1 of 1 (latest)
Below are links to other discussions we've had with you in the past week in case you want to review that information. If your question is related to one of these previous discussions, please provide a comprehensive summary of the current state and what you need help with now. We help many users simultaneously, so a summary allows us to resolve your issue as soon as possible.
- codename-mid9it_error, 1 day ago, 14 messages
- codename-mid9it_code, 3 days ago, 76 messages
๐ Welcome to your new thread!
โฒ๏ธ We'll be here soon! Typically we respond in a few minutes, but sometimes we might take a bit longer if the server is busy or if you have a particularly tricky question.
โฑ๏ธ We close idle threads, which makes them read-only. Once a thread is closed it won't be reopened, but you can always start a new thread if you have another question.
๐ This thread will always be available, even after it's closed. You can find it again using Discord's search, or you can save this link: https://discord.com/channels/841573134531821608/1220416441736495185
๐ Have more to share? Add more details, code, screenshots, videos, etc. below.
The is my backend logic using PHP
if($_SERVER['REQUEST_METHOD'] == "POST"){
set_value($_POST);
$token = (isset($_POST['stripeToken'])) ? $_POST['stripeToken'] : null;
$crad_number = (isset($_POST['crad_number'])) ? $_POST['crad_number'] : null;
$month = (isset($_POST['month'])) ? $_POST['month'] : null;
$year = (isset($_POST['year'])) ? $_POST['year'] : null;
$cvv = (isset($_POST['cvv'])) ? $_POST['cvv'] : null;
// Validation
$errors = array();
if(empty($token)){
$errors[] = 'Token is required';
}
if(empty($crad_number)){
$errors[] = 'Crad Number is required';
}
if(empty($month)){
$errors[] = 'MONTH name is required';
}
if(empty($year)){
$errors[] = 'YEAR is required';
}
if(empty($cvv)){
$errors[] = 'CVV is required';
}
if(empty($errors)){
try{
$stripe = new \Stripe\StripeClient('stripe test key');
// Creat Customer In Stripe
$customer = \Stripe\Customer::create(array(
"email" => $email,
"name" => $membernamedata,
'source' => $token,
));
$finalamount = $amount*100;
$paydesc = "Members Online Directory";
// Create the subscription with the found product ID
$subscription = $stripe->subscriptions->create([
'customer' => $customer,
'items' => [['price' => $product_id]],
"currency" => $_currency,
"description" => $paydesc,
//'amount' => $finalamount,
]);
// Create Payment Intent
try {
$stripe = new \Stripe\StripeClient('stripe test key');
// Create PaymentIntent
$intent = $stripe->paymentIntents->create([
'amount' => $finalamount,
'currency' => $_currency,
'customer' => $customer->id, // If customer already exists
'payment_method_types' => ['card'],
'confirmation_method' => 'manual',
'confirm' => true,
]);
// Check if 3DS is required:
if ($intent->status === 'requires_action') {
echo json_encode([
'requires_action' => true,
'client_secret' => $intent->client_secret,
'redirect_url' => $intent->next_action->redirect_to_url->url // Stripe will provide the redirect URL
]);
}
} catch (\Stripe\Exception\Exception $e) {
// Handle Stripe errors
echo json_encode(['error' => $e->getMessage()]);
}
<!-- Stripe JavaScript library -->
<script src="https://js.stripe.com/v2/"></script>
<script>
// Set your publishable key
Stripe.setPublishableKey('stripe test key');
// Callback to handle the response from stripe
function stripeResponseHandler(status, response) {
if (response.error) {
// Enable the submit button
$('#payBtn').removeAttr("disabled");
// Display the errors on the form
$(".payment-status").html('<p>'+response.error.message+'</p>');
}
else{
var form$ = $("#payment-form");
// Get token id
var token = response.id;
// Insert the token into the form
form$.append("<input type='hidden' name='stripeToken' value='" + token + "' />");
// Submit form to the server
form$.get(0).submit();
}
}
$(document).ready(function(){
// On form submit
$("#payment-form").submit(function (event) {
event.preventDefault(); // Prevent default form submission
// Disable the submit button
$('#payBtn').attr("disabled", "disabled");
$.post("/join-us/payment.php") // Assuming payment.php is the form's action
.done(function (data) {
if (data.requires_action) {
// Redirect to Stripe for 3DS
window.location.href = data.redirect_url;
} else {
// Payment successful (no 3DS)
console.log("Payment successful!");
}
})
.fail(function () {
// Re-enable submit button
$('#payBtn').removeAttr("disabled");
console.log("Error submitting to backend");
});
});
// Submit from callback
return false;
});
</script>
currently the only thing i see on my network tab using browser dev tools "Payment Successful" but then no stripe customer or subscription is created, neither am i redirected to an authentication page.
Have you debugged what is happening on your server? It sounds like something may be going wrong there that is failing in a way that your frontend isn't expecting
Like are your create subscription and intent calls being made at all?
Also quick question: is there a reason that you are creating both a subscription and a payment intent here? Like are these two separate payments? Depending on how much you can change about your site, you can simplify this to only use the subscription's initial payment intent.
I've but i'm getting no error logs neither are errors being displayed on the page.
๐ hopping in here since pompey has to head out
Hello Karbi
If you're seeing "Payment Successful" in your console logs that means your client-side is getting data.requires_action: false, right? Have you checked what the response was from your servver and confirmed it's sending the response you expect?
I've tried by using var_dump() but i get no output. I've checked for errors and it's the same thing no output.
Have you checked your stripe account to make sure thre requests are goingn through? If you have an account ID or example request ID I could take a look
in my intial code before i included the paymentintent, request were going thru and i could create customers and subscription. i was even able to generate the "client secret" but it would only work using non 3ds cards. if i used a 3ds card then on the subscription tab in the dashboard the customer and subscription will be created but the subscription will be noted as incomplete
let me get you an example id
Yeah an example ID would help a lot
this is the one using a 3DS card
sub_1OwkCkDLt3ELpQcmnD19emZt
this is a non 3ds card
sub_1OwkE8DLt3ELpQcmmaCOSwp3
For sub_1OwkCkDLt3ELpQcmnD19emZt I don't see you creating a separate payment at all so it doesn't seem like that part of your code is being hit
and backing up for a bit - if you're creating a subscription you shouldn't need to create a separate PI. You should be able to reuse the Payment Intent that is generated on subscription creation
yes it's not a separate payment. i'm new to setting up stripe. so i usually go to the docs as reference point but sometimes i really don't understand it all, like when i wanted to use subscription schedule for setting future subscription, meanwhile i should have just maintained my original create subscription code. it took days for me to finally get it. just as you and pompey have said about this paymentIntent thing
any ideas on how i should proceed from here on? i was creating the paymentIntent because i wanted to create the verification step i was missing
or you could say the authentication for 3DS card. so say i revert my code back to the point i was able to successfully create customers and subscription successfully using non 3DS cards. (because i can no longer do so since i started using the paymentIntent). what will i do next
Yeah I'd rip out the Payment Intent creation code, and then:
- update your subscription creation code to expand
latest_invoice.payment_intent - and then add logic that check
latest_invoice.payment_intent.status = 'requires_action'to know if 3ds is required or not
you mean like this
'expand' => ['latest_invoice.payment_intent'],
Yes, but the key thing is expanding latest_invoice.payment_intent. Try it out - after adding the expansino you should be able to see the full Payment Intent in your sub creation response
alright then after i do so and add the logic, do still put something this in the logic?
echo json_encode([
'requires_action' => true,
'client_secret' => $subscription->client_secret,
'redirect_url' => $subscription->next_action->redirect_to_url->url
and what about the js side?
Yeah, you'd still need to implement the next action redirect on your end
You had a lot of it already in the code you shared earlier
but i was failing successfully at it lol.
at this point i don't even know anymore.
but at least i can remove paymentIntent block
Yeah you weren't really reach the next action redirect code at all though since your server-side code wasn't behaving as you'd expect. If I were you I'd make the server-side changes, make sure your endpoint is returning the response you expect, and then move on to the client-side stuff
Also I know you mentioned this earlier but if you can convince your client to upgrade I'd strongly recommend stripejs v3. It'll make the client-side piece much easier
i already told 'em but it's not in my current job scopes cause a lot of their apis are deprecated but oh well. if this v3 i could have used stripe elements long time ago looooool
okay just so we can round this up immediately.
i should
- Rip out the Payment Intent creation code
- Update your subscription creation code to expand latest_invoice.payment_intent
- add logic that check latest_invoice.payment_intent.status = 'requires_action' to know if 3ds is required or not
4)............
- Add your client-side logic to check if 3ds is required and display it if so (https://docs.stripe.com/payments/3d-secure/authentication-flow?platform=web#when-to-use-3d-secure)
will this work with version 2?
You handling the 3DS redirect or iframe display manually should work, yes, but not the automatic handling
hello synth.
so that means in my logic that checks latest_invoice.payment_intent.status = 'requires_action' following what karbi suggested earlier i should set 'confirmation_method'='manual' and also 'confirm' => true?
That sounds right, and then inspect to handle the 3ds/action case
One little gotcha to be aware of this using that flow: after the 3ds action is handled, you need re-confirm the payment intent to complete the payment within 1 hour
If you wait more than 1 hour after that happens, the payment intent will revert back to requires_payment_method
okay, now i'm legit confused. so you mean once the 3ds action is handled, i'll need like a "confirm.php" to complete the payment? and how does this affect future subscriptions, like if collection_method is "charge_automatically"?
It looks like my information might be outdated here, since the redirect handling suggests the payment will be succeeded
https://docs.stripe.com/payments/3d-secure/authentication-flow?platform=web#handle-redirect
But yes, you might need to handle 3ds authentication for future subscription payments, that is a possibility
Stripe also offers a flow to handle this for you with customer emails to authenticate the payment
Let me grab information about that
actually i'm using stripe.js v2 so i can't use a few of the new objects or methods
alright
but if you more versatile with v2 you could save my life rn lol
We strongly recommend upgrading to v3 as karbi said, v2 is far out of date and does not support much of our current functionality
ikr but unfortunately it up to my client not me : (
else i'd be long done with this job
please help me look at my js part of the code, is there anything i should change?
i forgot to add this part
// Create single-use token to charge the user
Stripe.createToken({
number: $('#crad_number').val(),
exp_month: $('#month').val(),
exp_year: $('#year').val(),
cvc: $('#cvv').val()
}, stripeResponseHandler);
// Submit from callback
return false;
This is the information about getting webhooks to handle authentication (3ds) when needed
Other that being an old pattern we no longer recommend, the token creation is not the problem, its that you need to handle authentication later.
i tried setup webhooks but it was a mess and never worked
You really should get webhooks set up to learn about future payment failures
but looking at this i don't really have much problem, yeah? except the part you said i need to re-confirm the payment intent
But, if you don't have that for now then i strongly recommend setting up the automatic customer emails for completing subscription payments that need 3ds: https://docs.stripe.com/billing/subscriptions/overview#recurring-charges
you can configure your billing settings to send a hosted link to customers so they can complete the flow.
The links there are to the relevant dashboard settings
except the part you said i need to re-confirm the payment intent
Yep, ok I found the info I was looking for here: https://docs.stripe.com/payments/payment-intents/upgrade-to-handle-actions?platform=web#update-server-second-confirm
Confirm the PaymentIntent again
Server-side
Using the same endpoint you set up earlier, confirm the PaymentIntent again to finalize the payment and fulfill the order. The payment attempt fails and transitions back to requires_payment_method if it is not confirmed again within one hour.
i'm looking at all the docs.
but these docs are mostly for the new stripe yeah? so i don't waste time on implementing things that won't be compatible with the stripe i use now
also is there a doc that shows how i can use webhooks to send the customers a hosted link to confirm payment and what happens after that?
theres so much docs and only got until tomorrow to finish up lol
All our docs are assuming use of the latest v3, just as they are targetted towards the latest API version. That said, the hosted options should work regardless of your specific integration details.