#wesbos_api
1 messages ยท Page 1 of 1 (latest)
๐ Welcome to your new thread!
โฒ๏ธ We'll be here soon! We typically respond in a few minutes, but in some cases we might need a bit more time (e.g., server's busy, you've got a complex question, etc.).
โฑ๏ธ We close idle threads, which makes them read-only. Once a thread is closed it won't be reopened, but you can 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/1250897505692946473
๐ Have more to share? Add details, code, screenshots, videos, etc. below.
Was chatting with @ynnoj on twitter about this. I've added to the github issue here: https://github.com/stripe/stripe-js/issues/599
ynnoj has let me know I can manually handle the actions myself via an undocumented .confirmPayment() handleActions: false, , but I rather stick with Stripe handling it all for me and just hide my modal when stripe has theirs open
Oh hey!
hello!
Based on my understanding of the current situation, it won't be possible for Stripe.js to handle this automatically if you're using dialog
But I will bump this internally for more investigation.
Ideally we could handle this conditionally, but at minimum we should clarify the current limitation and workaround via manual actions
Okay great- I was thinking of another possible workaround. If I use the handleActions: false can I just opt to use the redirect method for 3DS that way?
I have no way to detect when the stripe modal opens
So, if you call that, you can back arequires_actionPI, correct?
You could redirect if you opt into that flow, but I think you could also close your top-layer modal and call handleCardAction for the same PI to surface the Stripe.js 3DS modal
https://docs.stripe.com/js/payment_intents/handle_card_action
Okay, so:
confirmPayment() returns a paymentIntent that may have a requires_action. If it does, I can close my modal and then call handleCardAction ?
What about other payment methods? I essentially want to determine if I need to close my modal or not and then call .handleNextAction() . Are cards the only actions that are embedded via a modal?
Yea that gets more complicated, and you need to look at the details of next_action:
https://docs.stripe.com/api/payment_intents/object#payment_intent_object-next_action-type
Complete reference documentation for the Stripe API. Includes code snippets and examples for our Python, Java, PHP, Node.js, Go, Ruby, and .NET libraries.
Oh right, handleNextAction should account for all caes, i think, and show the 3ds modal or redirect as required
Definitely something you'll need to test for your flow to confirm it does what you expect for cards + other test PMs
Ok - so the next action will either be a redirect or a modal, right? So closing my modal in any case should be fine
This is more relevant when confirming server-side, where you might redirect directly yourself to a 3rd party url, vs push back to your client for 3ds via Stripe.js (but it can also operate via redirect to bank url, if preferred).
Yes, I expect that to work in all cases since the first confirmation should have collected all the required payment details from the Element
(closing your modal with the Element before confirm would be a problem, since it would likely unmount the element and make the payment details inaccessible)
Oh not a problem in my case- using the browser API doesnt unmount
I think the only other issue I'm gonna have is the few second delay when you call handleNextAction. If I close my modal right away, then I have a few dead seconds before the nextAction happens. I'm kind of right back to wanting to find out if and when stripe shows a modal..
Hmm so you'd want to show some kind of loader UI until then? We don't currently emit any kind of event for that that I'm aware of, but might be a neat feature request.
yeah, i was snopping on window.addEventListener('message') - there is some sort of event, but im not sure which one is for stripe modal
But in the case of handleNextAction there's not necessarily an Element to tie the events too ๐ค
eg, if this was handleActions: true with PaymentElement, theoretically we could have paymentelement.on('actionmodal', ...)
But in the manual case is not clear where the .on() would go
Yeah I think it would be some sort of global API, just wanting to know when stripe opens a modal on the page
Maybe on the elements group itself? elements.on('actionmodal', ...)
even just putting a class on that div would be enough, I can watch for it
Would you be willing to share your account id (or any request id etc I can pull it from) so I can tie the feedback/feature request to that?
yep, for reference if you need it in future the account ID is here: https://dashboard.stripe.com/settings/account
but that request will do, ty
Sign in to the Stripe Dashboard to manage business payments and operations in your account. Manage payments and refunds, respond to disputes and more.
Oh noo, So handleNextAction doesn't have an option to set redirect: "if_required", ? So there is no way to trigger the modal ?
and I can't set it on the confirmPayment() call either
The docs suggest if_required is the expected behaviour:
Depending on the payment method and required action, the customer may be temporarily redirected from your site and brought back to the return_url parameter provided when the PaymentIntent is confirmed.
What are you seeing happen?
its redirecting me to the URL isntead of putting it in a modal iframe
pi_2PRK474CNRdLPvsT0KpweuxG
This one does not look like you've confirmed it yet
oh yah thats because that one errored, one sec Ill do it again without redirect: "if_required",
pi_2PRKAt4CNRdLPvsT17GwaJpT
req_7e1a3cczRVHbCf is the confirmation request
let confirmation = await stripe
?.confirmPayment({
elements,
clientSecret: intent.client_secret as string,
confirmParams: {
return_url: finalizeEndpoint.href,
payment_method_data: {
billing_details,
},
},
// redirect: "if_required",
handleActions: false, // Undocumented https://x.com/ynnoj/status/1801334076583837763
})
Ok let me poke at this for a few minutes
Okay thanks. I'm feeling like its probably another limitation. I'm going to poke away at detecting the stripe overlay some more
Ok, i'm still trying to work through the POC, but at a high level you'll need to modify your flow a bit to get the desired result
Basically, you need to separate your PE details collection from your action-handling (in order to close your modal)
This is essentially a two-step flow, so you can achieve it by creating a confirmation token from PE instead of confirming the payment directly, then closing the modal and calling confirmPayment with that confirmation token:
https://docs.stripe.com/payments/build-a-two-step-confirmation#create-ct
so instead of:
1/ confirmPayment(actions:false)
2/ handle actions
you'd do:
1/ create confirmation token
2/ confirm payment with CT (confirmation token)
what is CT?
const {error, confirmationToken} = await stripe.createConfirmationToken({
elements,
params: {
payment_method_data: {
billing_details: {
name: 'Jenny Rosen',
}
}
}
});
and
const {error} = await stripe.confirmPayment({
clientSecret,
confirmParams: {
confirmation_token: '{{CONFIRMATION_TOKEN_ID}}',
return_url: 'https://example.com/order/123/complete',
},
});
Are you familiar with the createPaymentMethod pattern?
Okay i see - and confirmPayment will pop up the modal for me?
Yes, thats right
and how do I know if its going to open the modal?
Confirmation Tokens (CT) are a bundle of the payment details and customer consent data to the presented terms
which can be used for later confirming a payment, without those details visible in PE any longer, either in the two-step client side pattern (think multi-step checkout or a staged funnel) or for server-side confirmation
You don't using the pure client approach, but you can if you do the server pattern
hmmmm.
The thing is I dont want to close the modal because in most cases I dont need to, and I also show the success confirmation int he modal
I think this will work a bit better - I had looked into the paymentMethod flow instead earlier today - but it still doesnt tell me when the modal needs to open
Right, so to have that control you'd need to use the CT to confirm the PI on the server, and check whether an action is needed
if it goes straight to succeeded you can show your success message
ahhhh okay
If its requires_action then you use handleNextAction
and with the server-confirm you can force request using Stripe.js to handle your 3ds:
use_stripe_sdk=true
https://docs.stripe.com/api/payment_intents/create#create_payment_intent-use_stripe_sdk
Complete reference documentation for the Stripe API. Includes code snippets and examples for our Python, Java, PHP, Node.js, Go, Ruby, and .NET libraries.
like i said, still trying to build my POC
but handleNextAction still doesnt show a modal? Only redirects?
Ive gotta run to dinner - thank you for your time on this. Ill check back tomorrow.
I also have been toying with this hack to detect the modal being on the page:
function useStripeModal() {
const [open, setOpen] = useState(false);
// Continually check if there is a stripe modal div
useInterval(() => {
const stripeModal = document.querySelector(
'div[tabindex="-1"] > iframe[name*="__privateStripeFrame"]'
);
setOpen(!!stripeModal);
}, 1000);
return open;
}
The trick here is with use_stripe_sdk -- that should be enough to get the modal for 3ds
just about wrapped my demo/test flow
Ok, yea, this works like I described ๐
Demo will sit here for now: https://apocalypse-supplies.glitch.me/upe-di
(it's messy, just a playground)
A cool thing made with Glitch
async function createCtAndPay() {
console.log('createCtAndPay!');
const elementsSubmitResult = await elements.submit();
const createCTResult = await stripe.createConfirmationToken({
elements,
});
console.log("createCTResult");
console.log({createCTResult});
const piResult = await fetch('/upe-pi-ct', {
method: 'post',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
confirmation_token: createCTResult.confirmationToken.id,
})
});
const piData = await piResult.json();
console.log("piResult data");
console.log({piData});
if (piData.status == "requires_action") {
if (piData.next_action.type=="redirect_to_url") {
window.location.replace(piData.next_action.redirect_to_url.url);
} else if (piData.next_action.type=="use_stripe_sdk") {
const actionResult = await stripe.handleNextAction({
clientSecret: piData.client_secret,
})
console.log("actionResult");
console.log(actionResult);
} else {
console.warn('Unexpected PI next_action.type:', piData.next_action.type)
}
} else if (piData.status == "succeeded") {
console.log('Payment Succeede!')
} else {
console.warn('Unexpected PI status:', piData.status)
}
}
Server:
app.post("/upe-pi-ct", async function(request, response) {
console.log("in /upe-pi-ct...");
const { confirmation_token: confirmationTokenId } = request.body;
const pi = await stripe.paymentIntents.create({
amount: 4242,
currency: 'usd',
return_url: 'https://example.com/success',
automatic_payment_methods: {
enabled: true,
},
confirm: true,
confirmation_token: confirmationTokenId,
use_stripe_sdk: true,
});
response.send({
status: pi.status,
next_action: pi.next_action,
client_secret: pi.client_secret,
type: 'payment'
});
});
If you try the demo use 4000 0027 6000 3184 in the PE card form and the "Create CT & Pay PI" button
Thank you! I will review tomorrow. You are awesome - very helpful