I'm sure most of you are familiar with PayPal, with the explosion of eBay over the past couple years, many people use PayPal as a means to transfer funds for online purchasing of goods. In this article we will discuss PayPal's Instant Payment Notification (IPN) system and how you can create transactional Web pages that respond to a successful payment notification from PayPal.
Before we delve into the code let's go over the IPN process.
- Your customer goes to your site to purchase an item.
- They click on some link, button, or some other element to trigger an event for the purchase. Within your code you will redirect the user to PayPal, and provide some information about your account and the product being purchased inside hidden form fields. This information will contain the product name, and price for the purchase. In addition, you can specify some optional information to be sent to PayPal as well.
- This sends the customer to PayPal's site so they can pay for the transaction.
- Once the customer completes the transaction you then send them to a thank you page or some other page you specify.
- PayPal's system then verifies the transaction, and then notifies your IPN handler whether or not the transaction was successful or not.
- Your IPN handler then performs the appropriate action based on the values returned by PayPal, ex: send an email for a download, create a subscription for a Website service, etc.
In this first block of code we will respond to some click on a button within an ASPX page. You'll notice that we build a query string that contains all the information that PayPal requires in order to handle the transaction.
Private Sub PurchaseBtn_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles cmdPurchase.Click
If Page.IsValid Then
' build secure PayPal URL
Dim sBaseURL As String = IIf(Request.ApplicationPath = "/", "", _
Request.ApplicationPath) & "/PayPalIPN"
Dim strPayPalURL As String = ""
' strProcessorId is your PayPal account name.
strPayPalURL = "https://www.paypal.com/xclick/business=" & HTTPPOSTEncode(strProcessorUserId)
' strProductName is the name of the product you want displayed to the user on the payment screen.
strPayPalURL =+ "&item_name=" & HTTPPOSTEncode(strProductName)
' An item number for your product.
strPayPalURL =+ "&item_number=" & HTTPPOSTEncode(strItemNumber)
' Quantity that the user is purchasing.
strPayPalURL =+ "&quantity=1"
' Custom can be any value you want, here we are passing the user account for the site.
strPayPalURL =+ "&custom=" & HTTPPOSTEncode(Context.User.Identity.Name)
' The price of the product.
strPayPalURL =+"&amount=" & HTTPPOSTEncode(strPrice)
' Optional currency type for the transaction.
strPayPalURL =+ "¤cy_code=" & HTTPPOSTEncode(lblTotalCurrency.Text)
' Where do you want the customer to go once they pay for the item?
strPayPalURL =+ "&return=" & HTTPPOSTEncode("http://" & GetDomainName(Request))
' This is for redirecting to a cancel page if the customer decides to cancel the purchase.
strPayPalURL =+ "&cancel_return=" & HTTPPOSTEncode("http://" & GetDomainName(Request))
' this is where you want PayPal to send the IPN to.
' You can also use the default one configured via the
' PayPal site, but this allows you to specify a dynamic URL for accepting the IPN.
strPayPalURL =+ "¬ify_url=" & HTTPPOSTEncode(sBaseURL & "/PaymentNotify.aspx")
strPayPalURL =+ "&undefined_quantity=&no_note=1&no_shipping=1"
' redirect to PayPal
Now that we have the code to send PayPal the information we need to set up three pages:
- The Cancel Page. We not going to cover this here. This page can contain some kind of message to the user or send them back to your site.
- The Thank You Page. Again, this page we don't do anything special. At this point we do not know if the transaction was successful, we won't know this until PayPal sends a message to our IPN handler page.
- The IPN Handler. This is where we do the bulk of our application logic. This page is going to accept the request from PayPal, validate the request, ensure the values are correct, and then do some action like send the user an email with a download link.
The IPN Handler
This is the page that is the bulk of the application. In this page we are going to handle the information from PayPal. We will verify the information from PayPal to make sure it is coming from PayPal, check the transaction information to see if the payment was complete. We will then check the transaction amount from PayPal to make sure it matches up with the amount for the product, then send the user an email notifying them of a successful transaction.
We will create a PayPalNotify.aspx for receiving the IPNs. In the code behind we'll first include a couple namespaces:
PayPal is going to send an HTTP Post to this page, so we need to handle the post values coming in and then post it back to PayPal for verification. In the Page_OnLoad event we'll accept the parameters and assign them to variables. Then we'll send this information back to PayPal for verification.
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' assign posted variables to local variables
Receiver_email = Request.Params("receiver_email")
Item_name = Request.Params("item_name")
Item_number = Request.Params("item_number")
Quantity = Request.Params("quantity")
Invoice = Request.Params("invoice")
Custom = Request.Params("custom")
Payment_status = Request.Params("payment_status")
Pending_reason = Request.Params("pending_reason")
Payment_date = Request.Params("payment_date")
Payment_fee = Request.Params("payment_fee")
Payment_gross = Request.Params("payment_gross")
Txn_id = Request.Params("txn_id")
Txn_type = Request.Params("txn_type")
First_name = Request.Params("first_name")
Last_name = Request.Params("last_name")
Address_street = Request.Params("address_street")
Address_city = Request.Params("address_city")
Address_state = Request.Params("address_state")
Address_zip = Request.Params("address_zip")
Address_country = Request.Params("address_country")
Address_status = Request.Params("address_status")
Payer_email = Request.Params("payer_email")
Payer_status = Request.Params("payer_status")
Payment_type = Request.Params("payment_type")
Notify_version = Request.Params("notify_version")
Verify_sign = Request.Params("verify_sign")
strToSend = Request.Form.ToString()'Create the string to post back to PayPal system to validate
strToSend &= "&cmd=_notify-validate"'Initialize the WebRequest.Dim PostMode As String = "2"Dim WebURL As StringDim SdHost As String'//* 1 = Live Via PayPal Network Non-Secure'//* 2 = Live Via PayPal Network SSL-Secure'//* 3 = Test Via EliteWeaver UK Non-Secure'//* 4 = Test Via EliteWeaver UK SSL-Secure If PostMode = "1" Then'// Live Via PayPal Network Non-Secure
WebURL = "http://www.paypal.com/cgi-bin/webscr"
SdHost = "www.paypal.com"ElseIf PostMode = "2" Then'// Live Via PayPal Network SSL-Secure
WebURL = "https://www.paypal.com/cgi-bin/webscr"
SdHost = "www.paypal.com"ElseIf PostMode = "3" Then 'strictly for testing!!!'// Test Via EliteWeaver UK Non-Secure
WebURL = "http://www.eliteweaver.co.uk/testing/ipntest.php"
SdHost = "www.eliteweaver.co.uk"Else'// Selected PostMode was Probably Not Set to 1, 2, 3 or 4
Response.Write("PostMode: " & (PostMode) & " is invalid!")End If
Now we'll take our values and post them back to PayPal.
Dim myRequest As HttpWebRequest = CType(HttpWebRequest.Create(WebURL), HttpWebRequest)
myRequest.AllowAutoRedirect = False
myRequest.Method = "POST"
myRequest.ContentType = "application/x-www-form-urlencoded"
'Create post stream
Dim RequestStream As Stream = myRequest.GetRequestStream()
Dim SomeBytes() As Byte = Encoding.UTF8.GetBytes(strToSend)
RequestStream.Write(SomeBytes, 0, SomeBytes.Length)
'Send request and get response
Dim myResponse As HttpWebResponse = CType(myRequest.GetResponse(), HttpWebResponse)
If myResponse.StatusCode = HttpStatusCode.OK Then
'Get the stream.
Dim ReceiveStream As Stream = myResponse.GetResponseStream()
Dim encode As Encoding = System.Text.Encoding.GetEncoding("utf-8")
'send the stream to a reader.
Dim readStream As StreamReader = New StreamReader(ReceiveStream, encode)
'Read the result
Dim Result As String = readStream.ReadLine()
If Result = "INVALID" Then
' The result was invalid so send a failure notice or some other handling.
ElseIf Result = "VERIFIED" Then
Select Case (Payment_status)
' The payment has been completed and the
' funds are successfully in your account balance.
' Add code for emailing user. First check your database
' to make sure the price that was sent to PayPal
' is the same price as your product.
' This will prevent people from URL tampering with your price.
You can download the SDK for the IPN from PayPal and expand upon this code for your own applications.
Several comments have been placed here asking me what is HTTPPostEncode. The code from this article is pulled from an implementation on DotNetNuke. DotNetNuke provides the method HTTPPostEncode, basically this is to replace any backslashes in the directory path to something a bit more friendly for posting. Below is the HTTPPostEncode method.
' encodes a URL for posting to an external site
Public Function HTTPPOSTEncode(ByVal strPost As String) As String
strPost = Replace(strPost, "\", "")
strPost = System.Web.HttpUtility.UrlEncode(strPost)
strPost = Replace(strPost, "%2f", "/")
HTTPPOSTEncode = strPost