#sahilasopa
1 messages · Page 1 of 1 (latest)
đź‘‹ happy to help
each time you create a subscription if you don't specify a specific payment behavior we will default to try to pay that subscription immediately meaning that you either need to specify the payment method or your customer has to have a pm attached and setup as a invoice_settings.default_payment_method
Complete reference documentation for the Stripe API. Includes code snippets and examples for our Python, Java, PHP, Node.js, Go, Ruby, and .NET libraries.
when you specify default_incomplete you will get the chance to collect the payment method before we try to pay the first invoice
const subscription = await stripe.subscriptions.create({
currency: 'inr',
customer: customerId,
items: [
{price: planId},
],
payment_behavior: "allow_incomplete",
payment_settings: { save_default_payment_method: 'on_subscription' },
expand: ['latest_invoice.payment_intent']
});
this is what I tried
what is the difference between default_incomplete and allow_incomplete
from the link I sent you
Use allow_incomplete to create subscriptions with status=incomplete if the first invoice cannot be paid. Creating subscriptions with this status allows you to manage scenarios where additional user actions are needed to pay a subscription’s invoice. For example, SCA regulation may require 3DS authentication to complete payment. See the SCA Migration Guide for Billing to learn more. This is the default behavior.
Use default_incomplete to create Subscriptions with status=incomplete when the first invoice requires payment, otherwise start as active. Subscriptions transition to status=active when successfully confirming the payment intent on the first invoice. This allows simpler management of scenarios where additional user actions are needed to pay a subscription’s invoice. Such as failed payments, SCA regulation, or collecting a mandate for a bank debit payment method. If the payment intent is not confirmed within 23 hours subscriptions transition to status=incomplete_expired, which is a terminal state.
in your case you need default_incomplete to collect the payment method
How can I get such a flow
- user creates an account on my website by giving their username and password
- I create a stripe customer and get the customer id
- then I use that customer Id to start PaymentSheet, and if the payment is successful the subscription is created
I already have done first 2 steps
you should create the subscription first
as you're doing now and expanding the latest_invoice.payment_intent
and passing the client_secret to the PaymentSheet
then you pay
but you should use default_incomplete to allow the creation of the subscription without any attached PM
I have just changed allow_incomplete to default_incomplete I am yet to run the code, I am doing it rn, this should prevent the error mentioned above ?
yes
and will let you collect the PM and save it on the subscription ( since you're using payment_settings: { save_default_payment_method: 'on_subscription' }) and pay the first invoice all at once
I get a new error this time
Passing apiVersion in a separate options hash is required to create an ephemeral key
const customerId = "cus_NE9pq2xHjSmOnw";
const planId = "price_1I2blSCZB9UZu9OeyCPrLl5P";
const subscription = await stripe.subscriptions.create({
currency: 'inr',
customer: customerId,
items: [
{price: planId},
],
payment_behavior: "default_incomplete",
payment_settings: { save_default_payment_method: 'on_subscription' },
expand: ['latest_invoice.payment_intent']
});
const ephemeralKey = await stripe.ephemeralKeys.create(
{customer: customerId},
)
return {
ephemeralKey: ephemeralKey.secret,
subscriptionId: subscription.id,
paymentIntent: subscription.latest_invoice.payment_intent.client_secret,
publishableKey: 'the key here'
}
this is my whole code for the backend
why do you need the ephemeral key here?
would you mind sharing the request id that has the error? https://support.stripe.com/questions/finding-the-id-for-an-api-request
Find help and support for Stripe. Our support center provides answers on all types of situations, including account information, charges and refunds, and subscriptions information. Get your questions answered and find international support for Stripe.
it is needed by PaymentSheet in the backend I suppose
customerConfig = new PaymentSheet.CustomerConfiguration(
user.getStripeId(),
result.getString("ephemeralKey")
);
final PaymentSheet.Configuration configuration = new PaymentSheet.Configuration.Builder("Bhaktidwar Media Pvt Ltd.")
.customer(customerConfig)
.allowsDelayedPaymentMethods(true)
.build();
gimme a min
weird it says the subscription was created
req_diO0MCSkdUkeN7
so do I just remove the customerConfig?
customerConfig = new PaymentSheet.CustomerConfiguration(
user.getStripeId(),
result.getString("ephemeralKey")
);
paymentIntentClientSecret = result.getString("paymentIntent");
PaymentConfiguration.init(getApplicationContext(), result.getString("publishableKey"));
runOnUiThread(this::showStripePaymentSheet);
void showStripePaymentSheet() {
final PaymentSheet.Configuration configuration = new PaymentSheet.Configuration.Builder("")
.customer(customerConfig)
.allowsDelayedPaymentMethods(true)
.build();
paymentSheet.presentWithPaymentIntent(
paymentIntentClientSecret,
configuration
);
}
this is what I am doing
you don't need all of this, please read through the doc I sent you
yes correct, now the subscription has been created successfully
so you just need to follow the steps in that doc to pay the first invoice using the PaymentSheet
Yes I went through the documentation and my code seems to be working, I just would like to know if I did it the correct way
this is my frontend
paymentIntentClientSecret = result.getString("paymentIntent");
PaymentConfiguration.init(getApplicationContext(), result.getString("publishableKey"));
runOnUiThread(this::showStripePaymentSheet);
void showStripePaymentSheet() {
final PaymentSheet.Configuration configuration = new PaymentSheet.Configuration.Builder("Name")
.allowsDelayedPaymentMethods(true)
.build();
paymentSheet.presentWithPaymentIntent(
paymentIntentClientSecret,
configuration
);
}
this is my backend
const customerId = "cus_NE9pq2xHjSmOnw";
const planId = "price_1I2blSCZB9UZu9OeyCPrLl5P";
const subscription = await stripe.subscriptions.create({
currency: 'inr',
customer: customerId,
items: [
{price: planId},
],
payment_behavior: "default_incomplete",
payment_settings: { save_default_payment_method: 'on_subscription' },
expand: ['latest_invoice.payment_intent']
});
return {
subscriptionId: subscription.id,
paymentIntent: subscription.latest_invoice.payment_intent.client_secret,
publishableKey: 'key'
}
what is the error you're getting?
I am not getting any error, I would just like to know if I did it using the correct/efficient way
I don't see anything "problematic" you should try to test the full scenario and see if you get any errors
alright, I just found one problem, the stripe payment element buffers for long time before loading
Hey! Taking over for my colleague. Let me catch up.
sure, thank you
the stripe payment element buffers for long time before loading
Could. you please give more details about this ? like how much ?
Did you checked if there is something blocking the UI rendering in your side (e.g. API call) ?
for the first time it takes around 10 secs, and after that it takes around 3 secs
nope nothing blocks it
the payment intent opens after the call is made
and it takes 10 secs after the call is made
Try to profile your app performance and see for that page what's blocking the UI rendering
Also, try running this sample project and see if on the same device you are noticing the same issue:
https://github.com/stripe/stripe-android/tree/master/example
As you can see, for the first time it took more then 10 secs, but for the second time it was almost instant
profiling shows nothing's blocking
And this one ?
try running paymentsheet-example and see if you notice the same behavior on that device please
alright gimme a min
Yes!
I am unable to download the repo
git clone gives errror
and zip file
also I had another question, documentation suggests using
Fuel.INSTANCE.post(url) for making calls
but I am using
FirebaseFunctions.getInstance().getHttpsCallable(url)
does this make a huge difference
It looks like you OS (windows) blocking the clone due to file path too link I think, you need to fix this on your laptop, sorry don't knw a lot about windows
I would say to follow the documentation
alright, thank you for your help, thanks to tarzan as well
You're welcome!