Forget Stripe: The Easiest Way to Add Payments β
How to Build Full-Stack AI SaaS with Claude Code (Tutorial)Freshπ
2025-11-21
Integration Flow β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β INTEGRATION ARCHITECTURE β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β USER REQUEST β
β β β
β βΌ β
β βββββββββββββββ βββββββββββββββ βββββββββββββββ β
β β β βββββΊ β β βββββΊ β β β
β β Database β β AI Engine β β Output β β
β β β βββββ β β βββββ β β β
β βββββββββββββββ βββββββββββββββ βββββββββββββββ β
β β β β β
β β β β β
β ββββββββββββββββββββββββββ΄ββββββββββββββββββββββββ β
β β β
β βΌ β
β βββββββββββββ β
β β RESULT β β
β βββββββββββββ β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββIntegration Points β
- Core concepts explained
- Step-by-step implementation
- Practical examples
Transcript β
[00:00] In this video, I'll show you how to add payment processing to your SaaS applications. Welcome back to this series where I show you how to build a real world SaaS application using coding agents like Claude Code. So far, we've created this application that allows users to upload images of themselves or their pets, and we'll use AI to generate plushies from those images. And of course, as we're generating images, we're also deducting credits from our account. Now the problem with our app at the moment is once we've used up all of our credits,
[00:31] we would have no way to purchase additional credits. We've simply created these mock components for purchasing credits, but this isn't actually integrated with any payment system. Now sure, a lot of you are familiar with Stripe, but the problem with Stripe is that it's not available in all countries. And from what I understand, dealing with tax can also be really challenging. So instead, we'll actually use Polar. Now there are basically two major benefits of using Polar. Firstly, it's available in way more countries.
[01:03] And also Polar is the merchant of record, and they will deal with all the complications around tax. And just to be clear, I'm not sponsored by any of the platforms covered in this series. I've just tried a lot of different payment gateways, and Polar has actually been really easy to use. Polar offers easy integration with Next.js, which is what we're using in our tech stack. And speaking of our tech stack, you might recall that we are using BetterAuth for all of our authentication stuff.
[01:34] And you'll be pleased to know that within plugins, there's a Polar plugin for BetterAuth. This makes it insanely easy to integrate Polar into our Next.js and BetterAuth ecosystem. So what I'm actually going to do is on this page, we have all of the instructions for adding Polar to our application. So I'm actually going to copy this page as markdown. And if you've watched the previous videos, you know exactly what I'm going to do next. In the docs folder, under technical,
[02:07] let's go to BetterAuth. And within BetterAuth, I'm going to create a new file called Polar. I actually already included this file as part of the border plate, but really all you have to do is create a subfolder called BetterAuth with this Polar file, and then paste in everything that you just copied. And believe it or not, it's really that easy. So in Cloud Code, let's switch over to plan mode and let's say, hey there, let's create an implementation plan for adding Polar and
[02:37] payment integration into our app. At the moment, if we go to the pricing page, we have those three different packages, but they're not actually integrated into the solution yet. Those are just UI mockups. So what we want to do is offer those same three packages in our application, but actually integrate Polar as a payment gateway. Now do take note that we are using BetterAuth, and BetterAuth provides a Polar plugin that we can use. All right, so if you want, you can pause the video
[03:08] and have a look at this prompt. But what I really want to do is I'll grab our doc and throw it into the context. Over and above this documentation, feel free to use tools like the context seven MCP server to retrieve up to date documentation on using BetterAuth with a Polar plugin. And let's send this. All right, so Cloud's asking a few clarifying questions like which Polar environment should we start with for development and testing? So this is an important point.
[03:39] In development, we don't want to use real credit cards to test the functionality. So we will start in sandbox mode. And that simply allows us to test all of this with fake credit card details. So let's start with sandbox. Should we track purchase history in a dedicated database table? So I'm actually going to say something like, we need to keep track of all the transactions. So when users purchase credits, we want to have a record to show that they've purchased credits.
[04:10] But when they spend credits, we also want to track that. All right, so let's send that. Which Polar feature should we implement? Checkout. So core checkout flow for purchasing credit packages. This is essential and should always be included. When Cloud gives us these square brackets, we can just press space bar and it actually allows us to select multiple options. So we definitely need checkout. Then for the portal, this will allow users to view their purchase history, orders and subscriptions.
[04:41] We definitely want that. Weighbooks handle Weighbook events like orders.paid, et cetera, for credit addition. Required for adding credits, we definitely need that. Usage tracking, track usage events for potential future usage based billing features. I don't think that's necessary. Let's go to the next step. How should we handle Weighbook processing for credit addition? We'll actually go with the async option, which is also the recommended option. Then let's submit these answers.
[05:12] Cool, so Cloud is done and let's have a look at what we have. All right, so we've got this implementation plan. It says it's going to integrate polar with better auth to enable credit purchases through three existing pricing tiers. Basic, pro and elite. This includes full transaction tracking and purchases. It's going to install all of these dependencies. And this is really important. We need to set up a few more environment variables. I'm actually going to copy all of these right now
[05:42] and add them to our environment variables. So in the .env file. But for now, let's go to the implementation plan and make sure everything looks correct. Okay, I'm happy with this implementation plan. So let's switch over to change mode and let's run the command create feature. This create feature command will now create a subfolder within this specs folder. And within that subfolder, it will create a requirements file and a detailed implementation plan. And cool, so we've got our feature folder
[06:13] along with the requirements document and this detailed implementation plan. The plan is split up in phases with actionable tasks per phase. So all we really have to do now is clear the chat, let's pull in our feature folder and it say, please go ahead and implement phase one of the implementation plan. Update the tasks to complete once you're done. Well, phase one is actually really small. It's just kind of installing the dependencies and adding these environment variables.
[06:44] So these are mostly manual tasks. And in phase two, a lot of this seems like manual work as well. So we have to create our polar account and create our packages. And then we have to provide the product IDs. So let's actually go ahead and set all of this up. So what we need to do is change this from polar to sandbox.polar.sh. Now we're in our sandbox environment. You might be prompted to sign in first. Then let's create a new organization.
[07:14] Let's call this Plushify. Then I'll accept the terms and click on create. I'm going to click on skip onboarding. Then from this page, let's go to products and let's click on create new product. And let's give it a name like basic. And in the description, I'll just say 30 credits. Then under pricing, we can make this a one-time purchase or maybe it's a subscription that runs daily, weekly, monthly, or yearly. And for the price, I'll just make it $9.
[07:44] All right, we don't have to populate any of this other stuff. Let's simply click on create product. All right, so we've got our basic package. Let's actually create another one. We'll call this one pro. And with this one, we'll get 100 credits. Again, I'm not going to set anything else. Let's simply create this product. This is a one-time purchase at a fixed price. And for the price, let's make this $19. All right, then let's create one more. This one I'll just call premium. And this will give you 200 credits.
[08:15] And of course, we'll make this a one-time purchase at a fixed price of $29. Then let's create this product. All right, so we've now created our parallel account. We've also set up our three packages and then copy all three product IDs for configuration. Right, so to get the product IDs, all we have to do is click on these three dots next to the product and click on copy product ID. I'm actually going to add these two cloud code. So I'm going to say, all right, so I've created my parallel account
[08:45] in the sandbox environment and I created the three products. Here are the product IDs for each product. So for basic, I'll paste in that ID. Then we also have pro and premium. So let's copy the pro product ID and let's copy premium as well and add it to this list. And also, please rename the ELITE package to premium. And cool, let's send this. All right, so what I'm not sure about
[09:16] is where these product IDs will actually be stored and used. So I'm just going to ask Claude. Don't make any changes. This is just a question. After I've given you the three product IDs, but where are these actually stored and configured in our application? Right, great question. The product IDs will be stored in phase four when we create the configuration files. All right, so these values will actually just be stored in a config file. I guess that's okay. We could always move those to a database table if we wanted, but for now,
[09:46] let's just go with this config file. All right, continuing with this implementation plan, we need to create this webhook endpoint in Polar. So this can be quite a tricky one. The reason we need a webhook is when we process the payment and we send the instruction of the Polar, Polar will deal with everything payment related. So they will process the client's credit card. And if the transaction succeeds, Polar will try to call our application to let us know that the transaction was successful
[10:17] or that the transaction failed. Now there's really no way for Polar, which is hosted in the cloud, to call our application, which is running on our local machine. So it can't call an endpoint sitting at local host 3000 as an example. So what we need to do is temporarily expose an endpoint that is publicly available. Is the webhook API endpoint that you have correct? Since we're using the BetterAuth plugin for Polar, BetterAuth will be dealing with everything related
[10:47] to these Polar webhooks. So please use context seven and our Polar documentation or our BetterAuth documentation to ensure that the API endpoint for the webhook is actually correct. All right, so by the way, this endpoint just changed. I noticed that this endpoint didn't actually go through Auth. So I'll ask Auth guy just to verify this and it seems to have fixed this endpoint now. All right, so how do we expose this dev instance to Polar? Well, for this we can simply use ngrok.
[11:19] Now this is actually really easy to set up. You can just sign in and follow the instructions. Then all you have to do is open up another terminal. I'm just going to rename this to ngrok. And then we can run ngrok, HTTP, and the path to our running dev server, which is on localized port 3000. And ngrok will now create this temporary URL that we can use to access our dev server. In fact, if I run this in the browser, we can subjectly call on visit site.
[11:49] And now we can access our application, which is currently running on our own machines. Now, of course, what we want to do is tell Polar where to access our dev server. So in our app, let's go to settings, let's go to waybooks, let's add an endpoint, then let's paste in that ngrok URL. And we can actually just reference our documentation. So we want to copy everything from front slash API all the way to waybooks, like so. I'll just move the camera so
[12:20] you can see the full thing. Then under format, let's select a role. And under events, we're only really interested in order created, updated, paid, and refunded. Then scroll down and click on create. Also, we can now copy the secret and then let's add that secret to our .env file. Now I do want to mention that if we start this ngrok server, we will have to start ngrok again, which will most likely generate a different public URL.
[12:51] So basically every time we want to test payments, so if you start up ngrok, grab this URL, and then update the URL in Polar. Now this is only applicable in the sandbox environment. It production will have a static domain for our app. Now all we need is our Polar Access Token. So what we can do is go to general, then under developers, click on new token, I'll just call this sandbox, and I'll let this token expire after 30 days. Then I'll just select all of these scopes
[13:22] and let's create this token. Then I'll copy the token and add it to our .env file. All right, so we are done with phase two. So let's have a look at phase three then. So we can just take a look at the implement the rest of these phases. So we'll clear the chat. Let's grab our feature folder and throw it into the chat and it say, we just implemented phase one and phase two. Please go ahead and implement phase three. Mark all the tasks in the implementation plan as complete once you're done and let's send this.
[13:54] So you would have noticed that I'll ask Cloud Code only to implement phase three. It's very important that we keep the context window as lean as possible. So I prefer to implement everything one phase at a time. So after implementing phase three, I'll clear the chat and then ask Cloud Code to continue with the next phase. I'll go through that process and I'll see you on the other side. All right, so Cloud Code just completed all of these phases and we're only left with this testing and validation phase. So one thing I like to do is after implementing all of these phases, I like
[14:26] to add this feature folder back in and ask both just to do a code review. Hey there, we just implemented all of these phases. Please can you go ahead and do a thorough code review and fix up any issues that you pick up. Okay, cool. So the code reviewer went through the solution and it actually made a few fixes. We've done a lot of work so far. So I am going to create a checkpoint just to commit all of these changes. And then let's actually test this out. So back in our app, we currently have 191 credits.
[14:58] So let's click on this button. We can also just go to the pricing page. Then let's try to purchase any of these packages. So let's try the basic package. Let's click on get started. Now we are correctly being navigated to polar. Now something doesn't look quite right to me. We're asked to enter our email and this should be inferred based on the email address that we're logged in with. And I think the reason is this user already existed in our system. So we already had that user over a year. So what I'm going to
[15:28] do is actually clear out all of our users so that our database and polar is in sync because in polar we don't have any customer records yet. A better auth is supposed to replicate that user record to polar as well. So a better auth will keep these users in sync. So another auth sign in, we can see that user record. And if we go to polar and refresh this, we can see that user in our polar dashboard as well. Cool, so now if we go to pricing,
[15:59] let's try to purchase a package. And now the email address is automatically populated for us. Now let's try to purchase some credits. So since we're in the sandbox environment, we can use this card number and then the expiration date can be any date in the future. And for the security code, we can just enter 123. Then I'll just select my country and let's click on pay. All right, so now we get this payment successful page. And at the moment I don't see an update to our actual credits. So let's try to refresh this page
[16:31] and I still don't see that update. So let's try to troubleshoot this. If we go to our database, we can see the credits for this user is still zero. And if we go to our dashboard and we go to sales, we can indeed see that $9 purchase. So the transaction definitely went through. So back in our app, let's have a look at our dev terminal. Here it seems like we actually have a failure. So what I'm going to do is copy all of these errors and let's say, hi there.
[17:02] So I've just tried to make a purchase using the Polar sandbox environment. I can see the customer record and the purchase reflecting in the polar dashboard, but the credits in our app was not updated for this user. And I can see these messages in the dev terminal and then they spaced in all that information and send this. All right, so let's test this fix and these credits are still not reflecting. And again, all we have to do is go to our dev server and see if we find any error messages.
[17:33] And now we get a different set of errors. So again, I'm simply going to copy all of this. Let's go back to Claude. All right, so I just retested your changes, but now we're getting this error. All right, so I had to repeat the process a few more times where I would attend to make a payment and I would then pass any error messages from the dev terminal to Claude. And eventually everything seems to work. I can now see we've got 90 credits. Let's actually try to purchase one more. Let's go for the pro package.
[18:04] So let's go to get started and let's enter these details and let's try to pay. We should now receive 100 credits. All right, so I had to manually refresh the page in order for the credits to reflect. So I'm just going to do one more thing. All right, so it seems we've resolved the issue. The payment process does seem to work now. Now I do want to add two more changes. Firstly, I noticed that after we purchased the credits, I had to manually refresh the page to see the actual credits.
[18:36] So can you maybe add some functionality to automatically refresh the credits? Secondly, when new users sign up, I want to allocate one free credit to their account. This should also reflect as a free credit in their transaction history. All right, so that seems to be working. I'm just going to test the functionality to see if that free credit is loaded when we sign in with a new account. All right, so I've just signed in with a new email address and we can see we do indeed have one credit.
[19:07] So I do want to add one more thing. Let's also say, all right, so we need to show the users their transaction history somewhere on their profile and users should also be able to access their Polar Portal where they can view things like their subscriptions and download invoices. And I'll just add the Polar documents. You can also use contact seven to retrieve up-to-date documentation on using Polar with better auth. All right, so while cloud is running, I actually just want to show you a few very cool things.
[19:38] So in the Polar dashboard, we can go to the customers page where we can view all of our customers along with the revenue generated by customer. Of course, we can also go to sales where we can view all of the purchases made and we can also view subscriptions. Now, if you wanted to give people discounts, you can go to products and discounts. And of course, the analytics page is also full of valuable info. All right, so we can now go to our profile page. In In-Year, we have this billing and payment section
[20:09] where we can view our transaction history and we can also click on this manage billing button which will take this user to their very own Polar Portal. And In-Year, they can view their previous orders as well. And this is valuable because this is where people will go to download their invoices. So now the payments are working, let's go ahead and deploy this to production. So the first thing we have to do is check that the code is indeed clean. So let's run the check bold command. This will simply run type check and lint and npm run bold.
[20:41] And now that the bold is done, let's create a commit. I'll just use my checkpoint command. And finally, let's push all of this to production. All right, so far we've been working in the sandbox environment in Polar. So what we need to do now is actually go to the main Polar site at polar.sh and let's sign into our account. Then let's create a new organization. Let's call this pacify AI. It's accepted terms and click on create. I'm going to skip the onboarding process
[21:12] and let's go to products. Let's create a new product. And really all we have to do is copy across all the values from the sandbox. I'll call it basic in prod as well. And for the description, I'll copy that across. For the pricing, this is a one-time purchase at a fixed price of $9. And let's create this. And then I'll just do the same thing for the other two products. And in production, we'll have unique product IDs. And these will be different to the product IDs
[21:43] that we have in dev. And the problem we have is that we've actually got these product IDs, are coded in this config file. Now these will work in dev, but they won't work in production. So I think what we should do instead is move this configuration to a database table. We could also move these to environment variables, but because we've got so many values to deal with, I think it's better just to store this in a database table instead. So I'm just going to clear the conversation. Let's pull in this config file.
[22:15] All right, so at the moment, we've got our product IDs hard coded in this config file. This will work if we only had one environment to deal with like development. But once we deploy to production, these product IDs will be different. So I think a better solution is to create a database table where we store all of these values. And then we have to use the database table to retrieve these values in our application. Over and above creating the database table, we should also be able to maintain these values
[22:46] using the platform admin pages. So in the platform admin section, create a page called products. And then allow me to maintain the values for these three products, including the product ID on that page. Remember, only users with a platform admin role should be able to maintain these values. So just to show you what I'm referring to is in the admin tutorial, we created this admin route. And only users with a very specific role
[23:16] are able to access those pages. In fact, when I tried to access that route now, I was redirected to dashboard. So what I need to do is go to that user in my database and change the platform role to admin. All right, so let's try this again. We can now access our admin panel and now we have this product manage consection. And in here we can see all of our products. Right, we now have an easy way to maintain the products in production. I just want to make sure that everything else still works. So I'm just going to
[23:47] try to purchase a package. And cool, we now have our credits. All right, cool, so let's create a commit for all of this. And let's push these to production as well. All right, so the bolt just completed. Now there's no point in trying to use our app because when we try to sign in, we won't get this better auth error. And that's because we haven't set up a folder yet. So what we have to do is go to our project settings, let's go to environment variables. And now we have to create three variables.
[24:17] We have to create a folder access token, polar webhook secret and the polar server. For the server, we'll set this to production. Now for the access token, let's go to polar, let's go to settings. Then at the bottom, let's go to developers. Then we'll set the name, we'll set the expiration. I'll just select all of these scopes and let's click on create. Then let's copy this key and add it to Vercel. Then for the webhook secret,
[24:48] again, under settings, let's go to webhooks. Let's add the URL to our website. And then we have to add slash API slash auth slash polar slash webhooks. For the format, let's select raw. Then for the events, let's select order created, updated, paid and refunded. And let's create this. Then let's copy the secret and add that to Vercel as well. Then let's save this and let's click on redeploy. Now, another thing we
[25:18] need to do at this point is remove all existing users from our database. So let's go to our database. Let's go to tables. Let's go to users. And I've removed all existing users from this database. And that is because when a user signs up, we need better auth to replicate that user to polar. So all existing users won't have as polar records. Cool, we're able to sign into our app in production and in our production polar instance,
[25:48] I can also see that user. Now, when we go to the pricing page, we actually won't see any products. And that's because we haven't created them yet. And if we try to go to the admin page, we're instantly redirected to dashboard. So what I'm going to do is in our production database, I'll simply find my user. Let's change the platform role to admin. Let's save this. Then let's go to product management. And now we don't have any products. So I'm just going to click on add product. And I'm simply going
[26:18] to replicate everything we have in dev. The only difference is we need to get the product ID from production. So again, back in polar, let's find our product and let's click on copy product ID. And let's add it to this field. And let's create this product. And let's continue adding the other two as well. And that's cool. So we've put all of our products in our production instance. And of course, if we go to our pricing page, we can see all of our products as well. But so let's try to purchase some credits.
[26:50] Let's go to basic. And this is saying the payments are currently unavailable. It's very important that back in polar, you complete this account setup process. So I'm simply going to continue with this and add in all my details. So this basically involves describing your business and telling polar what you plan to sell. So I'll just add something like this. And let's submit this for review. Then you have to select your payout account. So let's continue. So I'll select my
[27:20] country and set up account. And that's it. So I've just gone through the all setup process. Let's try to purchase this package. You can see that error message is now gone. And because we're no longer in the sandbox environment, we do have to provide an actual credit card. Now for testing, I don't really want to do that. So another way to test in production is you simply apply a 100% discount code. So back in polar, what we can do is go to products. We can go to discounts.
[27:52] Let's create a new discount code. I'll just call this demo. And the code I'll also call demo. And for the discounted percentage, let's make this 100%. Let's create this. Then let's apply the discount code. And now we run by a thing. Let's submit this. All right, so I actually had to debug this issue. I noticed that even after waiting a while, the credits actually never refreshed. And everything seemed okay in the polar dashboard. I can see that order. And if we go to sales and orders,
[28:26] we can see that order over here as well. But what I noticed in ingest in production is that we don't actually see that run. And if we go to events, we can see the event for order paid sitting here, but the function was never triggered. So this is quite important. As part of our polar integration, we added new functions to ingest to deal with processing payments. And if we go to functions, we actually don't see the new functions that we added. For comparison's sake,
[28:57] if I open up dev and we go to functions, we get this process purchase function. And this is missing from production ingest. So just keep that in mind. Whenever we make changes to ingest in dev, we actually have to re-sync our application in production. So what we can do is go to apps, then under these three dots, click on re-sync app. And let's click on re-sync app. And now that new function is available. So let's try again. Let's go to our package,
[29:27] our internet discount code. Let's submit this. And now we can see the credit was actually allocated. In fact, we received two bundles. And that is because both of these events ran. So I'm guessing the one that was stuck under events was successfully sent. So let's actually just try one more. Let's go for this 30 credit package. Let's apply the discount. Let's submit this. And there we go. We just received 30 credits. So this video and the series was a lot of effort to create.
[29:58] So if this helped you in any way, then please hit the like button and subscribe to my channel for more authentic coding tutorials. Also, let me know down in the comments if you've got any specific questions related to the series. Thank you for watching and I'll see you in the next one.