#hooky-india-mandate
1 messages ยท Page 1 of 1 (latest)
(I used this test card number: "4000003560000123", which corresponds to 3D Secure 2, "Simulates successful mandate setup and renewals.")
And a side question, question #2: setupIntents don't involve amounts, right? so could that be the reason I don't get the error? perhaps only when the charge is attempted, IF it surpasses the 15,000 INR threshold, then I'd get the error?
However what confuses me is that the successful setupIntent I created does contain a mandate_id! maybe it's an empty, placeholder one?
Ohhh wait, hold on, I am so sorry. I think in my testing I DID create a mandate explicitly using the options. Silly me! Disregard this. If I run into problems I'll open a new thread. My bad.
Ah
makes sense
No worries at all. If this thread is still open you can message here
I just had lost track of the test setupIntents I was creating and testing. ๐
Gotcha
Cool! I'll just test I am able to reproduce my production error if I try a new setupIntent without the mandate options.
Sounds good
Hmmm, so I was unable to reproduce the error that requires you an e-mandate...
Here's an example setupIntent: seti_1McWweA3np33huFNqB374Ncp
Here's how I see it:
{
id: 'seti_1McWweA3np33huFNqB374Ncp',
object: 'setup_intent',
application: 'ca_I4LOYSW5co4HuYMTsK2TW9xH0x2ZQ5vP',
cancellation_reason: null,
client_secret: 'seti_1McWweA3np33huFNqB374Ncp_secret_NNHVcFQCdkvIjOdSocntCxN5byThvUR',
created: 1676651880,
customer: 'cus_NN7hAciDX0lq2E',
description: null,
flow_directions: null,
last_setup_error: null,
latest_attempt: 'setatt_1McWyeA3np33huFNkfqv0rVS',
livemode: false,
mandate: null,
metadata: {},
next_action: null,
on_behalf_of: null,
payment_method: 'pm_1McWyeA3np33huFNvaIxYB05',
payment_method_options: {
card: {
mandate_options: null,
network: null,
request_three_d_secure: 'automatic'
}
},
payment_method_types: [ 'card' ],
single_use_mandate: null,
status: 'succeeded',
usage: 'off_session'
}
The card I used was the first 3D Secure 2 one from here: https://stripe.com/docs/india-recurring-payments#test-mandate-setup
4000003560000123 - Simulates successful mandate setup and renewals.
(In a moment I can share the error message I was expecting to see, but I was unable to reproduce)
This is the one. We get it in production because we currently don't specify mandate for India customers.
(I should also ask: That error message seems wrong, no? The mistake we did was providing neither mandate id or options. Not both, like the error says)
Can you give me that request ID
I don't have it at hand, I just have the screenshot. I can track it down from the invoice I suppose, one sec...
Nah that's okay
We could both just type it out from the screenshot
Just didn't want to do that lol
XD
ahhhh yes, I see the request ID on the top right, too
This is just one example. We've gotten a bunch of these.
The context is: We are a B2B serving many countries. And we recently found some of our new functionalities were not working for Indian customers (specifically: updating payment info in the context of dunning), because of this e-mandate thing. So we're kinda rushing to fix it ASAP. ๐
I understand it's safe to just add a bunch of mandate options to ALL setupIntent creations, right? And this will only be used for the cases where it's needed, for India-issued cards. And in the rest of the cases, this will just be ignored.
Yes that's correct.
So the weird part is that I'm not able to reproduce the error I showed you in the screenshot. If I create a setupIntent in a little sandbox script locally, it works. If I include mandate options, it creates a mandate_id nicely. But if I do not include those mandate options... I don't get the error! (like I do in production)
Surely I'm doing something wrong.
Ahh I wonder if the error only occurs when actually paying, not when creating the setupIntent!!! ๐ค๐ค๐ค
The example I shared in the screenshot is a invoice/.../pay one.
Looking one sec
hooky-india-mandate
Okay all caught up
So what you need to be doing here is actually passing the mandate ID on /pay: https://stripe.com/docs/api/invoices/pay#pay_invoice-mandate
We talk about this a bit here: https://stripe.com/docs/invoicing/india-emandate-guide#use-mandate-charge
That error though is indeed confusing
Ahhhh, okay
I'll try that in my testing.
And a second question I just realized:
When you create a paymentIntent, that's for a specific payment, and you are supposed to have a paymentMethodId at hand.
However, when you create a setupIntent, you're not supposed to have a paymentMethodId at hand, because you are actually about to set up a payment method, right? My current code in production looks like this:
const setupIntentOptions = {
customer: customerId,
usage: 'off_session',
};
But when one sets up e-mandates and adds a bunch of new options to the setupIntent creation... a payment_method is required. How could I have that? I am creating the setupIntent in order to create a new payment method through Stripe Element! No?
So you can still pass a PaymentMethod to a SetupIntent if it has already been created in order to set it up for future use with a mandate or to complete 3DS etc.
In terms of creating a PaymentMethod and creating a Mandate with a SetupIntent then you can indeed pass the necessary mandate_data when you confirm the SetupIntent.
So both options work
Aaaahhh
I see.
Well, I have a feeling I will have more questions in a few minutes. Should I write in this thread again if I find it's still open?
(Btw thanks for all your help so far!)
Yep just pop back in here
If the thread gets archived feel free to post back in main channel
Ok I'm back. ๐
So we're currently running the setupIntent creation server side. As discussed before, I couldn't possibly create the mandate here, because we don't know the paymentMethodId: This whole flow I'm working on is the end customer actually about to update payment method. That's fine.
Then, secondly... for setupIntent confirmation, we use the Stripe Element confirmSetup method, on the client side. However, at the point where I make the call stripe.confirmSetup({ elements, redirect: 'if_required' }) I don't think I have the new payment method ID at that point... I believe this very confirmSetup call is what makes Element gather the form data and create the new paymentMethod, no?
Here's a little screenshot of our client side page where end customers update their payment method:
I understand in line 191, the call confirmSetup allows to include mandate parameters.
But my problem is, I don't have the paymentMethodId at that point, because I'm actually calling this method in order to create a new paymentMethod! No?
Or maybe I'm misunderstanding something. ๐
(Perhaps Element has a way to create the paymentMethod first, and then, with the paymentMethodId at hand, actually confirm the setupIntent???)
Yeah the client-side confirm request will do both
Create the PaymentMethod and create the Mandate
Hmmm but the mandate_data I'm supposed to add to the call, includes a payment_method ID, no?
where do I get that from?
(Ohh or maybe when called from Element that's optional?)
ahhhhh
It is a separate param from mandate_data
But when I call from the server side, playing around with setupIntent confirmation, it does seem to require a payment method. Is that because in server side it's different?
If you confirm server-side then yes you need a PaymentMethod
Np!
So to my line of client side code where I call Element's confirmSetup,
Instead of:
confirmSetup({ elements })
I'll call
confirmSetup({ elements, confirmParams }) - as explained here https://stripe.com/docs/js/setup_intents/confirm_setup
Where confirmParams contains a mandate_data property with all the options. Right?
You got it
i.e.
mandate_data: {
reference: '{{REFERENCE}}',
description: '{{DESCRIPTION}}',
amount: 1099,
start_date: 1675238400,
amount_type: 'fixed',
interval: 'month',
interval_count: 1,
supported_types: ['india'],
},
Ok awesome, thanks! You've been of great help.
Hmm one sec
Okay everything you said is correct, except unfortunately our product is weird here
I'm going to file some feedback about this
Okay... ๐ค
But let me explain
If you look at https://stripe.com/docs/api/setup_intents/confirm you can see what you can pass to a SetupIntent confirmation
There you will see the mandate_data parameters
However, that does not have the mandate_data params that are necessary for India mandates
Ahhhh
That mandate_data is actually within payment_method_options.card.mandate_options
Complete reference documentation for the Stripe API. Includes code snippets and examples for our Python, Java, PHP, Node.js, Go, Ruby, and .NET libraries.
Right, I follow.
But the issue here is that payment_method_options is a server-side only parameter
Ooooh
(Notice that in the API Ref it says secret key only)
Yes, I see. I follow you so far.
I think this has to be secret key so that a malicious user can't set this client-side
As India mandates are sensitive
So actually our product isn't really weird here, but we could likely do a better job explaining this in our docs
So what you are going to want to do here is create your PaymentMethod client-side and then create/confirm a new SetupIntent server-side afterwards to actually pass payment_method_options and create your India mandate.
You won't be able to do that client-side.
Let me know if that doesn't make sense.
Makes sense. However... how will I "combine" both setupIntents?
You don't need to
or can I "update" the client side one?
All you need is the PaymentMethod ID and then the mandate ID that is created from the second SetupIntent
Ahhhhhh
So really I'll kind of ditch the setupIntent created client side, I don't care about it. I only care about allowing the end customer to create a PaymentMethodId.
So then I can use that PaymentMethodId to create and confirm a setupIntent server side. Right?
Yeah then the above flow is correct
Are there other Elements?
There are but ignore them ๐
This is for setting up a payment method for subscriptions.
Yep Payment Element is the way to go
cool
So,
This is client side.
In line 202 I call the server, chargeBalanceToCard, and pass the brand new paymentMethodId.
What I can do, is right there in the server, use that paymentMethodId to do all the work we discussed, server side.
Right?
Yep
Excellent. Sounds good!
Try it out and let us know if you run into any further issues
Sure
In my server side code where I get the paymentMethodId from the Payment Element, I do a few things, including retrieving the proper invoice, and then calling invoice.pay(invoiceId, {payment_method: paymentMethodId})
So the idea is that before doing that, I'll want to create a new setupIntent and confirm it with that paymentMethodId, and passing mandate options...
This will give me a brand new mandate_id,
And then when I actually call invoice.pay I need to include that mandate_id somewhere in the arguments, right? (I'll check the docs of that in a sec)
But do I also need to pass the setupIntent or something like that?
Ahh because setupIntent is just for the process of adding new payment methods, right?
Silly me ๐
Allright, thank you!
Np!
Oh, sorry to bother you. I have a follow up question here: I understand how and when and where to create the mandate, and how to use it when paying an invoice for a subscription.
However... how can I attach this mandate to the subscription, so that all the next invoices also use this mandate ID? Do I need to do that manually somehow?
Afaik that isn't possible right now and you have to pass it on every /pay attempt. Let me double check
like you can set it on Invoice creation: https://stripe.com/docs/api/invoices/create#create_invoice-payment_settings-default_mandate
But don't believe we currently support that on Subscription creation
Ah, I see. What if invoices are created automatically, due to a recurring subscription? Currently there's no way to make it automatically use a mandate, then? ๐ค
Right that's what I'm saying. I'm surprised that is the case... not sure if there is a reason that wasn't built or the team just hasn't gotten around to it yet.
Overall the India regulations do not want you to do recurring Subscriptions ๐
So that is likely why
๐
(I would advise to also explain this last point prominently in the docs, it will save many people some time ๐)