Prevent duplicate subscriptions with Stripe Checkout - stripe-payments

Consider the following course of events:
A user selects one of multiple subscription options on my website and clicks the "pay" button.
They're redirected to the Stripe Checkout page but don't complete the payment yet.
They somehow manage to get back to the page where they select the subscription while keeping the Stripe Checkout page open. (I know this is somewhat contrived but technically possible.)
They choose a different subscription option and click on "pay" again.
A second checkout session is created and another Stripe Checkout page opens.
Now they complete payments on both checkout pages.
How can I prevent this? Is there a way to cancel a checkout session? When I create a checkout session for a subscription, I don't receive a payment intent that I could cancel. There also doesn't seem to be a way to cancel checkout sessions directly.

I don't know of a way to prevent the scenario you described as the customer in question is explicitly deciding to pay you twice for two different subscriptions.
That said, if your use case requires a customer to have only a single Subscription you could add logic on your end that would do the following:
Set up a webhook endpoint to listen for customer.subscription.created events.
Whenever a new Subscription is created list the Subscriptions belonging to the Customer.
If the Customer has more than one active Subscription cancel the newest one(s) and refund the associated payments. You may also want to send the customer an email letting them know what happened.

Related

Stripe create Subscription with payment method in one go instead of two

for my subscription based product I want to have a possibility to subscribe and enter payment details at once with stripe and struggle with that with the api.
In https://stripe.com/docs/billing/subscriptions/build-subscriptions?ui=elements I see an option to create a subscription with payment_behavior='default incomplete' and then enter the details to confirm the payment intent. So far so good. However if I create the subscription like that even before the customer confirms payment details stripe already generates an invoice which is not really what I want before final confirmation by customer.
Options I see:
create setupintent, have this filled by customer via elements and then have the customer subscribe. Technically works nicely but for a sales and customer perspective is not good as it has two steps thus probably reduces conversion.
create the subscription in the background before final subscription confirmation by customer and use the clientsecret of it to pass back to browser and then have customer enter his payment data and submit that and finish the setup of subscription and payment info. Technically works - however I realize that when I create the subscription to get the clientsecret to pass to elements before the customer enters his payment data and confirms the subscription the subscription is not only created but an invoice too - which would be really, i.e. an invoice created before customers really confirms the contract
create setupintent and submit it via elements and in metadata of it add the info of product that customers wants so that when the paymentmethod gets created and I get webhook event I do the booking of the product given in metainfo. May however mean the customer gets to success page but the webhook has not notified yet and thus the customer is not really subscrubed at the point in time but gets a success message he is
same as 3 except do not pass info via metadata but via successUrl parameters which refers to and endpoint at my backend which upon being called after setupintent was setup will do the subscription and then redirect to my frontend which shows success page. That seems like a error prone workaround however.
Create a workflow which is a 2 step sign up and asks for paymentinfo, sets that up and then brings customer to a final confirmation page where the submit triggers subscription creation. Seems a bit complicated from a user flow, but so far probably the best option?
Any better options?
Cheers
Tom
ps: Interestingly enough on discord stripe support told me #2 is the way to go - find it hard to believe ...
As far as I know, there isn't a workaround for this unfortunately. It is just how Subscriptions API is designed by Stripe. You can learn more about that here where they talk about "how subscriptions work".

With paypal REST API V2 if payer does not complete the payment, what is the best way to implement retry payment feature?

I am quite new to PayPal rest API and wanted to provide user with a way to retry payment option in case user does not continue or cancel from the PayPal approve URL. Should I create a new order altogether and get a new approve URL or is there a way to retry payment for an old order in 'CREATED' OR 'APPROVED' state?
An order is valid for 72 hours from the moment it is created, and for 3 hours once loaded in a PayPal checkout for approval.
If a user abandons it and is going to restart their checkout on your site, it's generally best to forget about the old order and generate a new one. You can specify a unique invoice_id for orders to prevent any accidental duplicate payments (by default the PayPal account will only allow one completed payment per invoice ID)
Rather than redirecting away from your website to PayPal for approval, for modern websites it's best to keep the user on your site, and have them approve the payment in an in-context experience/lightbox, which also has the option of expanding a credit card form right within your website. See the demo at https://developer.paypal.com/demo/checkout/#/pattern/server

Stripe webhook confusion

I am having a hard time finding the right webhooks in Stripe to use since it seems a lot of get fired off for multiple situations.
So my site sells a few items (like 10) that can be bought as a single purchase or a subscription (you get the item every X days, no SASS jut products). I am using Stripe's Checkout and Portal to handle all subscriptions and single purchase and those parts work great. Person adds stuff to cart, checkouts out, pays, we are all good. The issue is adding an order to our system from the webhook.
Look at this scenario: a person adds 2 single items and 1 subscription to their cart. They checkout and pay. When that happens we had the checkout.session.completed catching the checkout session was completed and we add those items from their cart to an order. The subscription re-ups after "X" Days we would listen for the invoice.payment_succeeded webhook to create a new order in our system. This logic is flawed though since invoice.payment_succeeded is called on the first order too so basically when they checkout our system adds 2 subscription orders: one from the checkout.session.completed and one from the invoice.payment_succeeded. How can we handle this?
What I would like to have is:
1 webhook to know when the checkout is complete and is only called then, which they do: checkout.session.completed
1 webhook that is only called when a subscription is renewed, not also when created, which I cant find.
If they dont have that webhook for subscription renewals only, how can I tell in the "invoice" object is the very first one so I dont do anything on checkout, only create a new order on renewal?
Instead of using invoice.payment_succeeded you should consider using invoice.paid, as it will also fire when you mark an Invoice as paid out-of-band (which won't happen with invoice.payment_succeeded). Both describe an Invoice, so you should be able to switch between them with minimal or no changes to your code.
You're correct that there is no Event specific to renewals for a Subscription only, but you can use the billing_reason property on an Invoice to determine why the Invoice was created. If it's the first Invoice for a new subscription the Invoice will have billing_reason set to subscription_create.

Which webhooks to look after in Stripe Checkout?

I'm implementing subscription with Stripe Checkout, but I have some questions that I couldn't get definitive answers for even from their support.
I have following scenario:
User clicks on a Subscribe button
User gets redirected to Stripe Checkout page (along with session token)
User successfully pays (and from now on is a Customer)
and here I get 14 webhook calls (each one is different event type):
checkout.session.completed
payment_method.attached
invoice.created
customer.updated
customer.subscription.created
customer.created (even though I used the same email - test mode, but still...)
invoice.finalized
invoice.updated
invoice.payment_succeeded
customer.subscription.updated
charge.succeeded
payment_intent.succeeded
payment_intent.created
invoice.updated
edit: I get all of them at once because I use Stripe CLI's listen feature and it probably shows all calls which normally wouldn't happen because they have to be defined in dashboard event by event. For instance if I create invoice in the dashboard and pay it then if no webhook is defined explicitly then my server won't know about anything
Until here it all works good. My concern is that:
if a Customer will be charged next month which webhook should I listen to? I need to differentiate between first-time Customer (because I create new account for that user) and existing Customer that I just need to note in database that this user is still active (or listen for event of subscription cancellation? subscription_schedule.canceled maybe?). One idea is to just listen to successful payment and upon that check if customer exists in database - if he does just update, if not then create account.
when I do another subscription payment using the very same email I get exactly the same webhooks (including customer.created which I think shouldn't be there) or am I missing something?
is there any possibility to double-charge a Customer by accident like I read in other Stripe implementations (see: idempotency)?
what are other things to take into account while implementing Stripe Checkout? I feel like their instructions are not reassuring that I've done everything that is considered good practice.
Flow that I want to achieve:
User successful payment (as above in points from 1 - 3). Already done!
Register new customer in database (Firebase in this case) and log him in automatically so after payment he has instant access.
As long as customer's card is charged he has access. While he cancels or card has no insufficient funds I need to have my server notified about this to downgrade access.

How to deal with subscriptions using PayPal's REST SDK

I am trying to create a basic subscription service on my site and I am not sure of a standard way to deal with subscriptions. I'm sure I could hack something together but I'm just wondering if there is a suggested way.
So I have created a billing plan and activated it.
I have a subscribe button on my site that creates a billing agreement referring to the billing plan created in step 1 and redirects the user to the PayPal website were they can login and accept the subscription.
Once the user completes the actions on the PayPal website they are returned back to my site with a token were I then execute the agreement using the returned token from PayPal as per the documentation.
So I guess after these steps the subscription is created for that user, is active and the first payment is made immediately.
In my database, I have a field for each user names subscribed and it's value is a boolean which I set to true once they are returned to my site and the execute command is successful.
My problem is keeping this boolean value up to date for each user as this is the value I check to see if they can access the content.
Canceling - I can provide a cancel button on my site to cancel their subscription and when successful I can set the value to false. But what if they cancel through the PayPal website? I think there is a webhook names BILLING.SUBSCRIPTION.CANCELLED which may send me the agreement ID and If I save it in my database I can see which user it belongs to and set their subscription to false.
After the first month has passed and the next payment is due, is there a webhook sent for a successful payment or a failed payment so I can then set the subscription value accordingly? I see there is a webhook named PAYMENT.SALE.COMPLETED but I don't know if this fired for a successful payment and PAYMENT.SALE.DENIED for a failed payment. If these webhooks exist for subscriptions I imagine it should be a simple solution to keeping this subscribed value up to date.
Hope this made some sense.

Resources