#tudor-subs-testing
1 messages · Page 1 of 1 (latest)
Hello! We'll be with you shortly. Below are links to other discussions we've had with you in the past week in case you want to review that information. If your question is related to one of these previous discussions, please provide a comprehensive summary of the current state and what you need help with now. We help many users simultaneously, so a summary allows us to resolve your issue as soon as possible.
- tudor_ang, 5 hours ago, 69 messages
Hello
i have some problems
i want to do subscriptions with stripe for my mern app
i try to build a saas platform where users can have premium account (i keep on my mongodb per user isPremium boolean)
and for subscription paymenth i have this webhook logic
case 'invoice.payment_succeeded':
if (dataObject['billing_reason'] == 'subscription_create') {
// The subscription automatically activates after successful payment
// Set the payment method used to pay the first invoice
// as the default payment method for that subscription
const subscription_id = dataObject['subscription']
const payment_intent_id = dataObject['payment_intent']
// Retrieve the payment intent used to pay the subscription
const payment_intent = await stripe.paymentIntents.retrieve(payment_intent_id);
try {
const subscription = await stripe.subscriptions.update(
subscription_id,
{
default_payment_method: payment_intent.payment_method,
},
);
console.log("Default payment method set for subscription:" + payment_intent.payment_method);
const dbUser = await User.findOne({ email: dataObject.customer_email })
dbUser.isPremium = true;
dbUser.subscriptionId = subscription.id;
await dbUser.save();
} catch (err) {
console.log(err);
console.log(`⚠️ Falied to update the default payment method for subscription: ${subscription_id}`);
}
};
break;```
are you there?
i really need your help to check my flow
Yup I'm here - I'm just waiting for you to give all the context
ok so
with the code from above the subscription will automatically renew for the user?
(i create the customer on user registration)
The Subscription will automatically renew/cycle even without the code you have above - the code you have is specifically for making sure that the Subscription can automatically attempt payment on each renewal
ok and lets say it renew and the user dont have money on the card anymore
how i can check this to remove the premium from my db
?
i read the docs but is not clear to me
You'd listen for the invoice.payment_failed to know that they weren't able to pay for the renewal invoice
i have this in my code
case 'invoice.payment_failed':
// TODO: handle case where subscription renew fails
// If the payment fails or the customer does not have a valid payment method,
// an invoice.payment_failed event is sent, the subscription becomes past_due.
// Use this webhook to notify your user that their payment has
// failed and to retrieve new card details.
break;
but
how i can see what arrives here
to test my logic?
using testclocks?
Yeah test clocks would be one way to test this
The other way would be to create a Subscription with a short (few second) trial_end or billing_cycle_anchor so that the renewal Invoice happens quickly
and how i can know what will happen? how i can make it fail or succeed?
You'd just want for a few minutes until the Subscription is automatically transitioned
Do you have specifics on why test clocks didn't work for you? It's more precise to use test clocks and if you're going to be doing a lot of tests it may be worth getting it up and running to save you time down the line
2 seconds to test again
tudor-subs-testing
i found other problem in my code that was not there some time ago
when i simulate a subscription from ui
from my app ui
my backend crash with this error
/Users/tudorang/Desktop/DevReadyFrontend-Backend/node_modules/stripe/cjs/StripeResource.js:99
throw new Error(Stripe: Argument "${param}" must be a string, but got: ${arg} (on API request to \${requestMethod} ${path}`)`);
^
Error: Stripe: Argument "intent" must be a string, but got: null (on API request to GET /v1/payment_intents/{intent})
at /Users/tudorang/Desktop/DevReadyFrontend-Backend/node_modules/stripe/cjs/StripeResource.js:99:23
at Array.reduce (<anonymous>)
at Constructor._getRequestOpts (/Users/tudorang/Desktop/DevReadyFrontend-Backend/node_modules/stripe/cjs/StripeResource.js:96:35)
at /Users/tudorang/Desktop/DevReadyFrontend-Backend/node_modules/stripe/cjs/StripeResource.js:143:29
at new Promise (<anonymous>)
at Constructor._makeRequest (/Users/tudorang/Desktop/DevReadyFrontend-Backend/node_modules/stripe/cjs/StripeResource.js:139:16)
at Constructor.retrieve (/Users/tudorang/Desktop/DevReadyFrontend-Backend/node_modules/stripe/cjs/StripeMethod.js:31:83)
at /Users/tudorang/Desktop/DevReadyFrontend-Backend/index.js:83:62
at Layer.handle [as handle_request] (/Users/tudorang/Desktop/DevReadyFrontend-Backend/node_modules/express/lib/router/layer.js:95:5)
at next (/Users/tudorang/Desktop/DevReadyFrontend-Backend/node_modules/express/lib/router/route.js:144:13)
Node.js v18.17.1
[nodemon] app crashed - waiting for file changes before starting...
the subscription in stripe dashboard is active but in my db ispremium is false because the backend crash
and now i send again and it worked
Ah, if you were testing with a trial then the first invoice of the subscription won't have a payment_intent ID so you need to account for that
what?
and how i can make this work
i dont want to have a free trial on the subscription
Not all paid Invoices have a payment_intent (because they may not need any payment because it's a trial or the amount owed is too low)
and how i can make it not crash
All you'd need to is add an if statement to only retrieve the PaymentIntent and set default_payment_method if the Invoice has a PaymentIntent
And stepping back a bit -you could remove the code that sets default_payment_method in your webhook entirely if you create the Subscription with payment_settings.save_default_payment_method: on_subscription instead (see https://stripe.com/docs/api/subscriptions/create#create_subscription-payment_settings-save_default_payment_method)
The Error: Stripe: Argument "intent" must be a string, but got: null error?
Yeah, the issue is that you're passing nothing there instead of an Intent ID.
Why what? Why is causing the error? Why are you passing nothing? Something else?
The more specific your questions the more helpful I can be. 🙂
What specifically don't you understand?
and first time sends this error
if i send the second time works
can you help me?
please
i also dont understand what karbi said here
"All you'd need to is add an if statement to only retrieve the PaymentIntent and set default_payment_method if the Invoice has a PaymentIntent
And stepping back a bit -you could remove the code that sets default_payment_method in your webhook entirely if you create the Subscription with payment_settings.save_default_payment_method: on_subscription instead (see "
The key thing to understand is that Subscriptions won't always have a Payment Intent. Your code is currently assuming they will always have a Payment Intent.
yeah i understand this
but i dont understand what is the intent
for what is this used
?
The Payment Intent is used for the actual payment. Have a look at this short video: https://stripe.com/docs/payments/tour#payment-objects
and if i dont have this how subscription should work?
If the Subscription doesn't need an immediate payment (like if there's a trial) there's no need for it to create a Payment Intent, so it doesn't.
Is that the case? Are you creating the Subscription with a trial?
i dont want to have any free trial
Okay, does the Subscription not require a payment initially?
needs
i want when the user subscribe to to pay the first month
and then renew each month
thats my workflow that i want
Okay, what line of code is throwing that error?
Default payment method set for subscription:pm_1OUvEVFi8oKxdd7KxuuLrxUf
/Users/tudorang/Desktop/DevReadyFrontend-Backend/node_modules/stripe/cjs/StripeResource.js:99
throw new Error(Stripe: Argument "${param}" must be a string, but got: ${arg} (on API request to \${requestMethod} ${path}`)`);
^
Error: Stripe: Argument "intent" must be a string, but got: null (on API request to GET /v1/payment_intents/{intent})
at /Users/tudorang/Desktop/DevReadyFrontend-Backend/node_modules/stripe/cjs/StripeResource.js:99:23
at Array.reduce (<anonymous>)
at Constructor._getRequestOpts (/Users/tudorang/Desktop/DevReadyFrontend-Backend/node_modules/stripe/cjs/StripeResource.js:96:35)
at /Users/tudorang/Desktop/DevReadyFrontend-Backend/node_modules/stripe/cjs/StripeResource.js:143:29
at new Promise (<anonymous>)
at Constructor._makeRequest (/Users/tudorang/Desktop/DevReadyFrontend-Backend/node_modules/stripe/cjs/StripeResource.js:139:16)
at Constructor.retrieve (/Users/tudorang/Desktop/DevReadyFrontend-Backend/node_modules/stripe/cjs/StripeMethod.js:31:83)
at /Users/tudorang/Desktop/DevReadyFrontend-Backend/index.js:83:62
at Layer.handle [as handle_request] (/Users/tudorang/Desktop/DevReadyFrontend-Backend/node_modules/express/lib/router/layer.js:95:5)
at next (/Users/tudorang/Desktop/DevReadyFrontend-Backend/node_modules/express/lib/router/route.js:144:13)
Node.js v18.17.1
thats the error
and here is my logic for the subscription
case 'invoice.payment_succeeded':
if (dataObject['billing_reason'] == 'subscription_create') {
// The subscription automatically activates after successful payment
// Set the payment method used to pay the first invoice
// as the default payment method for that subscription
const subscription_id = dataObject['subscription']
const payment_intent_id = dataObject['payment_intent']
// Retrieve the payment intent used to pay the subscription
const payment_intent = await stripe.paymentIntents.retrieve(payment_intent_id);
try {
const subscription = await stripe.subscriptions.update(
subscription_id,
{
default_payment_method: payment_intent.payment_method,
},
);
console.log("Default payment method set for subscription:" + payment_intent.payment_method);
const dbUser = await User.findOne({ email: dataObject.customer_email })
dbUser.isPremium = true;
dbUser.subscriptionId = subscription.id;
await dbUser.save();
} catch (err) {
console.log(err);
console.log(`⚠️ Falied to update the default payment method for subscription: ${subscription_id}`);
}
};
Which specific line though?
i am not sure about that
i dont have any StripeResource in my project
I don't think that's the right code.
what?
I don't think that error is coming from that code. Can you check to see where you're setting intent?
thats my full stripe logic
app.post(
'/webhooks',
bodyParser.raw({ type: 'application/json' }),
async (req, res) => {
// Retrieve the event by verifying the signature using the raw body and secret.
let event;
try {
event = stripe.webhooks.constructEvent(
req.body,
req.header('Stripe-Signature'),
endpointSecret
);
} catch (err) {
console.log(err);
console.log(`⚠️ Webhook signature verification failed.`);
console.log(
`⚠️ Check the env file and enter the correct webhook secret.`
);
return res.sendStatus(400);
}
// Extract the object from the event.
const dataObject = event.data.object;
// Handle the event
// Review important events for Billing webhooks
// https://stripe.com/docs/billing/webhooks
// Remove comment to see the various objects sent for this sample
switch (event.type) {
case 'invoice.payment_succeeded':
if (dataObject['billing_reason'] == 'subscription_create') {
// The subscription automatically activates after successful payment
// Set the payment method used to pay the first invoice
// as the default payment method for that subscription
const subscription_id = dataObject['subscription']
const payment_intent_id = dataObject['payment_intent']
// Retrieve the payment intent used to pay the subscription
const payment_intent = await stripe.paymentIntents.retrieve(payment_intent_id);
try {
const subscription = await stripe.subscriptions.update(
subscription_id,
{
default_payment_method: payment_intent.payment_method,
},
);
console.log("Default payment method set for subscription:" + payment_intent.payment_method);
const dbUser = await User.findOne({ email: dataObject.customer_email })
dbUser.isPremium = true;
dbUser.subscriptionId = subscription.id;
await dbUser.save();
} catch (err) {
console.log(err);
console.log(`⚠️ Falied to update the default payment method for subscription: ${subscription_id}`);
}
};
break;
case 'invoice.payment_failed':
// TODO: handle case where subscription renew fails
// If the payment fails or the customer does not have a valid payment method,
// an invoice.payment_failed event is sent, the subscription becomes past_due.
// Use this webhook to notify your user that their payment has
// failed and to retrieve new card details.
break;
case 'invoice.finalized':
// If you want to manually send out invoices to your customers
// or store them locally to reference to avoid hitting Stripe rate limits.
break;
case 'customer.subscription.deleted':
if (event.request != null) {
// handle a subscription cancelled by your request
// from above.
} else {
// handle subscription cancelled automatically based
// upon your subscription settings.
}
break;
case 'customer.subscription.trial_will_end':
// Send notification to your user that the trial will end
break;
default:
// Unexpected event type
}
res.sendStatus(200);
}
);
thats all i have
and on user registration i have this
// generate stripe customer id
const newStripeCustomer = await stripe.customers.create({
email: email,
});
stripeCustomer = newStripeCustomer.id
to keep stripecustomerid in my mongodb
Ah, it must be this line then:
const payment_intent = await stripe.paymentIntents.retrieve(payment_intent_id);
yeha \
You're not checking to see if payment_intent_id is empty or not.
and how i can do this?
if i put an if
this will not brake my logic?
and if not exist what should i put?
You need to adjust your logic to account for there not being a Payment Intent ID at that point.
If there's not a Payment Intent ID at that point you need to decide what your code should do about it.
can you give me some tips on how i can do it?
i want to user to pay at the start the first month and then automatically renew each month
Are you following the guide here? https://stripe.com/docs/billing/subscriptions/build-subscriptions
You should give it a try and see.
I can't run your code for you, or explain how it will behave.
Yes, unless there's a default set elsewhere.
is not
hmm
and how i can do it
i dont understand
if i dont have the intent but i need it to automatically renew
how i can do it
?
You need to figure out why you don't have the Intent.
i removed it
and like this is looking my customer
on stripe
this will automatically renew?
i think yes
right?
because the card is there
There is a payment method saved there, so maybe. I recommend you use Test Clocks to speed up time in test mode and make sure what you want to happen happens: https://stripe.com/docs/billing/testing/test-clocks
can you help me set up some test clocks please?
i am not able to make them work
with the docs
sorry for my big thread of problems
What help do you need? Do you have a specific question?
Like what specific thing is preventing you from using them?
i dont know how to run a testclock for this customer
You don't. Test Clocks aren't for use with existing Customers. You create the Test Clock, then you create a new Customer for that Test Clock.
yeah but in my terminal
2024-01-04 20:49:31 --> test_helpers.test_clock.advancing [evt_1OUvyxFi8oKxdd7KLnQ1oxz5]
2024-01-04 20:49:31 <-- [200] POST http://localhost:3001/webhooks [evt_1OUvyxFi8oKxdd7KLnQ1oxz5]
2024-01-04 20:49:32 --> test_helpers.test_clock.ready [evt_1OUvyyFi8oKxdd7KdNbRtYxu]
2024-01-04 20:49:32 <-- [200] POST http://localhost:3001/webhooks [evt_1OUvyyFi8oKxdd7KdNbRtYxu]
w
i made the testclock
but the webhook with invoice.payment_succeeded was not triggered again
on stripe the invoice was paid
but this was not reach to my backend
so how ik if i have to remove user premium in my db or not
According to those logs your local code did get them and returned a 200 (success) status back.
That's what the <-- [200] POST http://localhost:3001/webhooks lines mean.
invoice.payment_succeeded was not triggered
Yes, tha'ts not one of the events listed above.
You should have received test_helpers.test_clock.advancing and test_helpers.test_clock.ready.
Probably because you didn't advance time far enough?
i did
hmm
now was triggered
i dont understand
why sometimes is sometimes not
After you created the Test Clock you added a new Customer for it and set them up with a Subscription, then advanced time?
yeah
It does looks like things are working, the Events are being generated.
but if is working like this what was the thing with that intent id
can you expalin please?
I don't understand your question. Can you provide more details?
Payment Intents are used for accepting payments.
I don't understand... are you asking me why your code used them?
You need to be specific. Can you give me the ID of a Subscription where it worked?
Or the ID of an Invoice?
now is working
and i no longer have that intent code
default_payment_method: payment_intent.payment_method,
this
i no longer have
and is working
how
?
I don't know. Give me the ID for a Subscription or Invoice so I can look and see.
Do you have an ID for one I can take a look at?
no
Why?
let me find one
I'd be happy to tell you how it's working, but I need to be able to see it.
where can i find it?
In your logs, in the Events, in your Dashboard.
Like when you got the invoice.* Events there should be an in_ ID in there.
I don't know, please give me the ID so I can look.
I need the Subscription or Invoice ID.
sub_ or in_
It should be right there in the Dashboard.
in_1OUwJgFi8oKxdd7KtLQnSuAn
Looking...
The Customer had an existing balance that was used to pay the Invoice.
where was this balance?
Looking...
Oh... I think the amount was below our minimum charge amount, so we applied the -1 to the balance to charge later.
Yeah, that's what it was.
You need to increase the amount so it's above the minimum charge amount.
See here for details: https://stripe.com/docs/currencies#minimum-and-maximum-charge-amounts
Yeah, but that's below our minimum charge amount, so an Invoice with a total of 1 ron isn't going to create a payment.
When you go and do the second Invoice for the same amount, the 1 fromt he Invoice and the 1 from the customer balance are combined to 2 and that does meet the minimum so that one works.
That's why you were seeing some go through and some not.
You should try 25 in test mode to see if it works as expected.
It should, but you should always test.
i have one more problem on the same customer
i run the clock
and the defautl card
should expire on apr 2024
and now i am in may and still succedd the paymenth
Expiration dates are ignored. They often get updated transparently or still work after being expried.
and how i can test a fail case?
You can attach the test card ending in 0341 to the Customer: https://stripe.com/docs/testing#declined-payments
Attaching this card to a Customer object succeeds, but attempts to charge the customer fail.
when i try to attach it i get Your card has insufficient funds.
on stripe dashboard
You're trying to attach 4000000000000341?
yeah i tried with yours and the paymenth fails
thank you
i think the integration looks good
this is my webhooks
try {
event = stripe.webhooks.constructEvent(
req.body,
req.header('Stripe-Signature'),
endpointSecret
);
} catch (err) {
console.log(err);
console.log(⚠️ Webhook signature verification failed.);
console.log(
⚠️ Check the env file and enter the correct webhook secret.
);
return res.sendStatus(400);
}
// Extract the object from the event.
const dataObject = event.data.object;
// Handle the event
// Review important events for Billing webhooks
// https://stripe.com/docs/billing/webhooks
// Remove comment to see the various objects sent for this sample
switch (event.type) {
case 'invoice.payment_succeeded':
if (dataObject['billing_reason'] == 'subscription_create') {
// The subscription automatically activates after successful payment
// Set the payment method used to pay the first invoice
// as the default payment method for that subscription
const subscription_id = dataObject['subscription']
// const payment_intent_id = dataObject['payment_intent']
// Retrieve the payment intent used to pay the subscription
// const payment_intent = await stripe.paymentIntents.retrieve(payment_intent_id);
try {
const subscription = await stripe.subscriptions.update(
subscription_id,
// {
// default_payment_method: payment_intent.payment_method,
// },
);
// console.log("Default payment method set for subscription:" + payment_intent.payment_method);
const dbUser = await User.findOne({ email: dataObject.customer_email })
dbUser.isPremium = true;
dbUser.subscriptionId = subscription.id;
await dbUser.save();
} catch (err) {
console.log(err);
console.log(`⚠️ Falied to update the default payment method for subscription: ${subscription_id}`);
}
};
break;
case 'invoice.payment_failed':
// TODO: handle case where subscription renew fails
const dbUser = await User.findOne({ email: dataObject.customer_email })
dbUser.isPremium = false;
await dbUser.save();
break;
case 'invoice.finalized':
// If you want to manually send out invoices to your customers
// or store them locally to reference to avoid hitting Stripe rate limits.
break;
case 'customer.subscription.deleted':
if (event.request != null) {
// handle a subscription cancelled by your request
// from above.
} else {
// handle subscription cancelled automatically based
// upon your subscription settings.
}
break;
case 'customer.subscription.trial_will_end':
// Send notification to your user that the trial will end
break;
default:
// Unexpected event type
}
res.sendStatus(200);
}
you see smth that i dont cover?
We can't provide code reviews here, sorry.
Happy to answer specific questions and get you unblocked, but testing and reviewing your code is up to you.
i dont think thats a code review
what edge cases i have to cover for this subscription app model?
It depends on the specifics of your integration, your business needs, your subscriptions, etc. We have documentation that provides guidance here: https://stripe.com/docs/billing/subscriptions/overview
From that earlier example you added a card to that Customer via the Dashboard, and that card was used to pay for the Subscription.
yeah but if i add a card from the checkout page
from this one
fetch('https://devready-backend.onrender.com/create_checkout_link', {
// fetch('https://dev-ready-frontend-backend.vercel.app/create_checkout_link', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
})
.then((response) => response.json())
.then((data) => {
window.location.replace(data.url);
});
}
still works
Okay.
oh if i create fro mthe checkout page is not marked as default
Okay.
What's the ID of that Customer?
cus_PJZsmfXpUOf3Ff
if is not default i dont think the subscription will renew from it
right?
You need to set setup_future_usage when you create the Checkout Session: https://stripe.com/docs/api/checkout/sessions/create#create_checkout_session-payment_intent_data-setup_future_usage
i am not sure how i can do this
i dont understand this docs
where i set setup_future_usage in this checkout
You need to change your Node code. It's the code that created the Checkout Session in this request: https://dashboard.stripe.com/test/logs/req_jEwLwOLaIs1qHp
You need to set payment_intent_data.setup_future_usage in that request.
in the headers of the req?
hello hanzo
No, it's in the body of the request.
You set it alongside things like success_url and customer.
so in the data object
let data = {
priceId: priceId,
// customerId: props.customerId,
email: mail, // TODO: send email directly from auth
}
fetch('https://devready-backend.onrender.com/create_checkout_link', {
// fetch('https://dev-ready-frontend-backend.vercel.app/create_checkout_link', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
is not clear to me what i have to set
I don't think so? That doesn't seem to be the correct code.
This would be in your server-side code.
Where you create the Checkout Session.
oh yeah here
app.post('/create_checkout_link', async (request, response) => {
const priceId = request.body.priceId;
// Retrieve user's stripeCustomerId based on the provided email
const user = await User.findOne({ email: request.body.email });
if (!user) {
return response.status(400).json({ error: "User not found." });
}
console.log(user)
const session = await stripe.checkout.sessions.create({
billing_address_collection: 'auto',
// email: request.body.email, // TODO: add validation to my middleware email have the same mail from this body else redirect in a err page
customer: user.stripeCustomerId,
line_items: [
{
price: priceId,
quantity: 1,
},
],
mode: 'subscription',
success_url: http://localhost:3000/?success=true,
cancel_url: http://localhost:3000?canceled=true,
});
response.send({
url: session.url
});
});
sorry i am tired
Yeah, that's it.
See how you set line_items there, with the nested stuff? See how that's described in the API reference here? https://stripe.com/docs/api/checkout/sessions/create#create_checkout_session-line_items
yeah
Now you need to set this specific property: https://stripe.com/docs/api/checkout/sessions/create#create_checkout_session-payment_intent_data-setup_future_usage
i dont know whats that property
So use that info in the API reference to add that to your code.
If you had to guess, what do you think the code would look like if you tried to add that property?
I linked you directly to it. It's payment_intent_data.setup_future_usage.
So it's a top-level payment_intent_data property that contains an object, and that object has a setup_future_usage property which has a value that's a string.
If you take the time to learn how to translate your code to and from the API reference things are going to be a lot easier for you.
I have to run, but hanzo can help you further!
payment_intent_data: [
],
idk what to set there
@marble nova
hello
i want the card from checkout to be set as default paymenth
and i am not able to wfind out how
Hello 👋
give me a moment to catch up
So there's no way to set the payment method to be default directly from a checkout session.
You can configure checkout session to set up and attach the payment method to a customer by setting payment_intent_data.setup_future_usage parameter
Once attached, you'd need to update the customer object by calling the Update Customer API separately
can you help me to do this please
?
how i can set payment_intent_data.setup_future_usage
this is not clear to me
I can't write your code for you unfortunately.
What part are you not clear about? I'm happy to provide more context and help clarify but you'd need to write the code yourself.
See this doc
https://stripe.com/docs/payments/save-during-payment?platform=web#create-the-paymentintent
It has an example of how you'd pass setup_future_usage to a PaymentIntent, you'd need to do the same but with payment_intent_data on Checkout Session object
whats that payment intent for
i have const session = await stripe.checkout.sessions.create({
PaymentIntent is a separate API, I don't want you to focus on that API but how it's setting setup_future_usage
const session = await stripe.checkout.sessions.create({
billing_address_collection: 'auto',
// email: request.body.email, // TODO: add validation to my middleware email have the same mail from this body else redirect in a err page
customer: user.stripeCustomerId,
setup_future_usage: 'off_session',
line_items: [
{
price: priceId,
quantity: 1,
},
],
mode: 'subscription',
success_url: http://localhost:3000/?success=true,
cancel_url: http://localhost:3000?canceled=true,
});
this is what i have
to what to set this setup_future_usage?
setup_future_usage needs to be set as a child property of payment_intent_data
https://stripe.com/docs/api/checkout/sessions/create#create_checkout_session-payment_intent_data-setup_future_usage
what do you mean as child
what this should be in a programming languge
lol
?
i dont understand
can you please say how i send this
My colleague and I have both tried to explain how you'd be able to add setup_future_usage parameter multiple times, we're just short of writing your code for you (which we won't do).
yeah
but i dont understand
so i have to set this inside const session = await stripe.checkout.sessions.create({
right?
so i have to set this inside const session = await stripe.checkout.sessions.create({
This meaning what exactly?
where i have to set this
here?
const session = await stripe.checkout.sessions.create({
billing_address_collection: 'auto',
// email: request.body.email, // TODO: add validation to my middleware email have the same mail from this body else redirect in a err page
customer: user.stripeCustomerId,
line_items: [
{
price: priceId,
quantity: 1,
},
],
mode: 'subscription',
success_url: http://localhost:3000/?success=true,
cancel_url: http://localhost:3000?canceled=true,
});
response.send({
url: session.url
});
});
ok so i added this
line_items: [
{
price: priceId,
quantity: 1,
},
],
payment_intent_data: [
]
and what exactly i have to add to it?
to set the card as default
for the customer
can you respond please
Please be patient, there are multiple people I am helping.
i have this and is not working
customer: user.stripeCustomerId,
line_items: [
{
price: priceId,
quantity: 1,
},
],
payment_intent_data: {
setup_future_usage: "off_session"
},
the card is not set as default
So there's no way to set the payment method to be default directly from a checkout session.
You can configure checkout session to set up and attach the payment method to a customer by setting payment_intent_data.setup_future_usage parameter
Once attached, you'd need to update the customer object by calling the Update Customer API separately
That parameter attaches the payment method to a customer
You need a separate api request to make it default
and when this should be called
if the card is not default
the subscription will renew from it?
if is just added
?
The customer update API is here
https://stripe.com/docs/api/customers/update
https://stripe.com/docs/api/customers/update#update_customer-invoice_settings-default_payment_method
Taking a step back, is your concern how a subscription created using checkout session will renew?
yeah
when i subscrbe from checkout the card is added but is not set as default
my question is
when the subscription for that user will renew
next month
will charge the card
even if is not default?
I believe the payment method is set as default on the subscription when created via checkout session, so yeah renewal payment should go through fine.
You're looking at the customer details page
open the subscription page
to see what
i want to see
when the subscription
on the customer
renew
if
he
is
chared
on the credit card
even if is not default
thats all
i want to see
that's all subscriptions, you need to look at the subscription that you created for that specific customer
yes, look at the payment method there
and billing method
it says "charge specific payment method" followed by the actual payment method used in checkout
meaning it isn't looking for customer's default payment method to charge
thats the current billing
here is the upcoming
and guess what
will charge the default card
that is not set
wow
Can you share the subscription ID you're looking at?
sub_xxx
Sign in to the Stripe Dashboard to manage business payments and operations in your account. Manage payments and refunds, respond to disputes and more.
you can take it from the url please
because is upcomming_invoice
I believe the dashboard upcoming invoice view is showing the wrong info there.
I checked the subscription and it has the payment method set correctly
yeah
but
the next
invoice
in 1 month
when this user will be charged
this will not work
look at the webhook event here
https://dashboard.stripe.com/test/events/evt_1OUwj3Fi8oKxdd7KLrtb3vNs
It shows the subscription has a default payment method
because he has no default card
Well technically, the upcoming invoice details page says "charging default payment method"
It doesn't say anything about default payment method on subscription or customer
and I double checked that the subscription HAS a default payment method
how i can test if this works
if i do a testclock the card will be set as default
so?
When you create subscription using a checkout session, the payment method is set as default on the Subscription meaning that payment method will be used for renewal automatically.
Testing a checkout session based flow with a test clock would be challenging as you can't create a checkout session linked to a test clock.
You'll need to create a test clock customer, a test clock subscription separately while setting a default payment method on the subscription