Advanced Guide on stripe subscription: NextJS, Webhooks, NextAuth, Prisma

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
I have been building out a SAS project in the side and in that for this pricing strategy I have Incorporated a subscription based model from stripe and to be honest it was quite challenging to work with because there's a lot going on you have your local production environment you got stripe you got web hooks you got database you got even authentication so all of these things together playing together to make things work so if it wasn't for this person Nicholas he has he's got this amazing repository which explains everything in detail so he helped me understand this within a day so the goal of this video is to teach you everything you need to know about subscriptions in stripe so that you can integrate subscription based model in your SAS or whatever and we will try to achieve that in less than 30 minutes I'm not promising anything but that's our goal within less than 30 minutes will be equipped with the knowledge of integrating subscription based model for your SAS and fii this the repository is based on um Prisma and for my project what I've used is um dynamodb for certain reasons I'll explain that later but in case if you're using dynamodb um I've also got a repository which is called stripe subscription dynamodb in this I use dynamodb instead of Prisma so you can check that out if you don't understand you could let me down know in the comment section below I'll help you figure this out or I'll also bring a video if you want me to so that's basically it um let us move on to the video part before we actually begin let me demonstrate how this works so this is my sign in page so in my stripe customers tab there's just one um customer right now which is me as a guest so don't pay any attention to that and if I go to billing subscriptions there's nothing right here so now if I go here and also my Prisma studio if I refresh this you can see there's nothing here so now if I sign in if I click one of my accounts you can see the web hooks being triggered right here as you can see the customer created and got sent back to my local host if I go to customers now refresh this you can see the new user here if I go to my Prisma refresh this he's been updated in Prisma as well and right now the subscription is not active because he's not clicked any of the subscriptions so it's false but now if I go to standard you can see the web hooks again now I'll just hit the since this is a test mode I'll just hit some random numbers here and hit start trial you can see all those web hooks being triggered I'm I I'm sent back to the dashboard and if I go to my customers billing subscriptions you can see um he started his subscription and if I go to my Prisma Studio here refresh this is active is true and the subscription is also there now finally if I hit cancel subscription again the web hooks are triggered here if I go back here I refresh this you can see it cancels um at July 11th which is after a few days and if I go back here this Still Remains the Same because um if I refresh this this is still the same it will only change to false when this time hits so when you when this user hits July 11th a trigger is fired which will change this to false so that's basically what we'll be building let's move on so I've got a minimal next.js app installed here with Prisma and next auth as you can see this is just the bare minimum um what you can find from the docs and I've also added an adapter here prism adapter and if you if I go to my Prisma schema here I've got um three to four models this is from here so if you go to next auth Prisma adapters you get their initial code from here I just copied it out and pasted it right here so that's what this is and we're using the sqlite database because this is just for demonstration reasons and so we are not using any external database like a plan scale or supabis so that's what we are working with and if I go here we have a login button in the login button we have certain conditions if the user is active we will have that field later on it'll be pushed to the subscription page I'm sorry if he's if the is active is false he'll be push to subscription if not he'll be pushed to the dashboard page and once the user signs in he is redirected to the subscription page and for the subscription card um if I go to subscription here pages we are mapping over an array of subscriptions so if I go here constants um here we have three plans which is basic standard premium and I've got the price ID for each one of those if you don't know how to do that check out the last video I go in detail on how to get the price ID and so on so we are mapping through that array um yeah so we are mapping through that array and um we are rendering out a card called subscription card and each of those card will have an on click uh as of now I have not configured it we'll do that together and we are rendering out some data which is the plan type price and this um description so that's what we are working with so to start off let's go to Prisma schema and in here we need three Fields extra fields for stride to work which are stripe customer ID should be a string this will be optional it will be also unique and we'll have a is active field to check whether the user has an active subscription or not and this by default will be false then we'll have a subscription ID which will be required when the user unsubscribes so that would be a string type which will be optional so once that's done let me push the changes so npx Prisma TB push so so this will Define the schema for us as you can see we got a new file here called dev.db so once that's done we can head over to next auth and start in our next auth file we have something called events that occur when certain things happen so for example there is sign in there is sign out but what we'll be using is create user so this basically is triggered when a new user is created um this is triggered so inside that what we'll do is I'll actually restructure the user all right so in here we'll initialize stripe so once this event is triggered um we can use stripe so await stripe and create those customers so we can um trigger something called stripe dot customers dot create which will create um Customs for us so we'll give the email which is user dot email and will also give name is equal to username and this error will go if I give an exclamatory here so this creates the stripe customers for us so after we've created the customers from stripe we'll have to push this to the database so in order to do that we chain a DOT then we have a callback function with customer and we return it with prisma.user.update with the user ID is user ID and we give it the stripe customer ID as customer ID which we're getting from stripe so this basically pushes the customer to our database so once that's done and also if I've also configured here the types so you might be getting an error if you're using typescript for the user so go to the declare just go to types declare module next auth and for the interface session I want you to add these four fields and for user add these three Fields so that will get rid of all the errors for you so once the user is created we need to have access to certain properties in the session so we to do that um we get some callbacks which next talk provides us so if I go here call backs and so in here we can add some additional properties to our session so if I and let me type out those additional properties which are ID stripe customer customer ID is active and subscription ID so let me type that out so what we are doing right now is in the call once the Callback is triggered for the session we are inserting some properties to the session which are the user ID stripe customer ID is active and subscription ID so now um if you go to our components if we go to any of the pages we'll have access to these additional properties which will be required for stripe to work properly so with that we've configured our next auth so now let us try whether everything works or not so let me go back to I'll run the server so npm run Dev let me refresh this I'll also leave okay don't mind this this is something which I was playing around with so as you can see there's now just a guest user which is me so once that's done it's loading okay I'll sign in I should lead me to this page right here and I'll select one of my accounts should redirect me to the subscription page right here so now if I go back to customers refresh this we have a new customer called take AK and let us also check our database so let me go to my terminal and npx Prisma Studio let's go to user and you should see some additional Fields as you can see here stripe customer ID is active is false by default it should be false yeah so as we if I go back here we are pushing the stripe customer ID to our database so with that we've done the first portion which is the authentication part all right so now let's move on let me expand this now let's so since we are in the subscription page sorry since we are in the subscription page let us move to the subscription page so under subscription folder I have a page and inside here I have something called sub subscription card let's go inside that so in here we'll have to once the user clicks this he has to be redirected to the stripe checkout page so let's configure that now so on the on click let me create an on click here so which will be handle create checkout session and we'll also give a price ID which is coming from if I go to constants here here I have a price ID we are um we are looping over this we are mapping over that here and we are sending each of the subscription card with a price ID and that we are giving it here now let us create this function so and uh just above the return statement nfn and create session this will be a product ID will be a string and let me just give a okay so I've created a response to API stripe checkout session which is not yet created we'll create that and I'm sending the product ID to it and we also have headers and next what we need is once we get this let this get the checkout session so check out session from the response so rest will await press.json and to get just the specific attribute of that object let us chain a then function inside that we'll have value dot session and I've probably made an error somewhere yeah so yeah so what we're doing right now is getting the session from the response to Json and we are getting just the session since we'll be sending an object we are taking the session out and putting it to this checkout session next up we have to create a stripe which which is which we are getting from here get straight so this basically I got from here setting up from the documentation it is said that um you are supposed to import stripe in this manner which I think is called the Singleton pattern so yeah so just create a file under utils get stripe JS and place in this value so that's basically what I've got here so once that's done we can destruct something out let me type that out now we can destructure error from away stripe dot redirect to checkout and we also have to give it a session ID called check session checkout um session ID I actually used to use window dot location.hrf but this is a method for this so this will redirect the user to the stripe checkout um page so now let us create this page now so under API let me create a new folder called checkout session check out session and inside here let me put this in API okay and inside here I need another folder called stripe let me put this so that everything is in one folder all the stripe related patch let me name this to perfect so now I have a full local stripe in there I have a checkout session folder and let me create a new file now called route.ts so in here let me insert some code boilerplate code so what we're doing is we are getting the body from Vector Json and we're just console logging it out so that we can see what is happening next let us initialize stripe here so that we can create a checkout session next we can create a session which which this time is get service session so now we have access to the session we are also providing it the auth options from next auth so if I go here yeah so we are giving it this auth options to get server sessions right here so now we have access to this session so now we can perform a check so if the session does not exist we can just give a Json response that the user is not signed in so this won't trigger our stripe next we can move on to the stripe portion so if I go to Mozilla here um they mention how to create a session um so we'll be doing that now let's go here under the if condition in here let us create the checkout session so inside let we'll have to mention the mode which is a subscription mode you have payment setup and we'll be using subscription next is the customer so you'll have to give it the customer who wants to subscribe so that will get from session user dot stripe customer ID stripe customer ID so this will tell stripe which customer wants to subscribe so once that's done you can just mention the line icons and here we give it an early object we have the price ID so the price this is the price ID so that will will be getting that from the body so if I go back to subscription card here we are giving into the product ID we are sending it and we are getting that here that's what we are giving here so once we've given the product um the price ID we'll also mention the quantity which is one so once that's done we can give a success URL so this basically is in the EnV file which just points to localhost so when you're shipping it to production you'll have to change this in the EnV variable and then we give the session ID with the checkout session ID so this um will in the path this will be having access to session ID next is the cancel URL so I'll just copy this paste it right here and just remove this so if it gets canceled we can just push them back to the main page so we have the cancel URL as well this one plus okay next is next property is the subscription data subscript subscription data here we can send some metadata which will which so metadata is basically things which will be having access to in a subscription object when we will be handling with the web hooks so metadata inside that we passed the paying user ID you don't actually need this but just um Just for information sake I'll put this as well metadata and lastly so whenever you're having a SAS project you'll have to give it a trial period of time so that the users can play around with the application and figure out whether it's for them or not so to do that they give us another property called trial period days so you can mention the amount of days the trial period should last so in our case it's 14. so yeah for so we've done that so this is the main checkout session object configuration and lastly we'll have to send a response back to the client so let's do that so before sending a response we'll have to check whether there is a URL attached to this object if there is no URL attach the object we'll have to send a message if there is a URL attached attached so if there is a URL attached we can just send a Json um of session object and a status of 200. so with that um we have finished the back end portion API routing so again once again this is the front end we are sending the product ID here we are getting the product ID we are telling stripe which customer wants to subscribe and also the product in the body this is the price ID and once that's done we send a response to the front end with session so right here we'll be destructuring that out with value dot session and putting that to checkout session then with stripe we redirect the um we redirect the customer to the stripe checkout page with the session ID which we're getting from here so that's basically it now let's try whether this works or not so let me go back here I'll refresh it just in case it's signed in as Taki K I'll hit basic and let's see what we get so as you can see it's a 14 days free trial um and we are redirected to this page you just have to give your um card info and you'd get subscribed so but before this we also need to configure web hooks so let's do that so that I can show you how everything plays out at the end let me go back so again so this is basically the cancellation page I have mentioned it right here so if right here so if the cancel URL is basically the home page which is here let's go to and configure the our web hooks portion for this build so before moving on let me explain what exactly web hooks are so when our local uh production environment is communicating with stripe stripe basically sends out some triggers and web hooks are something that listens to this triggers and they make changes to the database that in the simplest terms are what web hooks are so now if I go to a home Developers and in here if I go to web hooks I can say add endpoint and if this is for our production build which we won't be configuring so if I hit select events and go to um customers because these are these are all the events that can be triggered or um to put it more precisely these are the events that you can listen to but since we are developing in a testing environment let us actually do this so this is the initial boilerplate core which you'll be needing so let me just go back here under API let me create a new folder called Web hooks and inside that let me create a new file called route dot TS and in here let me paste in all the code so in here let me paste in the code so this is config configured according to next.js so here they're using Express so just change the little bit so that we next JS is used instead otherwise everything is same so these are all what has come from stripe what we are concerned with is this right here so if I um go to this check um drop down here and if I say I want to listen to invoice upcoming you can see that this changes are being made and you can just copy this out and paste it right here so that's what I did so I'll be listening to even such as customer Dot subscription.created and delete it so when the customer first is created this event is triggered and when it's deleted this event is triggered so they should something should happen in this case let's do that now so in here let me say await um Prisma dot user dot update so we want to update something and that something is basically where where subscription ID stripe customer ID is subscription dot custom and I'll just say add string so that we get rid of the error okay then we say data and we keep passing is active is true and subscription ID is subscription ID so yeah so we have an object called subscription which you're getting from stripe and I'm getting the subscription ID so that this will be used when we are when the user cancels their subscription so um in Nicholas's repository this process is not done this is what I did so in our we invoke our Prisma and say we want to update our stripe customer ID and we say that is active so the subscription is true and we also um say we also add the subscription ID so this um subscriptions ID we add now I can do the same for what happens when the customer unsubscribes so under customer dot subscription.deleted I'll paste in this but instead of passing in the subscription ID which is not required for in case the subscription is deleted I'll change the is active to false so the subscription is turned off and we'll take one of the break statements I'll save all this and I'll save this as well so now in order for us to listen to the webhooks um stripe provides us this [Music] um script which allows us to forward all the events to our localhost so this cannot be done in a production build just for the testing purposes we have this here so that you can see and understand how this works so let me just copy okay before that we'll have to login to stripe so I'll create a new instance of my terminal stripe login I I think I've already logged in therefore I don't need it okay um I hit enter and I can just authenticate it allow access this one so I have access I've logged in now so next what you can do is we have to forward those events to localhost 3000. let me go back here and change this to 3000 and this will be under API web hooks plural so API web hooks I'll just close this out so that you can see better okay so under API web hooks route that's what this path is Right enter and it should give me a secret key so as you can see it's completed here so now it's listening so this key you'll have to add to your EnV variable um here stripe web hook secret you'll have to add that in here so as this is env.example I can show you this but dot EnV well make sure you put that in the dot EnV file and not the dot env.example so once that's done we can test are um whether this webhook is um fired or not so let me go back here and let me go to my next app so I'll hit basic should forward me to the checkout page as you can see here now all of these events are triggered and it is being sent to localhost 3000. so yeah so if I go back so signed in as Taki so this is the dashboard if I go to back to customers I go to products or I think it's billing subscriptions you can see um I am start I started my trial and in July 11th which is the no yeah sorry it's created in June 27th so and the trial end in 14 days which is July 11th all right so with that um we have done that part now all that is left is to configure this cancel subscription part so let's do that now so for cancer subscription we can just copy out the checkout session folder and just copy that out and paste it right here okay so I've got to copy and I'll just rename it to subscription can sell I think that's spelled correctly I can go back here to this route and I can I'll just clean out all this so we'll need a session this will be the same and the only thing which will be different is um let us get the subscription ID so const type subscription ID will be from session dot user Dot um subscription ID and instead of using Create we can update this so update and we don't need any of this we don't even need this and this won't be an object so now inside here we can give it the stripe subscription ID and I can say cancel um cancel at end period okay I'm getting an error let me just check out what that problem is I probably have to import this okay so instead of it being checkout session it should be subscription dot update yeah so that error is gone we don't need this no more okay so I've given it the stripe subscription ID so when the user um deactivates a subscription I don't want him to immediately um lose his access to the service so in order to avoid that I want to cancel only at n period so once he hits cancel on say 13th and his subscription is about to get expired on 14th it won't get expired till that date so I'll say true and I'll also send the metadata ping which is paying user email so this is not required if you don't want this um metadata is like not required even if you don't give this it's fine but I'll just give it because in um okay why am I getting an error it's probably because of an exclamatory here okay that's fine so in the mongodb when I was using mongodb instead of Prisma I actually needed paying user email just to make um changes to my database but in this case you don't need this so you can just come in this out no worries but if you're using mongodb you probably might need this not mongodb sorry it's dynamodb okay so this is the back end now let's go to the front end I'll just remove all of this go back to dashboard page and have a canceled subscription already here I've already configure this function so we are having a response which is to API stripe um and it is subscription cancel we are destruction the subscription so if I go here we had this okay good thing I noticed that this should not be session there should be subscriptions oops this should be subscription and I'll send this right here subscription yeah yeah that's fine um yeah so subscription uh we are sending what is that we are destructing the subscription we are console logging it out and then we are pushing the user back to subscription page okay now let us try this go here and I'll say cancel subscription let's see what happens okay nothing happened let me check what the problem is unexpected end of data okay fine I probably messed that up let me check that we actually don't need all this and this should be a get request probably didn't have copied it get request and this is also a get request fine I think now it should work so I'll hit cancel subscription now yeah so you can see customer.subscription dot got updated and it was sent back to our Local Host so if I go back here trial ends I'll just refresh it and you can see it cancels at July 11th at the end of the trial so that's basically it so with that I think you are equipped with all the knowledge which is required for you to um add subscription based pricing in your SAS so let me just cancel this out actually I'll run that again now let me just demonstrate how it goes without um from the beginning so I'll sign out I'll refresh my Prisma Studio go back here I'll sign in take one of my accounts I sign in okay so I've signed an establish a call now if I go back here and go to customers okay so as you can see the new customer is created but if I go to billing and subscription he's not subscribed yet and let me go to my Prisma Studio refresh this is the new user and if I go here um he is not active because he's not yet clicked on any of the subscriptions and there's no subscription ID as well so now if I go back here and say premium I'll just do that and do that again it's fine it's important location and I hit start Trail you can see the all the triggers being fired here he's pushed back here to the dashboard and if I go back to my this billing page here I refresh it scroll down and he is now subscribed and if I go back to Prisma Studio refresh this you can see is active is now true and he has also a subscription um ID and let me go back here I hit cancel subscription okay now he's now let me go back to dashboard to refresh this and it cancels and if you noticed if I refresh this this is still true this won't be false until we have reached this date so once this date is reached um stripe sends off that event called um subscription deleted and only then um this is changed to is active false and which will be reflected here so until then the user will have access to the dashboard so that's basically it hopefully you understood something from this and yeah before leaving uh whenever you are configuring for your production build your end your you should add the add end point here which is a instead of localhost 3000 slash API slash web hooks will just be your domain name and slash I'll just type that out here domain Dot Com or domain name.com it should be API slash and it should be I think webhooks web hooks you just select all the events which you want to listen to so in our case it was customer so it will be customer subscription created and subs customer subscription deleted so you um hit those two you hit add events you'll get a web um web hook secret you'll have to copy that and paste in in wherever you're deploying it to so yeah so that's basically it um thanks for watching make sure you give a start to Nicholas [Music]
Info
Channel: thabish
Views: 6,590
Rating: undefined out of 5
Keywords:
Id: rjDv-iNO4iw
Channel Id: undefined
Length: 44min 4sec (2644 seconds)
Published: Fri Jul 14 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.