#hugo_best-practices
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/1341399414794878997
๐ Have more to share? Add more details, code, screenshots, videos, etc. below.
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.
- hugo_checkout-customer, 4 days ago, 40 messages
- hugo_docs, 4 days ago, 6 messages
- hugo_docs, 5 days ago, 11 messages
Then, for some reasons, he pays the failed invoice from the 1st payment attempt with his valid CC.
This will activate the firstly created subscription. Leading to having two active subscriptions for this customer.
What is the recommended thing to do to prevent this ?
I know after 1 day, the "incomplete" marked subscription goes into "incomplete_expired", but sometimes, the customer try again in the same day, without staying in the same checkout UI, leading to this.
๐
In your website, you need to add an extra check: before creating a new Checkout Session, see if the customer has already a Subscription or not that could be still used/paid ?
And if so, I pass it in the checkout session creation step ?
const options: StripeType.Checkout.SessionCreateParams = {
customer: stripeCustomerId,
mode: "subscription",
line_items: [{ price: priceId, quantity: 1 }],
success_url: successUrl,
cancel_url: cancelUrl,
metadata: {
userId,
priceId,
},
subscription_data: {
metadata: {
userId,
},
},
};
if (referalId) options.client_reference_id = referalId; // Rewardfull
const session = await stripe.checkout.sessions.create(options);
Maybe I do something wrong integrating subscription ?
As following the Stripe guide, this seems to be a real issue, not really an edge case ?
https://docs.stripe.com/billing/subscriptions/build-subscriptions?platform=web&ui=stripe-hosted
No, you need to fetch the latest invoice generated from the intial subscription and share the hosted invoice url with the customer in order to pay it
So I return said invoice URL instead of the checkout session URL ?
What if for this 2nd attempt, the user pick another product id ?
- User try to subscribe to the plan A, fails
- The user come back later in the day, try to subscribe to the plan B, but as I saw an unpaid invoice, I'll send back said invoice URL, but it's a plan A product invoice.
What is the standard way to handle this in Stripe ?
Yeah you need to make sure that the old Subscription is still valid (with same product)
There is no standard way, these are checks you need to implement in order to meet your businesss need. Each mercahnt handles it according to their needs.
So, I need to fetch the invoice generated from the initial subscription, or the old subscription as a source of truth ?
Both are valid, the Subscription or its latest invoice
So I can find back the payment URL from the subscription object I guess ?
If the custom has a matched Susbcription session, then the payment url will be a hosted invoice url
So something like this should work ?
const stripe = new Stripe(isDevOrPreview ? SECRET_STRIPE_TEST : SECRET_STRIPE);
let stripeCustomerId = await getStripeCustomerId(userId);
if (!stripeCustomerId) {
const customer = await stripe.customers.create();
stripeCustomerId = customer.id;
await setStripeCustomerId(userId, stripeCustomerId);
}
const incompleteSubscriptions = await stripe.subscriptions.list({
customer: stripeCustomerId,
status: "incomplete",
});
if (incompleteSubscriptions.data.length) {
const incompleteSubscription = incompleteSubscriptions.data[0];
const incompleteSubscriptionPriceId = incompleteSubscription.items.data[0].price.id;
if (incompleteSubscriptionPriceId === priceId) {
const invoice = await stripe.invoices.retrieve(incompleteSubscription.latest_invoice as string);
return invoice.hosted_invoice_url;
}
}
const options: StripeType.Checkout.SessionCreateParams = {
customer: stripeCustomerId,
mode: "subscription",
line_items: [{ price: priceId, quantity: 1 }],
success_url: successUrl,
cancel_url: cancelUrl,
metadata: {
userId,
priceId,
},
subscription_data: {
metadata: {
userId,
},
},
};
if (referalId) options.client_reference_id = referalId; // Rewardfull
const session = await stripe.checkout.sessions.create(options);
return session.url;
}
Also, no need to care about "incomplete_expired" ones ? There is nothing the user can do / pay for them ?
Yes correct.
Gotcha, anything you'd recommend / see in my integration to make it better ?
So far nope.
Ok, great, thanks for your help & time