Signup after user subscribe/purchase a product of stripe - node.js

I am building a app where public users can view a pricing page and they can click on any plan (I am using stripe for subscriptions). upon clicking on that user will be redirected to checkout.
I want the user who has paid/subscribed to be redirected back to my app for registration. How can I check if this particular user has paid?

When you create your Checkout Session, you can add {CHECKOUT_SESSION_ID} to your success_url. Stripe will replace that template variable with the Checkout Session's actual ID. When the user navigates to your success page for registration, you can retrieve the Checkout Session by its id[2] on your server and check that its payment_status is paid.
session = stripe.checkout.Session.create(
success_url="http://yoursite.com/order/success?session_id=.
{CHECKOUT_SESSION_ID}",
# other options...,
)
It is important to note that the customer's connection can cut out after they have made their payment but before they get to your success page. In that case a customer would pay you but not be able to register. To prevent that, Stripe recommends you also create a webhook endpoint[3] and listen for checkout.session.completed event. That way, you can email your customers a link to their registration page after they have paid so that they can get to it after payment.
[1] https://stripe.com/docs/payments/checkout/custom-success-page
[2] https://stripe.com/docs/api/checkout/sessions/retrieve
[3] https://stripe.com/docs/payments/checkout/fulfill-orders

Related

Stripe: Can I send payment link received from Checkout Session object to customer in email.?

In Stripe docs, it is mentioned you can create a pre-build checkout session which is hosted by Stripe. When response is returned from session creation you can send a redirect request to client with the link obtained for the session.
Instead of redirecting the client, I want to send the link in an email/whatsapp to the customer. I want to know is it safe to do so. Is there anything i need to keep in mind while doing this ?
If you are creating a Checkout Session, the URL will expire after 24 hours and it can only be used by a single user.
If you are creating a Payment Link, the URL won't expire and it also can be used by multiple users. Note that when a user clicks on the Payment Link URL, Stripe will automatically create a Checkout Session for that user.
So if you plan to share the link directly with your users (for example by email), I would recommend to use a Payment Link.

How can I display Stripe PaymentElement form without creating Payment Intent first?

I'm building a platform for selling video courses using React and Next.js.
My goal is to create a payment form that unauthenticated users can use. I want it to work the way it works on Gumroad - a user opens a modal where they can enter their email, their credit card info, and click "Pay" (see the image). When the user submits this form, I want to create an account for them behind the scenes and process the payment at the same time, and then redirect them to the already purchased course, with them being already logged in to their account. That way the UX is much nicer, and conversions are higher - I don't have to require users to create an account before purchasing the course, to them it all looks like one step.
The problem is that to handle payments, I'm using <PaymentElement />. In order to display this form on my website, I am required to create a Payment Intent first. In order to create a Payment Intent, I have to pass it stripeCustomerId (so that I could save the payment method the user has used), as well as userId (so that, in my webhooks, after the payment succeeds, I could add the course to the list of the courses the user has purchased). And that means that in order for me to display the checkout form, the user has to already have an account and be authenticated.
Can you give me some advice? What can I do, is there a solution or a workaround to this?
What I need is:
Show the user a form where they can enter their email address and credit card info.
When the user clicks "pay", create an account for them (which has userId and stripeCustomerId).
After that, use this information to process the payment.
You can update the Payment Intent's customer after the Payment Intent is created and/or confirmed. That means the flow would look something like this:
Create a Payment Intent
Display the payment page with the Payment Element
When payment successfully completes create a Customer and update the Payment Intent's customer with the Customer ID
Normally, to add a new card information, we should follow that order
Create a new customer on Stripe (using email, first name, lastname, phone, zipcode, etc)
Create a setup intent, get a client secret
Confirm card setup with the client secret (when adding card info)
The payment process comes after with that card info. You can make that new card as default if you want.
Create a guest user first
Create a payment intent using guest user credentials
Display Stripe form on the client
Whenever the user submits the form on the client, update the payment intent with the customer id first then confirm the payment.

Register user only if Stripe payment valid

I have an onboarding registration workflow for my web application. I want to register the user only if Stripe payment is valid.
Here are my current steps :
Choose plan
Set personnel infos
Validation --> User is created
Pay using stripe on a new page --> User is activated
The problem is that it causes some friction, so I want to have step 3 and 4 in one step : Validation return the Stripe Payment view, and if valid it create and activate the user.
The problem is that I can't figure how to give application users informations to Stripe to create user on webhook.
I thought about create a temp user before return stripe view, but I don't think that is the best architectural choice.

payment intent is null in a subscription checkout session

I am integrating stripe using php by following this tutorial:
https://phppot.com/php/manage-recurring-payments-using-stripe-billing-in-php/
(my website has some subscription plans and redirects to the stripe checkout form ) . however, for the last step, I decided not to use webhooks, I chose to store the info like in this tutorial https://www.codexworld.com/stripe-checkout-payment-gateway-integration-php/ (I know it is not for subscription but I just use the success.php code from this tutorial to collect the customer info and payment intent details).
I tested it, gone throught the stripe checkout form , and on success I printed the checkout session object and noticed that the payment_intent field of that object is empty ! so i cannot load the payment intent object and get its info although the payment is successfully made and it is showing on the dashboard . any idea why ??
EDIT :
According to the documenttaion of a checkout session (https://stripe.com/docs/api/checkout/sessions/object), the payment_intent field stores the ID of the PaymentIntent for Checkout Sessions in payment mode. In my case I have a subscription mode not a payment one. however,if I still want to get the $intent->status , can I use the payment_status field of the session object $checkout_session->payment_status?
And if subcription payments really don't have paymentintents , then why did the payment appear in the payments section on the dashboard?
Based on the mode you passed in, either one of payment_intent, subscription or setup_intent will be populated, the rest will be null.
When a Subscription is made, your user is invoiced so it is considered a payment and will appear in the Payments dashboard. You can retrieve the Subscription and access the latest_invoice field to obtain the Invoice object. The Invoice object contains the payment_intent field. This is likely what you're looking for.
Using webhook would simplify the process, since you could listen to invoice.payment_suceeded to retrieve the PaymentIntent ID.

With stripe Checkout, how do I keep track of the payment status

In the stripe documentation, it says:
So in this case, the checkout page goes to the success or failed page on my frontend.
I use the backend to track the payment status so that we can monitor the transactions in the admin portal, and the above approach seems dangerous to me.
When checkout is successful, it redirects the window to the success url. This means I have to call the backend API in the success page to update the payment status. However, the stripe is the source of truth about the payment status, and the status update on DB should come from Stripe, not come from a frontend page. At the very minimum, if a user refreshes the success page, it would have called the API again and again which is bad. Also, it is about "a user says I paid successfully" v.s. "Stripe says they paid successfully".
I tried the Stripe webhooks, but in the webhook data object, there is no information that I can use to link it to the sessionId that is generated from creating the checkout session, but the session id is the only tracking id I can get from Stripe about a payment.
What's the best practice, if Checkout is the only solution, to securely update my database?
You have 2 options:
Rely on webhooks. The checkout.session.completed event will describe a Checkout Session which contains its ID, which you hopefully saved when you created the Session earlier so you can link the two together.
Retrieve the session ID from the success URL once the payment is complete and retrieve the Session on your server, then check the Session's payment_status. This way your server can verify if the payment was actually completed or if someone just managed to guess the URL of your success page.
Stripe doesn't recommend only doing option 2, as it's very possible that users close the browser tab or window before the redirect to your success page can happen, resulting in a possible loss of payment confirmation. You should always use webhooks instead to guarantee your purchase fulfillment logic correctly fires.
You can get Stripe Payment status or session Details by session_id on asp.net core || .Net 5
var service = new SessionService();
Session session = service.Get(yourSessionId);
// You can track :-
session.Id;
session.PaymentStatus; // Paid or Unpaid
session.Status;
session.Mode;
//And more

Resources