This week I was working on PayPal integration in Serial Key Manager(http://serialkeymanager.com/). Some time I spent trying to understand how this can be accomplished using a server language, ASP.NET, since I have not been able to find a clear tutorial that would be easy to follow, So, in this guide I am going to outline how the entire process works and provide you with working examples!
1. Setting up the development tools
The first thing you need is to create a PayPal developer account so that you can access this page https://developer.paypal.com/webapps/developer/applications/myapps. When you press on Sandbox accounts to the left of the page, you will have the option to create two types of accounts: Personal or Business.
- Personal account will be used when you buy your product
- Business account is the account that will receive the payment from the Personal account.
Depending on how much your product will cost, you will have to insert an appropriate amount of money into the Personal account. I think you can have as much as you like since it is only for testing purposes.
2. Creating the button
Now, you will have to create two Views in a Controller, one where you have the button and one where you have the validation mechanism. Let’s start with the button! Put the code below into any View. My View name is IPN in the User controller.
<!-- When you are done with all testing and want to change to the real PayPal, use following instead--> <form action="https://www.paypal.com/cgi-bin/webscr" method="post"> <!-- end of Real PayPal example--> <form action="https://www.sandbox.paypal.com/cgi-bin/webscr" method="post"> <fieldset> <input class="full-width" type="hidden" name="business" value="<!--enter the Business account email here-->"> <input type="hidden" name="cmd" value="_xclick"> <input type="hidden" name="item_name" value="The unlimited music download subscription"> <input type="hidden" name="amount" value="9"> <input type="hidden" name="no_shipping" value="1"> <input type=hidden name=RETURNURL value="http://example.com/User/IPN"> <input type="hidden" name="return" value="http://example.com/User/IPN"> <input type="hidden" name="notify_url" value="http://example.com/User/IPN"> <button type="submit">Order now!</button> </fieldset> </form>
3. Processing the information returned by PayPal
The example code is based on this code. Please take a look at it to see how it is done with several variables.
Now you need to create a new View in the controller, called IPN. Insert the following code:
public ActionResult IPN() { var order = new Order(); // this is something I have defined in order to save the order in the database // Receive IPN request from PayPal and parse all the variables returned var formVals = new Dictionary<string, string>(); formVals.Add("cmd", "_notify-synch"); //notify-synch_notify-validate formVals.Add("at", "this is a long token found in Buyers account"); // this has to be adjusted formVals.Add("tx", Request["tx"]); // if you want to use the PayPal sandbox change this from false to true string response = GetPayPalResponse(formVals, false); if (response.Contains("SUCCESS")) { string transactionID = GetPDTValue(response, "txn_id"); // txn_id //d string sAmountPaid = GetPDTValue(response,"mc_gross"); // d string deviceID = GetPDTValue(response, "custom"); // d string payerEmail = GetPDTValue(response,"payer_email"); // d string Item = GetPDTValue(response,"item_name"); //validate the order Decimal amountPaid = 0; Decimal.TryParse(sAmountPaid, System.Globalization.NumberStyles.Number, System.Globalization.CultureInfo.InvariantCulture, out amountPaid); if (amountPaid == 9 ) // you might want to have a bigger than or equal to sign here! { if (orders.Count(d => d.PayPalOrderRef == transactionID) < 1) { //if the transactionID is not found in the database, add it //then, add the additional features to the user account } else { //if we are here, the user must have already used the transaction ID for an account //you might want to show the details of the order, but do not upgrade it! } // take the information returned and store this into a subscription table // this is where you would update your database with the details of the tran //return View(); } else { // let fail - this is the IPN so there is no viewer // you may want to log something here order.Comments = "User did not pay the right ammount."; // since the user did not pay the right amount, we still want to log that for future reference. _db.Orders.Add(order); // order is your new Order _db.SaveChanges(); } } else { //error } return View(); } string GetPayPalResponse(Dictionary<string, string> formVals, bool useSandbox) { string paypalUrl = useSandbox ? "https://www.sandbox.paypal.com/cgi-bin/webscr" : "https://www.paypal.com/cgi-bin/webscr"; HttpWebRequest req = (HttpWebRequest)WebRequest.Create(paypalUrl); // Set values for the request back req.Method = "POST"; req.ContentType = "application/x-www-form-urlencoded"; byte[] param = Request.BinaryRead(Request.ContentLength); string strRequest = Encoding.ASCII.GetString(param); StringBuilder sb = new StringBuilder(); sb.Append(strRequest); foreach (string key in formVals.Keys) { sb.AppendFormat("&{0}={1}", key, formVals[key]); } strRequest += sb.ToString(); req.ContentLength = strRequest.Length; //for proxy //WebProxy proxy = new WebProxy(new Uri("http://urlort#"); //req.Proxy = proxy; //Send the request to PayPal and get the response string response = ""; using (StreamWriter streamOut = new StreamWriter(req.GetRequestStream(), System.Text.Encoding.ASCII)) { streamOut.Write(strRequest); streamOut.Close(); using (StreamReader streamIn = new StreamReader(req.GetResponse().GetResponseStream())) { response = streamIn.ReadToEnd(); } } return response; } string GetPDTValue(string pdt, string key) { string[] keys = pdt.Split('\n'); string thisVal = ""; string thisKey = ""; foreach (string s in keys) { string[] bits = s.Split('='); if (bits.Length > 1) { thisVal = bits[1]; thisKey = bits[0]; if (thisKey.Equals(key, StringComparison.InvariantCultureIgnoreCase)) break; } } return thisVal; }
PayPal provides you with many variables, so I suggest that you take a look at how the response looks like. When you’ve found a value that you would like to save into the database, use the GetPDTValue function to retrieve that value.
Please note down the Activation token found in the Buyers account in Profile>My Selling Tools>Website preferences> Update. Then, enable auto return and payment data transfer. There, you will also find the Activation token which you should add to:
formVals.Add("at", "this is a long token found in Buyers account");
Nice tutorial… How to test this solution?
Is it particular component you would like to test or the entire solution?
For testing, please use the sandbox mode by changing the specific boolean flags.
I am implementing a similar function for my client but got stuck, about “business” field value, I can use “robinxxx-facilitator@gmail.com” on sandbox, should I use my formal account (ex: robinxxx@gmail.com) on production? Does Merchant account ID also works on production?
Thanks for any feedback.
Unless you are in sandbox, I would suggest that you use your real account. In sandbox, you can make up any account; as far as I know, no email verification is required in sandbox.
The answer to your question regarding “business” field: At this point, I’ve only tried using the formal account email address in that field. It might work with merchant ID to, however, I’m not sure.
Please let me know if you have other questions!
How can i capture a payment with status “authorization”? And about cancel it?
I haven’t tried this out but I would recommend following links:
IPN Intro here you will see the variables that PayPal sends to the websiite (once you find the one you need, it can be easily collected)
Authorization and capture
plz give answer quickly it is urgent
Where it says “<!–enter the Business account email here–>”.
Hey thank you so much for this tutorial. I am still learning my way with MVC, so a tutorial like this one really makes things easier for me.
If I’m correct, should the behavior of this “order now” button when clicked be that it pulls up the paypal (or sandbox) page for the payment that is specified? For some reason when I click the order now button, it just throws me back to the default view in my controller(/peyments/index). Do you have any ideas on why this might be failing?
Thanks again
Hi!
Correct, the “order now” button should navigate the user to the PayPal’s live or sandbox environment. I can’t really see why it would send you to the default page of the controller; could you please show me the code of that form?
/Artem
Hello Thanks for this article, can you please share the complete source code, i.e. up and running.
Hi!
I am happy you liked the article! Unfortunately, I am not able to do so at the moment because I don’t have a sample project containing just this example.
Please let me know if there is anything in particular you need help with! 🙂
/Artem
Hello, how i can change the currency?
Hi! Based on a quick Google search, I found this post: http://stackoverflow.com/questions/8245568/paypal-ipn-unable-to-change-currency-type-from-usd-to-gbp.
So, simply add this into the form (which will change from USD to GBP).
Hope this helps.
Hello,
As a MVC learner love this grate tuitorial.can i know why you use hidden values for that ?
Eg:
You mean amount 9 is USD 9 ? or something.. ??
Correct! It’s 9 USD.
Please see my comment above for a way to change the currency!
Hi thanks by your tutorial,
I just have a doubt related to formVals.Add(“tx”, Request[“tx”]);
What is the meaning of Request[“tx”], where it comes ?
Thanks in advance
Carlos Vieira
I have same question. Please help
Great article regarding paypal payment…
I have a question regarding the response from paypal to user’s website, i have implemented this code for testing the payment i am using sendbox at the moment, but when the payment is successfully collected by paypal with a dummy card, it redirects to my website but the response that i get from paypal says “Fail\n”.
Can you please tell me how to get a successful response?
Why the response is getting fail whereas the payment is successfully done on paypal.
Thanks
Hi!
Not sure I know the answer. Could you please try to use Payment Forms (https://serialkeymanager.com/PaymentForms)? There, you can create a payment processor for paypal and later manage all the transactions from one place. No server side code needed! 🙂
/Artem
Hi the activation token is not there. I just have one paypal account. it wasn’t where you said it would be. i guess they moved it?
Nevermind my previous question. I’m developing on my local IIS. I can’t provide a public url for pdt. what can I do?
Hi ! Awesome article but my response says fail even after successful transfer.
I think the problem is in these fields
formVals.Add(“cmd”, “_notify-synch”); //notify-synch_notify-validate
formVals.Add(“at”, “this is a long token found in Buyers account”); // this has to be adjusted
formVals.Add(“tx”, Request[“tx”]);
From where I can get these values??? Please help its urgent,
Hi ! The response that i get from paypal says “Fail\n”.
Can you please tell me how to get a successful response?
Why the response is getting fail whereas the payment is successfully done on paypal.
Thanks. Please help me. I followed the same code you have shared.