Santry Technology Solutions, Content Management, DotNetNuke, SharePoint Consulting
Register | Login
Tuesday, December 02, 2008

Sections
  
About Us
  
Partners
Downloads
  
 WWWCoder.com Resource Directory

Create a PayPal Instant Payment Notification (IPN) Handler
3/2/2004 3:19:47 PM

It's easy to accept payments and respond to successful transactions using PayPal's IPN system. Use this code to get started verifying payments to your ASP.Net application and respond once the transaction is complete.

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.

  1. Your customer goes to your site to purchase an item.
  2. 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.
  3. This sends the customer to PayPal's site so they can pay for the transaction.
  4. Once the customer completes the transaction you then send them to a thank you page or some other page you specify.
  5. PayPal's system then verifies the transaction, and then notifies your IPN handler whether or not the transaction was successful or not.
  6. 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
    Response.Redirect(strPayPalURL)
  End If
End Sub

Now that we have the code to send PayPal the information we need to set up three pages:

  1. 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.
  2. 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.
  3. 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:

Imports System.Net
Imports System.IO

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 String

Dim 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)
RequestStream.Close()
'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)
      Case "Completed"        
        ' 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.
   End Select
 End If
 myResponse.Close()
End If
End Sub

You can download the SDK for the IPN from PayPal and expand upon this code for your own applications.

Update:

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
        End Function


Page Options:
format for printing  Format for Printer
email article  Email Page
add to your favorites   Add to Favorites
How would you rate the quality of this content?
Poor - - Excellent
Comments?
Overall Rating:
Comments Left:
Left on 5/9/2008 5:24:33 AM by Anonymous
Comments: good but still problem
i am using asp.net and get following error message:
"underlying connection was closed: Unable to connect to the remote server."
any help?
Left on 4/26/2008 10:48:13 AM by Anonymous
Comments: what is the getdomainname procedure doing in the above code?
Left on 9/12/2007 12:13:42 AM by Anonymous
Comments: Very helpful, thanks!
Left on 1/21/2007 6:47:45 PM by Anonymous
Comments:
Left on 11/4/2006 5:05:32 PM by Anonymous
Comments: Is there a typo in the code for the HTTPPOSTEncode function?  I think the first strPost assignment should be strPost = Replace(strPost, "\", "'")?.
See, for example, a similar function at http://www.bluevisionsoftware.com/WebSite/TipsAndTricksDetails.aspx?Name=PayPal#PostingBack. 

Many thanks to the author for this helpful code.

Left on 5/1/2006 2:48:11 PM by Anonymous
Comments: Ok, I used this code and it worked great, except it kept producing INVALID transaction responces.  I tinkerd with it for a while then realized, this code is only set up for production environement and not the SANDBOX.  So if you are just developing against the sandbox, simply replace the WebUrl you are sending to with http://www.sandbox.paypal.com/cgi-bin/webscr 

After I did this, everything went smooth as silk.  Another point of advice, when you are creating the pageload event handler, you must declare all the variable.  This is not shown above. 

Again, with just a few tweeks this code works well.
Thank you to the poster.
Left on 2/16/2006 6:30:07 AM by Anonymous
Comments: This is a great help provided by u.
Thanks
No ratings available.
Left on 8/30/2005 12:06:21 PM by Anonymous
Comments: Everything seems fine, but I cannot make it work cause I am getting the following error:
System.Net.WebException: The remote server returned an error: (501) Not Implemented. at System.Net.HttpWebRequest.CheckFinalStatus() at System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult) at System.Net.HttpWebRequest.GetResponse() at wrkspace.ipnvb.Page_Load(Object sender, EventArgs e)

Does anybody encounter the same problem?
Any suggestions would be appreciated.
Left on 8/20/2005 1:36:09 PM by Anonymous
Comments: Very well explained
Left on 7/8/2005 5:51:17 PM by Anonymous
Comments: This is the worst code ever to be posted on this site, it never worked
No ratings available.
Left on 3/26/2005 1:03:58 PM by Anonymous
Comments: The only VB.NET explanation for doing this that I've yet seen.
No ratings available.
Left on 11/24/2004 5:54:54 PM by Anonymous
Comments: Is the COMPLETE code for the Page_Load event available?  Thanks!
Left on 11/24/2004 5:47:52 PM by Anonymous
Comments: In the second to last code snippet, what are the variables WebURL and strToSend?
Left on 9/25/2004 1:29:43 AM by Anonymous
Comments: where can i download code from ??
No ratings available.
Left on 9/14/2004 2:07:18 PM by Anonymous
Comments: Code is incomplete and has errors, very poor job at explaning the code, his example has cause more frustration then before I read it
Left on 7/12/2004 12:33:16 AM by Anonymous
Comments: HTTPPOSTEncode saved the day! I was having serious problems without it. Thanks.
Left on 7/2/2004 5:58:00 PM by Anonymous
Comments: Where could i find the c# one ..i can read VB..but not to good..
Left on 6/30/2004 6:02:21 PM by Anonymous
Comments: Excellent article!  where can I download the complete source code?  Thanks.
No ratings available.
Left on 5/12/2004 7:05:12 AM by Anonymous
Comments: The article has been updated with the HTTPPostEncode method.
No ratings available.
Left on 5/11/2004 9:56:18 PM by Anonymous
Comments: Thanks for making a complete example available. I would appreciate if you can add description on HTTPPOSTEncode. It appears that other folks understand what that is, but a newbie like myslef wonder if it is one of the function you wrote or it is available by "Imports" ing sokmething.

Again, I appreciate very much for the code with helpful comments. I will look forward your further guidence.
Left on 5/6/2004 5:00:34 PM by Anonymous
Comments: Great article!  I need to set up Paypal for a client in the very near future.
Left on 5/6/2004 12:01:37 AM by Anonymous
Comments: Here's the SDK link: https://www.paypal.com/sdk
Left on 5/3/2004 1:11:58 PM by Anonymous
Comments: So glad to find this. I am an inexpereienced .NET developer and help code is always great to find.
Thank you.
Left on 5/1/2004 11:56:43 PM by Anonymous
Comments: Had to do lots of editing to get this to work and still was not able to.
Left on 4/30/2004 9:49:04 AM by Anonymous
Comments: Here's the link to the new document: https://www.paypal.com/us/cgi-bin/webscr?cmd=p/xcl/rec/ipn-manual
No ratings available.
Left on 4/30/2004 9:44:11 AM by Anonymous
Comments: URGENT -- The SDK link gives this message:
You have requested an outdated version of PayPal. This error often results from the use of bookmarks. To enter the PayPal website please click on the Welcome tab.
If you are already logged in, please click on the My Account tab to continue.
No ratings available.
Left on 4/30/2004 6:31:49 AM by Anonymous
Comments: Uh, yeah the article mentions the SDK, and provides a link as well.
No ratings available.
Left on 4/30/2004 2:05:05 AM by Anonymous
Comments: There is a PayPal ASP.NET SDK which includes code for handling IPN in addition to Web Controls for PayPal buttons.  Login to your PayPal account and goto development tools section to find more info.
Left on 4/26/2004 10:16:18 AM by Anonymous
Comments: what is HTTPPOSTEncode()???
Left on 3/5/2004 8:51:51 PM by Anonymous
Comments: I wish I sawthis before I bought my last PayPal Control. The description here is easier to understand than the control
  

 Latest Articles
  

 Latest News
  

 

Spotlight
Syndication

 


 


Digg This
 


DotNetNuke Platinum Benefactor

  
 

 Terms Of Use | Privacy Statement
 Copyright 2008 - Santry Technology Solutions, Box 172, Girard, PA 16417, (814) 774-0970