#hooky-india-mandate

1 messages ยท Page 1 of 1 (latest)

fair parrotBOT
bitter fiber
#

(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.

odd solstice
#

Ah

#

makes sense

#

No worries at all. If this thread is still open you can message here

bitter fiber
#

I just had lost track of the test setupIntents I was creating and testing. ๐Ÿ˜„

odd solstice
#

Gotcha

bitter fiber
#

Cool! I'll just test I am able to reproduce my production error if I try a new setupIntent without the mandate options.

odd solstice
#

Sounds good

bitter fiber
#

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'
}
unreal narwhal
#

๐Ÿ‘‹ stepping in

#

Catching up and taking a look

bitter fiber
#

(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)

unreal narwhal
#

Can you give me that request ID

bitter fiber
#

I don't have it at hand, I just have the screenshot. I can track it down from the invoice I suppose, one sec...

unreal narwhal
#

Nah that's okay

#

We could both just type it out from the screenshot

#

Just didn't want to do that lol

bitter fiber
#

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.

unreal narwhal
#

Yes that's correct.

bitter fiber
#

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.

unreal narwhal
#

Looking one sec

simple kiln
#

hooky-india-mandate

unreal narwhal
#

Okay all caught up

#

That error though is indeed confusing

bitter fiber
#

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?

unreal narwhal
#

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

bitter fiber
#

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!)

unreal narwhal
#

Yep just pop back in here

#

If the thread gets archived feel free to post back in main channel

bitter fiber
#

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.

unreal narwhal
#

Yep you can pass mandate_data on confirm client-side

#

Yep

bitter fiber
#

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???)

unreal narwhal
#

Yeah the client-side confirm request will do both

#

Create the PaymentMethod and create the Mandate

bitter fiber
#

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?)

unreal narwhal
#

No the payment_method is optional

#

You can ignore that

bitter fiber
#

ahhhhh

unreal narwhal
#

It is a separate param from mandate_data

bitter fiber
#

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?

unreal narwhal
#

If you confirm server-side then yes you need a PaymentMethod

bitter fiber
#

Cool!

#

My bad.

#

Excellent.

unreal narwhal
#

Np!

bitter fiber
#

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?

unreal narwhal
#

You got it

bitter fiber
#

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.

unreal narwhal
#

Hmm one sec

bitter fiber
#

Aha

#

(oops, typo in my last block of code. I meant mandate_data) - fixed it

unreal narwhal
#

Okay everything you said is correct, except unfortunately our product is weird here

#

I'm going to file some feedback about this

bitter fiber
#

Okay... ๐Ÿค”

unreal narwhal
#

But let me explain

#

There you will see the mandate_data parameters

#

However, that does not have the mandate_data params that are necessary for India mandates

bitter fiber
#

Ahhhh

unreal narwhal
#

That mandate_data is actually within payment_method_options.card.mandate_options

bitter fiber
#

Right, I follow.

unreal narwhal
#

But the issue here is that payment_method_options is a server-side only parameter

bitter fiber
#

Ooooh

unreal narwhal
#

(Notice that in the API Ref it says secret key only)

bitter fiber
#

Yes, I see. I follow you so far.

unreal narwhal
#

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.

bitter fiber
#

Makes sense. However... how will I "combine" both setupIntents?

unreal narwhal
#

You don't need to

bitter fiber
#

or can I "update" the client side one?

unreal narwhal
#

All you need is the PaymentMethod ID and then the mandate ID that is created from the second SetupIntent

bitter fiber
#

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?

unreal narwhal
#

Yep

#

You are using Payment Element right?

bitter fiber
#

Yes

#

I think so?

unreal narwhal
#

Yeah then the above flow is correct

bitter fiber
#

Are there other Elements?

unreal narwhal
#

There are but ignore them ๐Ÿ™‚

bitter fiber
#

This is for setting up a payment method for subscriptions.

unreal narwhal
#

Yep Payment Element is the way to go

bitter fiber
#

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?

unreal narwhal
#

Yep

bitter fiber
#

Excellent. Sounds good!

unreal narwhal
#

Try it out and let us know if you run into any further issues

bitter fiber
#

Will do!

#

Quick question!

unreal narwhal
#

Sure

bitter fiber
#

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?

unreal narwhal
#

No you don't need the SetupIntent

bitter fiber
#

Ahh because setupIntent is just for the process of adding new payment methods, right?

#

Silly me ๐Ÿ˜„

#

Allright, thank you!

unreal narwhal
#

Np!

bitter fiber
#

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?

unreal narwhal
#

Afaik that isn't possible right now and you have to pass it on every /pay attempt. Let me double check

#

But don't believe we currently support that on Subscription creation

bitter fiber
#

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? ๐Ÿค”

unreal narwhal
#

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

bitter fiber
#

Ahhh I understand.

#

Well, thanks for your help!

unreal narwhal
#

๐Ÿ‘

bitter fiber
#

(I would advise to also explain this last point prominently in the docs, it will save many people some time ๐Ÿ˜†)

unreal narwhal
#

Yep fair call out for sure

#

I'll include it with my feedback