#ernezto_api
1 messages ยท Page 1 of 1 (latest)
๐ 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/1225856140848664709
๐ Have more to share? Add more details, code, screenshots, videos, etc. below.
Hi ๐
I'm having a little trouble following what you are doing with the requests. The Payment Method is added to the Customer using the Billing Portal.
Then you are attempting charge it and it fails due to a missing mandate?
First question, the Billing customer portal is used to manage payments for Stripe billing (E.g. Subscriptions and Invoices). Are you attempting to use it to collect payment methods for other reasons?
Well, essentially I understand that the mandate id is required. But in our case, how to do control the mandate id? We open the customer portal for our users and let them add any of the supported payment methods. But we're not registering anything on our end (at least not yet) then we use the API to get the payment method information (the default one) and create a payment intent with it
The only purpose of the Billing Customer Portal is to collect payment information, that's correct
Okay that is not how you should be using the Customer Portal in this case and I think that is the cause of the problem.
I see, what should I be using instead?
In this case I recommend you use the Checkout Session to collect payment method information. We document explicitly how to save payment methods for re-use later in this integration guide: https://docs.stripe.com/payments/save-and-reuse
So, I guess the mandate id be available in the checkout session we get via webhook call or synchronously with the redirect url, right?
Yeah, ok I see that the SetupIntent has the information in it
You will want to retrieve the Setup Intent as we describe in this step: https://docs.stripe.com/payments/save-and-reuse?platform=web&ui=stripe-hosted#retrieve-setup-intent. This will have the Payment Method included.
The payment_method property is, by default, just the ID but you can use the expand parameter to return the full object in a single API call. https://docs.stripe.com/expand
So something like setup_intent = stripe.SetupIntent.retrieve(set_XXXX, expand=['payment_method'])
Understood. Thanks for that info. There is a follow-up question tho. I would still like the customer to handle its payment preferences. Is there a recommended way to do that without the Billing Customer Portal?
By "payment preferences", do you mean setting a different payment method as the default?
exactly
If the customer wants to change the payment method we rely on the portal to allow the user to manage that information. But it seems like this is not the way to go.
We also have historical data (meaning users that already have a payment method with it's mandate id) and then isn't clear how to handle the migration to now be able to save the mandate_id on our end for upcoming payments
What you could do with Checkout (with just a bit more information) is add a Custom Field to allow a Customer to set whether or not the saved payment method should be their default.
For the historical data, can you share a Payment Method ID I can review?
well, this is not for a specific stripe subscription. We have an accounting system that uses stripe for many things but one of them is to collect money from subscriptions created internally in our software
here is an example: cus_M0JyYvtbsijuht
Right, I'm thinking about the Payment Methods and how you can get the mandate ID from the PM and use it when generating Payment Intents.
that's been my attempt the whole morning, trying to figure out if there were a possibility of fetching the mandate id from the PM (which seems possible in the UI were I can see it gets aggregated) but not using the API
or at least none that I could find
Correct, I'm not seeing a field where you can access this via the API.
For the payment method added in this request: https://dashboard.stripe.com/test/logs/req_qkhiOon43taJJY, I can see an attached mandate.
Even for the Payment Method on the failing request here: https://dashboard.stripe.com/test/logs/req_1M7rxoMKKPrUyL
yes, that was part of the testing, I tried using the mandate_id visually copied from the UI
but for thousands of customers, it's not feasible to go one by one in the UI and save the mandate_id into our system.
this could also represent a great disruption to some of our existing clients who expect us to reuse their customer's payment methods without any manual intervention, which is possible for credit/debit cards but for banks it seems we're hitting a wall
Yes that makes sense. This is why I'm somewhat confused by the behavior because we usually pass the mandate on our end.
I wish I could have access to something similar to this https://dashboard.stripe.com/v1/mandates?include_only[]=data.id%2Cdata.livemode%2Cdata.status%2Cdata.payment_method%2Cdata.payment_method_details.acss_debit.interval_description%2Cdata.payment_method_details.acss_debit.payment_schedule%2Cdata.payment_method_details.acss_debit.transaction_type&payment_method=pm_1P1tJvBnWDNfT9Wnk6fKRlFF&limit=10
copied from the network tab in the browser
Unfortunately I cannot view that link since it's unique to your dashboard
Would you say this is a fair summary of what we chat today:
- To attach payment methods to a customer we should switch to the checkout session and drop using the customer billing portal
- If a customer wants to change the payment method we can kick off the checkout session again in setup mode and rewrite the information
- If the payment method is a bank (or anything that requires a mandate id) we should save that information on our end for future reference (there is no way to get it back after it)
- For pre-existing payment methods that require a mandate id we cannot reuse them and should be re-entered by the client (big concern here)
I think that is a fair summary but I still want to check on some things
Can you test making a payment with this payment method? https://dashboard.stripe.com/test/logs/req_W1Xx9fGBm7e0uc
Do you mean creating a payment intent with that pm?
pi_3P2HLZBnWDNfT9Wn1X0SnEWf
Okay, so that was successful
but I know the mandate_id upfront which is not the case for pre-existing customers we have
if I try the way we're using it now for credit/debit cards without the mandate id it will fail
OH, I was asking you to test just passing the payment method via the API
{
"error": {
"message": "A mandate is required. Please either provide the id of an existing mandate on confirmation, or provide payment_method_options[acss_debit][mandate_options].",
"message_code": "acss_debit_provide_mandate_explicitly",
"request_log_url": "https://dashboard.stripe.com/test/logs/req_2Yqqh9O64ojf4F?t=1712341297",
"type": "invalid_request_error"
}
}
Sign in to the Stripe Dashboard to manage business payments and operations in your account. Manage payments and refunds, respond to disputes and more.
the payment_method_options parameter sounds appealing, but from what I understood, the information we should pass through is relevant when you have a checkout session or a user intervention, which is not the case for us
This is specific to ACSS I think, which has unique additional requirements for mandates. We discuss this here: https://docs.stripe.com/payments/acss-debit/accept-a-payment?platform=web&payment-ui=direct-api for both custom code options and Checkout
I think I was trying to reference this part of the payment intent
Ah, yes. That is specified in the Custom flow section of the ACSS guide
Given majority of our customers consented to be automatically debited I wonder if mandate_data.customer_acceptance.offline is a valid argument we can send, especially for customers that come as historical data
That definitely could be a valid approach! I wasn't sure how much coding you wanted to do on your end.
well, we have the Java implementation already in place for the PaymentIntent, so adding an extra parameter shouldn't be a problem. I was hesitant about the approach tho
Okay, in that case I think that approach would be ideal for your situation and alleviate that last pain point
So, if I understand correctly, by sending the mandate_data.customer_acceptance.offline value I'm "bypassing" the mandate_id requirement assuming that we have an offline agreement with the customer at hand, is that correct? I wonder if there is an easy way to test it
Correct
I'm testing this out quickly using the Stripe CLI and this command but I'm not getting success responses
tripe payment_intents create --amount "2000" --currency "cad" --customer "cus_ODQ2iNpfVPJCes" --confirm "true" -d "automatic-payment-methods[enabled]"="true" --return-url "http://example.com" --payment-method "pm_1P2FLUBnWDNfT9WnvA6cO8Ap" -d "mandate_data[customer_acceptance][type]"=offline -d "mandate_data[customer_acceptance][offline]"=true
Hello, thanks for jumping in. I think what we were trying to quickly prove is if it's possible to create a payment intent for a payment method that requires a mandate by sending the offline information in the mandate_data dictionary
{
"error": {
"message": "Invalid object",
"message_code": "invalid_hash",
"param": "mandate_data[customer_acceptance][offline]",
"request_log_url": "https://dashboard.stripe.com/test/logs/req_UaF5ySL6zKwVRP?t=1712343112",
"type": "invalid_request_error"
}
}
Sign in to the Stripe Dashboard to manage business payments and operations in your account. Manage payments and refunds, respond to disputes and more.
it should contain information about the offline acceptance but it requires no parameters...I'm a bit confused..
Oh I don't think you should be passing mandate_data actually
Scrolling up I see the error message you originally got was: A mandate is required. Please either provide the id of an existing mandate on confirmation, or provide payment_method_options[acss_debit][mandate_options].
oh, because this is specific for acss_debit I guess?
yeah
ok, but then still the question remains open to me regarding the best way to reuse payment methods attached to existing customers that were not setup using at platform and require a mandate_id to create a payment intent
is stripe open to consider an api implementation to support this?
best way to reuse payment methods attached to existing customers that were not setup using at platform
what do you mean by this
ok, sorry if I'm not explaining correctly. We have clients that connect their stripe accounts to our stripe. They come with customers that already have payment methods attached to them. Our clients expect that we can reuse those payment methods to keep charging their customers but instead of using stripe subscriptions we charge amounts based of invoices created in our system. When these customers have PMs that require a mandate id to be sent in order to create a payment intent there is no way we can use those right now. We haven't been able to find a way to fetch the mandate id associated to any of those PMs
Ah yeah there's not a endpoint to get a mandate from a payment method currently. You have to do something like this to charge a saved payment method with a mandate: https://docs.stripe.com/payments/acss-debit/set-up-payment?payment-ui=direct-api#charge-later
Yep, that could work for new subscriptions. For pre-existing ones tho, it's very hard to tell our clients that their customers have to reenter the payment information. I do see a few of our clients churning from our services if we deliver that message
Why would that not work for pre-existing?
Also you're saying subscription now
I thought you were charging via payment intents?
sorry for the confusion, by subscriptions I mean new customers subscribing to our platform and registering for automatic payments via stripe
Why would that not work for pre-existing?
if there is a customer with a payment method entered using which ever way we didn't control at that time. We cannot access programmatically to the mandate id associated to the existing payment method
The link I shared above shows you how to
You need to list setupintents by that customer
Or payment intents if it was collected via a payment intent
Then grab the mandate id from those objects
Unfortunately there's not a list mandates endpoint
Assuming payment method was collected via a setupintent, the mandate will be there: https://docs.stripe.com/api/setup_intents/object#setup_intent_object-mandate
Complete reference documentation for the Stripe API. Includes code snippets and examples for our Python, Java, PHP, Node.js, Go, Ruby, and .NET libraries.
If it was collected via a payment intent, instead it would be on the payment intent's charge object here: https://docs.stripe.com/api/charges/object#charge_object-payment_method_details-acss_debit-mandate
Complete reference documentation for the Stripe API. Includes code snippets and examples for our Python, Java, PHP, Node.js, Go, Ruby, and .NET libraries.
But the payment method in your sample request you shared earlier: pm_1P2FLUBnWDNfT9WnvA6cO8Ap was created via a setupintent
so, as long as they have been charged at least once with that payment method, we should have the mandate id whether on the PaymentIntent -> charge or the SetupIntent
yeah
if payment method was created via a setupintent, they wouldn't need to have a charge
you'd just grab mandate from the setupintent
setupintent isn't a charge
It's just a way to set up a payment method for future use
I see, that's the link I think I've been looking for. Thanks a lot for the patience and all the clarifications.
No problem!
It's a common piece of feedback we get that we need to add a list mandates endpoint
Unfortunately I have no idea when it will be implemented
I guess there is a good reason why is so low in priority, but at least this chat saved me a lot of headaches. I've been trying to find the correlation for a few hours already
Glad we could help
well, that's all on my end for now. Thanks again for the help and have a great rest of the day!