Integrate Paystack Payment Provider to Your Website via API - Nodejs (Nestjs) Example

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
this comment is from one of my previous NJ tutorials and it says please can you make a video on how to integrate payment method like pack floter wave Etc so I am making this tutorial for the person that dropped the comment and every other person that is interested in learning how to integrate payments in their web applications for this example we are going to use p t but but be rest assured that most of the things we are going to learn we apply to other payment providers Integrations so let's get started I will be taking a different approach in this tutorial instead of writing the code and explaining it along the way I want to focus on explaining the implementation because of this I already have the code that integrates pack but I will explain every step starting with the very basic things let's understand this controller transactions controller this controller has a few end points the first one is to initialize transaction this is the point that the user begins their payment Journey at this point what will happen is that we are going to call P stack you will see see in the actual implementation the controller is a bit dumb just calls the initialized transaction from transaction service so this is going to initialize the transaction and then we have endpoint for verify transaction this uh Slash transaction slash callback this is a common term in payment where we get um call back from the payment provider and we verify transaction using the information in that callback again this method is straightforward because it just cause the service in fact the service method is where we have the the mainting moving on to the next one we have this web hook end point this Endo is for another common um thing in payment this is for server to server communication between our application and the payment provider so there will be no user interaction in this communication for web hook p is going to call this endpoint to notify us about payment whether it is a successful payment or refund or whatever that happens p is going to call this endo and again in the controller we are not doing anything we just call the handle pest web Hook and the logic is there the implementation is there but there are few other things you have to note about this controller it will become clear during the demonstration so here we say HTTP code HTTP titles okay that is because by default um web hook endpoint expects that we respond with 200 status code but in next JS when you call a post end point it's going to respond with 2011 so I'm just telling it in this case I want you to respond to the payment provider with status code 200 and then here uh we have a regular stuff which is just to get the the request body from whatever uh pest is going to send and here similar to The Way We access the access the body we can access the headers so in the header pest is going to send a special header named this and this header is going to contain some hashed data which we are going to see how we are going to compute our own hash and validate um compare with the hash that P is going to send if everything is okay pest will quickly get uh a 200 response status if if not we just throw a bad request exception so that P knows that uh it didn't go well and finally this guy here is just for me to I just want to list all the transactions in my database so I'm going to uh call all these end points in a moment but let's move on to the next simple stuff the next simple thing is something that uh I'm thinking is not really necessary I could have just had coded some data for this demonstration but let me show you since I already have it I have two tables product and transactions in product I put whatever field I want to put there so this is not like a standard or a rule that your product table must have these three guys I have the ID I have product ID and I have the price which is stored as an integer take note of the price it is going to be inan or in our own case since it's p in cob so this is not this is going to be the amount plus the cents plus the Cobo part of it for example if if the price of the thing is 99 instead of 99 we say 99 0 0 because the last two is like like this decimal this is a standard that is also common if you prefer to treat it in a different way that's up to you you can do the conversion between API C between your application and the provider but it might be simple and straightforward to just store in the format that the provider expects I did not choose to store in Scent or Cobo whatever I prefer but because that is the standard API expects and uh for the transactions I have the primary ID call once again transaction reference I will be getting some most of this information from Pac and I want to have some of those information in my database this three for example and this just for something I choose to have here as where I want to keep it simple a payment status is either paid or not paid so this is an enum payment status and then product ID just a replica of the product ID as we have here this is my own structure you can your table can have whatever you want your table to have this is not really important now let's look at another simple thing before we go to the main implementation the D so as you already know I guess DT are just representation of the data we pass around in our application for example the D for initialized transaction I'm expecting only the product ID to be in the in the request data I don't add I don't have validations here I want to keep things simple and just go straight to the main topic can add validations and do all those usual stuff you used to do and for pack dto these are just representations of uh what I got from pack documentation for example to call pack API they expect not random data but data that follows their own specifications for example to initialize transaction it expects that there should be amount in Cent or Cobo anyone you prefer there should be email and then there should be optional Fields like cack URL we're going to uh see what all this represent a metadata field this metadata these are the fs I have in my own metadata and custom FS which are also these are also free FS you can store whatever you want to store there something that makes sense for for the transaction we are going to see an example what I chose to store in as meta as custom fields and um this order did your P create transaction so when we initialize a transaction we get a response from pack and this is the shape of that response I just picked the fs that I'm interested in in most of these okay there are other fields that pack expect as optional fi or send among the data that they send but I'm not really interested in those things I just pick what I need and then this is for verifying a transaction uh we have this controller for call back and when we get the thing called call back we want to verify transaction in the implementation we are going to see so this is the shape the shape of the data we are going to send to P tag for verifying transaction as they expect it to be and then we have the thing we call Web hook the server to server communication team and this is the shape of the data that P will send to us when they send that web hook so this data is broken down here by way I don't need most of these fields should have just removed I think I I used only the first few like three of them but I'll leave it there and then I have pesta callback D um this is the data this query param here callback and this query param this is this is data that P is going to send for call back remember we have the other one is for response to initialize transaction we have this one for cack and we have the other one for web hook and finally this is just my thing I want to Mark a payment a transaction as either paid or not paid keeping it simple and that's all for the Dil and I think we have covered all the B basic stuff uh one last thing is this okay I'll get to this as we use them but these are just Global constants you don't really need to uh are just Global constants let me leave it there so now we can go into the main implementation and look at them one after the other now let's take a look at the first step among these um transactions service methods and that is to initialize transaction this is the first step when the customer wants to pay and what does it look like I will go into the code before that let's see the documentation so we initialize transaction from the back end that's what this is saying and that makes sense and these are some of those fields I was talking about the data that you have to these are the required data and this is the structure of the response but what does this mean to initialize transaction we are just going to call pest API and say we want to initialize a transaction for this customer and this amount and along with that we can supply other fields these are the required fields and these are the optional Fields okay in my own case in the initialized transaction it takes the dto initialized transaction dto from there I am extracting the only few there which is the product ID and then I find the product from my database these are not really why way here I could have just had coded the product as well just like I had coded the user here but let's continue I find the product and I find a user or I had coded a user to demonstrate and then I prepare the payload that P is expecting and what is the payload the same payload that is described as body parameters here it requires email amount and other FS which are optional and which other FS are there I choose to pass metadata among all the there are various other FS but I just chose to pass meta data so you can see there so in my own metadata I just have some something that make sense to my transaction you can pass whatever you want to pass and all these are just for demonstration so here I'm passing the user ID product and the uh customer name customer email favorite color discount whatever you want to pass here at the end of the day you are going to get those information back or when you are checking the transaction you can see this information as you are going to see take note that this part will appear in the email the P we sent so you be careful what you are passing here whether you want the person that will get that email to have access to those information we're going to see that as well so at this point I have the payload I want to send to pay stack from the back end not from the uh client side and then we come to what is called um callback URL callback URL refers to the full URL that pack we have to call when customer has been redirected to payack to make payment and after that where does the customer go from that point if for example customer has made payment and successful what happens next so P we call this um end point with some data with some information it just a get request and when pest does that we verify that transaction so I'm telling P we are going to use this uh P callback URL by the way before we go further let me explain some environment variables that are necessary for this implementation um for my callback URL I have this as a placeholder so in your own case you're going to replace uh let's say example.com your website.com transactions which refers to this slash uh not really I made a mistake here it should be callback it should be call back not web hoop so transactions slash callback should be for the Callback URL and the next one is payack public key if you're already using past tack or even if you don't go to payack and create an account and go to the settings you are going to see your own public key and secret key of course make sure to keep those things secret and don't commit it to G or whatever you are using so you copy and paste your own public key and secret key from past T and that's is just all the uh things we need here now back to initialize transaction back to where we stopped I'll come down here what happens is that on payack the settings page you can specify a callback URL that becomes the default callback URL so if you don't specify any callback URL in your your code or in your request not necessarily your code in this request if you don't specify call back URL that default will be used so this is not really necessary but I just want to demonstrate to you that you can overwrite that default that was uh specified and P settings page that's what the thing is for and then um coming down here this is just a the request body you can call it payload you can call it param let me just call it payload so it doesn't sound like query parameters because this is a post request so just send the stringy the data by the way I'm stringifying because that's how past T wants it otherwise I would have just passed this uh past T create transaction DT straight to here and then we send the request I have a TR cat here because I am calling an exteral service and I can guarantee it's outside my control to guarantee that this external service will not throw any exception if it throws an exception I want to cash and handle that so we call pack endpoint here according to the API specifications and it requires us to call this URL API SLP st.co and whatever with the payload that is a string hence the just string F and the headers so this header is required the be token this be token is um your pack secret key which is the thing you are going to put in your in your secret place and then content type I don't know can't remember if this was really required maybe it was required hence me putting it there so uh when we call that API we get a result and this is just an exos exio Stu we grab the data from that result the shape of the data that P will return is already there in their documentation so if I go to the documentation uh when we initialize transaction we get this this kind of response and that is what I have here I have status message data so when I get that response what you will notice is that this authorization URL is a payment link as we are going to see in the demonstration it's a link that you can automatically redirect the customer to complete the to make payment however you want to use the link is up to you and that here I want to check uh because it will also return a status uh let's take a look here again so there will be a status field that is a Boolean to that's St just whether the request went fine and what I'm doing after that is to create a transaction record in my database at this point this transaction is going to is not paid yet nothing has happened I just initialized so in my database the status is going to be the default not paid and the transaction status this one from the provider is going to be null at the moment and all that so this is for initialized transaction we are going to try it out before we see the next steps one thing I forgot to mention is about the Callback URL when you go to pack um to set a callback URL for your application you will notice that you Cann not use HTTP like Local Host URL it must be https but I in in a local host environment and an application is is not running in HTTPS because of this I'm using a a service application what do I call it that is called um NG rock with NG Rock You Can map your Local Host URL to an https URL for free so what that means is that uh if someone calls this URL for example Local Host 3,000 or call this one they they're calling the same application so this is a differ in all together if your application is running with https you don't have to do all this but because like I said this is a local environment and I must satisfy the requirement that whatever URL I enter at pag whether it is callback URL or web hook URL as we're going to see must be https so I'm using this for that now um let me go ahead and call the initialized transaction end point by I already have my uh payack public key in EMV and my pack Secret in EMV I don't have to show you that and this EMV template is that when you get uh to your own code you can use this as an example and place your own values there let me start the application in debug mode in my database I already uh entered two products one is makeup tutorial the other one is baking lesson whatever over to postman I'm going to call the initialized transaction end point with the product ID so when I send this request um I put some some break points here so that we can see the data we got from PX so what has happened is that this end point was called without payload and in the initialized transaction a request has been sent to pack like I already explained and we got a response but what is inside that response inside the response you can see that we have this data uh like we we saw in the documentation authorization URL assess code reference payment reference whatever all this but what I need for now is this URL so I will let this continue and I will go back to postman here you can see that we got the result because we created a transaction in our database and returned it to see that if I go to I have this F transactions you can see this is what we have in the database so we initialize a transaction if it is your front end application that got this link you might want to automatically redirect the user to this URL so they can make payment but I'll visit the link manually from here now so this is going to take me to pack to make payment but because this is a testing environment just to simulate whatever you want to simulate whatever uh payment channel that you want to use I'm going to use card payment but before we make payment let's ask ourself what happens the moment I make this payment the moment I make payment the Callback URL will come into play so let's understand the Callback URL before making this payment let me remove this and stop theug now we talked about callback URL we say that after payment action with that's successful whatever I don't care uh what happens is that pest is going to call our callback URL and what it basically does is to send us the transaction reference and I think one other parameter which I'm not interested in it's going to send us the transaction reference in a field called reference with this transaction reference what we want to do is to call pest again to verify that transaction to verify means to check for example what is the status was it successful what other information and that is what this implementation is about before going through the code for that for verified transaction let's look at the documentation so we call the end point to verify transaction and what do we pass there the reference the reference field that pack we send as callback we already have this reference by the way we have it in our database already but P we still send it if you look here we have this transaction reference when we call the verified transaction endpoint we get a response so something similar to this but once again I only picked some fields that I'm interested in for this demonstration so back to the code what are we doing here first we find that transaction from our database using the reference remember we had that reference when we initialized transaction every other logic is up to you uh what you do if you don't uh find that transaction so let's leave this guy and go down the transaction is found then the next I want to do is to prepare the request to to send to Pac we have to call the verified transaction URL we just saw in the documentation passing the reference as a p par so this is the URL and then I'm using exos for my HTTP request I will send request to that URL and pass this headers this is according to the API specification I suppos to once again pass the pack secret key as a be token and when I do that I will get the response we just saw um in the documentation but I picking only the fields that I'm interested in and these are the fs that I am picking among all those information with that data I want to check uh if the payment was confirmed if it was successful so in the response data there's going to be a status field let me show you once again there is this status field so if it is Success then we know that the payment was successful that is what I am checking here if it was success the string success if it's success I want to set this transaction status to paid any other thing not paid I want to keep it that simple and then at this point I want to populate this transaction status field that I said is the one from payack and finally I will update that transaction record in the database so let's make the payment and see what happens here let me launch the application again and uh this end point will be called by pack when we make payment so I'll go ahead to pay I want to initialize another transaction I noticed that the Callback URL I entered was not correct that is my own callback URL that I entered on pack so I we leave the first one and initialize another transaction I'll just send the same request like before and then I will copy this and visit the URL so this is another transaction you will notice that uh the amount I entered in database was 1 2 3 4 0 0 but because it is in sense or in Cobo this is what that results to before I make this payment let me show you my pack um setup this is the settings page I was referring to I had to hide my public key and this is the the Callback URL I was talking about and this is another thing we call Web hook this is for the other end point that we are going to talk about but this is how just the URL to that end point in our code base this very one right here this web hook so when I make payment p is going to call this callback URL with an information let me go ahead and make the payment and pay the payment was successful and watch what happens we are brought to vs code because when you add this break point automatically when the code execution gets to that point vs code will open but if I go to the browser you will see that this is hanging it is hanging it called our endpoint call back URL but hanging for the code execution to continue I put this break point here because I want to show you the data that P sent as part of the Callback he just sent the reference and this other thing that I'm not using oh interesting is the same value so this is the reference this is transaction reference and so let me go to the code and continue the execution now I will go back to the browser and you can see that the end point was called This is SL transaction SL callback transaction reference and reference so if I go back now and check the status of that transaction this was the transaction when we created and returned it the status was not paid and the status there was nothing there but if I uh let me go here the ID is two so let me FH all the transactions for id2 you can see that the status we updated in our code to paid and this is the status we got from the payment Provider from Pac so this is the steps we have applied for verifying transaction and we are applying this uh verified transaction for for this callback you can use it for other purposes maybe you want to expose another endpoint you can have a form or somewhere in the front end where someone can inut transaction reference and verify that transaction and get the information about it now let's move on to the next thing which is web hook I talked a little bit about web hook we say it is for server to server communication between our own application and pack so um basically what happens is that when the payment is made Pac is going to call this end point for callback is going to redirect to this callback URL this is really helpful especially for a case where uh this callback has an issue or you don't really want to have this callback at all there could be other reasons but let's go to the implementation to see what happens here so what happens here is that pack is going to call the end point we specify as the as the web hook URL and when that happens best is going to send some payload uh once again I picked the fields that I'm interested in from that payload and a header a kind of special header this header is called X payack signature other payment providers might name their own header whatever they want if they use it so we need those two information in this service method called handle pest web hook here we want to validate to be sure that this uh web hook request came from pest otherwise uh if you go ahead to trust anything that CS your web hook endpoint by the way not that this is usually a public endpoint so there's no authentication anything protecting the end point and talking about authentication I decided to leave that out from what we are doing here so we can just focus on payment uh method integration so a request comes into the web hook we want to check that it is authentic and how we do that is this usually come in form of um hashed data there is going to be the plain data in the case of this pack there is a plane data that is this dto and then there is a hashed equivalence of that data so you can you can take a look on what is hashing and how it works and all that it's not our Focus here but this same payload is hashed and that hash is contained in the header and that header is what we grabbed here you are going to see what that looks like so let me add some uh break point for that I'm going to add one here so you'll see what those things look like and let me add another one for here so when we get the data and the hash what we are going to do is to use our pack secret and compute the same hash the hash in question is a hash of this uh of the data this D so what happens is that pack we use the secret key to create and send the hash so this dto is hashed and sent as a as a header then in our own code we are going to do exactly the same thing we create the hash of that dto Ash of the same data that is the DTU and when we create it if everything is okay they will give us the same value so we compare that value so let's say for example this hash after the whole hashing was done gave us something like this that is a hash when we create the same hash uh when we hash the same data with the same key we are going to get exactly the same thing there's any difference we are not going to get the same hash I don't know if you get the point but that is it so we create our own hash like this and then we compare 32 hash Mash how do we create a hash we use this uh create h mark that is from crypto from crypto nodejs package come on so we create the hash like this using our secret key and then we do comparison in a way that makes what is called timing ATT T more challenging so instead of a simple equal to instead of simply saying hash equals to Signature something like this hash instead of checking whether hash equals sign we use this timing save equals which is also from the crypto package um but this is left for the security expert to tell whether just doing it like this is okay but what does this do let's see it said that this function compar the online blah blah blah in a way that makes it more difficult for timing attack you can read the documentation that's what this thing is trying to do that's why we are not using a simple equality comparison and we do everything at a go so when we check and we have seen that this hash that pest sent us matches the hash we computed with the same exact data and the and this uh and the secret key if that is true we can say that this event or this uh web hook request came from Pac otherwise we say it didn't come from Pac okay we don't trust it but if you want to be a little extra careful after all this you can utilize our verified transaction uh implementation we already have a method to verify transaction and what does it take it just takes the payment reference so this web Hook is going to send a data that contains the payment reference inside this data there's going to be the reference so you can grab that payment reference if you don't trust your your hash verification and use it to call the verified transaction to retrieve that dat data straight from from the provider we have verified that this um web hook request came from Pac and we can thrust that data do with it whatever we want to do and what did I choose to do I found the transaction for that payment reference and I updated the transaction status uh where transaction status and and set the status to paid if this trans the transaction status is Success otherwise set it to not paid and that is just it so there's a whole lot on how web hook works and hashing and all those things but you can take your time to research and read more in depth what we're going to do now is to give this web hook thing a try although we can have both callback URL and web hook working um I just want to demonstrate the web hook only so that it doesn't confuse us whether it was through the Callback URL that we got the payment status and updated the records in our database because of this I'm going to remove this callback URL and make and save the changes I will also remove from my EMV the the overwriting I talked about about callback URL now let me go to postman and initialize another transaction so I'll send the request we have a new transaction this is the ID number three and this is the payment link I'll go to the payment link to make payment uh by the way before I make this payment let me show you the thing we talked about the request we send when we are initializing transactions I've made two two payments and for the first one you can see some of those the metadata field that we sent for example favorite color is in the email that I got from Pac the discount the email the name those information I passed there the same thing applies to to this second payment so let me go ahead and make this payment before I make the payment let's confirm the status from the database so the status for this guy with ID3 is not paid and there's no transaction status there as well then make the payment payment is successful you can see that once again because there was a request the web hook request came in the vs code automatically launched and if I go to the browser there is no redirect because we did not specify the Callback URL so we got this web hook and uh let's see what is inside it in this web hook we have the signature we talked about which is a hash of the data this uh thing I called D this signature is a hash of the data and this is the one that came from the payment provider and what we do from this point is to compute to create the hash and compare and that is what I've already explained here so we continue this execution we have computed our own hash and this is it here on hash here no that should be up here so when you look at these two things you can see that they are equal okay this is the hash we computed this is the hash from the provider that is called Signature the key is signature because they are equal we can say that this event this web hook request came from Pest and we proceed with processing that information further so let me continue this and the request is done there is no user interaction in the sense that pesta can decide to send this web hook in the next 5 minutes uh in the next one minutes whatever it doesn't necessarily mean that the user has to wait for the we hooks to happen it doesn't concern the user that made this payment so let's look further into this uh web hook thing to understand the hashing a little better I will go back to postman what I want to do is to simulate a case whereby uh someone just send some random stuff to the web hook endpoint this is the web hook endpoint I'm using Local Host 3,000 because this this is me calling the endpoint otherwise I'll have to use on the provider side we used https and the NG Rock URL stuff so I'll send this request and this is trying to mimic the pack header and this is trying to send some fake hash I'll send the request and we catch that in our breakpoint again and you can see this is the data this is the reference uh where is the hash yeah this is the hash at ient now when the hash is compared you notice that they are not the same thing so let me continue this execution you can see that this is my hash that is computed using the payload that I sent and the secret key but this is the hash that was computed uh using a wrong secret key so they are not the same and we cannot trust this web hook okay guys this brings us to the end of this lesson on how you can integrate payment uh methods in your web application please know that this is not really like uh the way you must do it but just to give you an idea you definitely want to be sure that everything is implemented and properly tested and safe and secure for a production application I hope this makes sense until next time enjoy coding
Info
Channel: ZestMade
Views: 634
Rating: undefined out of 5
Keywords:
Id: wn7Lxx5ugoo
Channel Id: undefined
Length: 47min 7sec (2827 seconds)
Published: Sat May 25 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.