Design and Implement a PayPal IPN Handler Using Code Rocket

This article will provide an overview of using the Code Rocket plugin for Visual Studio and Eclipse for designing and implementing a PayPal Instant Payment Notification (IPN) Handler. The article will cover specifying and capturing the IPN requirements, tracing them into a system design and implementing them in code. Figure 1 below provides a flowchart overview of the IPN process. Note: click on images to view larger sizes

Flowchart overview of PayPal IPN Processing

 Figure 1. Flowchart overview of PayPal IPN Processing

Contents

PayPal Instant Payment Notification (IPN) Overview

One of the payment processing options PayPal provides is Instant Payment Notification (IPN). When customers place orders at your web site you can submit their basket contents to PayPal. Through PayPal customers can then use a credit card or their PayPal account to pay for the items in the basket. During its payment processing stages PayPal sends a notification back to you to confirm when a payment has been received by a customer so you can perform any completion of the associated order as necessary, e.g. you can dispatch the products being purchased. When you create an account with PayPal you can provide them with a link to a URL to send the IPN notification to. Upon completion of payment PayPal will send information to this URL, summarising the order. This will usually be in the form of a set of HTTP Form fields containing the order information, e.g. the payer’s email address, the amount paid, etc.

IPN Processing : “Handshake”

When you receive the IPN notification from PayPal you need to perform a 'handshake' with them to confirm the validity of the data which has been provided and to ensure that the data wasn't intercepted and altered by someone else, e.g. to alter the payment amount or the PayPal account into which the payment has been sent. To perform the handshake with PayPal you need to:

  • extract the data from the Form fields PayPal provides you (typically extracted into a string);
  • append a code to the end of this string which informs PayPal that a data verification is being requested (the code is "&cmd=_notify-validate");
  • send all of the data back to PayPal again to request them to confirm its validity.

The handshake is typically performed using an HttpRequest to send and receive data synchronously to a server/url behind the scenes, i.e. you aren't using typical page post backs, etc. Streams are used to send data and receive a response. PayPal will send back a response to this request which will be a string containing a code confirming that they have verified the data as originating from them. If the response string is "VERIFIED" then things are ok.

IPN Processing: Order Verification

Once you have completed the ‘handshake’ with PayPal and received a “VERIFIED” response you can inspect the IPN data that PayPal has provided you with to process and complete the associated customer order. There are several checks which typically need to be made at this stage, e.g. make sure that the email address of the seller (the person receiving funds) is yours and not someone else, make sure the amount paid to you is as expected, make sure the payment status is recorded as ‘complete’. PayPal go through various stages of processing during which time they may send intermediate messages to you before payment is complete. PayPal also state that you may receive the notification more than once. You are expected to account for this in your processing to ensure you don’t end up processing the same order more than once.

IPN requirements summary in Pseudocode

I’m going to use Code Rocket to capture some of these requirements for the IPN handler in pseudocode form. The requirements are thus:

receive PayPal ipn data

extract ipn data into a string

append PayPal verification code to end of string

create an HttpRequest channel to perform handshake with PayPal

send data back to PayPal to request verification

receive response from PayPal

if PayPal response is successful / verified
  paypal has verified the data, it is safe for us to perform processing now
    
  extract the form fields expected: buyer and seller email, payment status, amount
    
  if the payment status is complete
    if the seller email is us (we don't want anyone else getting our payment!)
      if the amount received is as expected
        complete order processing
      else
        don't process the order, invalid amount
      EndIf
    else
      don't process the order, invalid seller
    EndIf
  else
    payment not complete yet, may be undergoing additional verification or processing
	    
    do nothing - wait for paypal to send another IPN when payment is complete
  EndIf
EndIf

Implementing the IPN Handler

The IPN design requirements can be captured using Code Rocket’s Stand-Alone designer (for up-front design, code forward engineering and legacy code inspection) OR using the plug-in to Visual Studio or Eclipse. For this sample, I’m going to start by using the Visual Studio plugin and implement the IPN Handler within an ASP.NET web application.

Creating a web application

Create an ASP.NET web application in Visual Studio 2008 (using C# CodeBehind) named ‘PayPal Backend’. Steps:

  1. File > New > Project
  2. In the ‘New Project’ screen select ‘Web’ under Visual C# Project types, and ‘ASP.NET Web Application’ as the template to use.
  3. Give the Project a name, e.g. ‘PayPal Backend’ and click OK.

Add a web form for the PayPal IPN Listener

I’m going to add a page to the application to act as a listener / url for receiving PayPal IPN notifications. Steps:

  1. Right-click on the ‘PayPal Backend’ project in the Solution Explorer
  2. Select Add > New Item
  3. Select ‘Web Form’ as the item to create and name it “PayPalIPNListener.aspx” – or maybe something less obvious for uploading to a public site.
  4. Click OK.

Handle IPN logic in the Page_Load

I’m going to invoke most of the PayPal logic required in the Page_Load event of the new web form. In ‘Design View’ for the Web Form, double click the design canvas to create a Page_Load event in the Code Behind File (PayPalIPNListener.aspx.cs). Inside the Page_Load event I will invoke a handler for the IPN processing. I have created a method stub for this.

namespace PayPalBackend
{
  public partial class PayPalIPNListener : System.Web.UI.Page
  {
    /// <summary>
    /// Use the Page_Load event to perform PayPal IPN processing
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    protected void Page_Load(object sender, EventArgs e)
    {
      // invoke handler to process the IPN information
      ProcessPayPalIPNNotification();
    }

    /// <summary>
    /// Process an incoming Instant Payment Notification (IPN)
    /// from PayPal, at conclusion of a received payment from a
    /// customer
    /// </summary>
    private void ProcessPayPalIPNNotification()
    {
    }
  }
}

Capture the design requirements with Code Rocket

Click on the method body of the IPN processing handler to make it current in Code Rocket’s design views. In the Pseudocode Editor, enter / copy the pseudocode design requirements that were captured above. See Figure 2 below.

Flowchart overview of PayPal IPN Processing

 Figure 2. Capture design requirements using Code Rocket's Pseudocode Editor.

You can also refer to Code Rocket’s Diagram View to view a flowchart type representation for the design requirements. See Figure 3.

Flowchart overview of PayPal IPN Processing

 Figure 3. View or edit the design in Code Rocket's Diagram View.

Forward engineer the requirements into Code

Click the ‘Commit’ button in the Pseudocode Editor and it will create a well commented, well formatted code skeleton to match these design requirements.

/// <summary>
/// Process an incoming Instant Payment Notification (IPN)
/// from PayPal, at conclusion of a received payment from a
/// customer
/// </summary>
private void ProcessPayPalIPNNotification()
{
  // receive PayPal ipn data

  // extract ipn data into a string

  // append PayPal verification code to end of string

  // create an HttpRequest channel to perform handshake with PayPal

  // send data back to PayPal to request verification

  // receive response from PayPal

  // if PayPal response is successful / verified
  if ()
  {
    // paypal has verified the data, it is safe for us to perform processing now

    // extract the form fields expected: buyer and seller email, payment status, amount

    // if the payment status is complete
    if ()
    {
      // if the seller email is us (we don't want anyone else getting our payment!)
      if ()
      {
        // if the amount received is as expected
        if ()
        {
          // complete order processing
        }
        // else
        else
        {
          // don't process the order, invalid amount
        }
      }
      // else
      else
      {
        // don't process the order, invalid seller
      }
    }
    // else
    else
    {
      // payment not complete yet, may be undergoing additional verification or processing

      // do nothing - wait for paypal to send another IPN when payment is complete
    }
  }       
}

Completing the Code

I'm now going to start filling in the code to address these design requirements - see below. NOTE: I'm just going to provide a basic, generic solution. You would obviously have to customise this to suit the needs of your own site, including any additional exception handling and data validation.

/// <summary>
/// Process an incoming Instant Payment Notification (IPN)
/// from PayPal, at conclusion of a received payment from a
/// customer
/// </summary>
private void ProcessPayPalIPNNotification()
{
  // receive PayPal ipn data

  // extract ipn data into a string
  byte[] param = Request.BinaryRead(Request.ContentLength);
  string strRequest = Encoding.ASCII.GetString(param);

  // append PayPal verification code to end of string
  strRequest += "&cmd=_notify-validate";
    
  // create an HttpRequest channel to perform handshake with PayPal
  HttpWebRequest req = (HttpWebRequest)WebRequest.Create(@"https://www.paypal.com/cgi-bin/webscr");
  req.Method = "POST";
  req.ContentType = "application/x-www-form-urlencoded";
  req.ContentLength = strRequest.Length;

  // send data back to PayPal to request verification
  StreamWriter streamOut = new StreamWriter(req.GetRequestStream(), Encoding.ASCII);
  streamOut.Write(strRequest);
  streamOut.Close();

  // receive response from PayPal
  StreamReader streamIn = new StreamReader(req.GetResponse().GetResponseStream());
  string strResponse = streamIn.ReadToEnd();
  streamIn.Close();

  // if PayPal response is successful / verified
  if (strResponse.Equals("VERIFIED"))
  {
    // paypal has verified the data, it is safe for us to perform processing now

    // extract the form fields expected: buyer and seller email, payment status, amount
    string payerEmail = Request.Form["payer_email"];
    string paymentStatus = Request.Form["payment_status"];
    string receiverEmail = Request.Form["receiver_email"];
    string amount = Request.Form["mc_gross"];

    // if the payment status is complete
    if (paymentStatus.Equals("Completed"))
    {
      // if the seller email is us (we don't want anyone else getting our payment!)
      if (recieverEmail.ToLower().Equals("my.paypal.seller.account@mycompany.com"))
      {
        // if the amount received is as expected
        if (WriteYourOwnLogic_IsOrderAmountCorrect(amount))
        {
          // complete order processing
          E.g. arrange for despatch of products, mark order as complete, send emails out,
        }
        // else
        else
        {
          // don't process the order, invalid amount
        }
      }
      // else
      else
      {
        // don't process the order, invalid seller
      }
    }
    // else
    else
    {
      // payment not complete yet, may be undergoing additional verification or processing

      // do nothing - wait for paypal to send another IPN when payment is complete
    }
  }       
}

Refactoring the Design

Having completed the implementation of the PayPal IPN handler, during a review we notice that the handler method could probably benefit with some refactoring. There's quite a lot going on in this method, in particular the the various PayPal handshake steps. Ideally, we could refactor these steps into a separate method. Code Rocket allows you to refactor within the design views, but this will be the focus of another article. However, what we can also do is refactor the view that we have onto this method through the Code Rocket design components. For example, Code Rocket allows you to group items together within the diagram into higher level elements, to reduce the amount of 'noise' in the design to allow you to focus more specifically on areas of interest.

For example, let's say we wanted to group all of the PayPal handshake steps into a single element in the Code Rocket flowchart design. We can use the mouse to capture the elements of interest within a selection rectangle - see Figure 4 below.

Selecting a group of elements in the diagram

 Figure 4. Selecting a group of elements in the diagram.

The selected items will be coloured blue. If we then right-click on one of these selected items, we can select the Grouping > Group option to group the selected items - see Figure 5.

Select the Grouping menu option

 Figure 5. Select the 'Grouping' menu option.

We will be prompted to give the group a name - Figure 6.

Give the group a name

 Figure 6. Give the group a name.

The items will then be grouped together and appear as a single element within the diagram. It will appear as a 3D block, indicating that it contains grouped content within it. See Figure 7.

Grouped elements appear as a 3D Block in the Diagram

 Figure 7. Grouped elements appear as a 3D Block in the Diagram.

You can right-click on the grouped element to un-group, or to jump into the grouped elements to view and or edit them. But what we are seeing here is an ability to customise the view of the code to best assist our navigation of it, and to guide our focus onto more relevant areas of the design.

RQS Region Tags

If we were to commit the design containing the newly grouped items into the code, you will see something interesting. Code Rocket has injected RQS region tags into the code - see Figure 8 below. These tags are used to enclose multiple lines of code within groups in the design views. '// RQS-' is used to open a region, and provide a descriptive name for it. '// -RQS' is used to close the region. All lines of code between the tags will be grouped into a single element within the design views.

RQS Region Tags are used to Create Groups in Code

 Figure 8. RQS region tags are used to create groups in code.

Of course you can just manually insert RQS region tags directly within the code, you don't need to inject them using the design views.

Summary

This article has provided an example of using Code Rocket's on-demand, detailed design support to design and implement an Instant Payment Notification (IPN) Handler for PayPal. It has sought to demonstrate the following:

  • Capturing requirements in a high level form within the pseudocode window in Code Rocket
  • Visualizing requirements within the flowchart diagram automatically created by Code Rocket - to confirm and/or review the design and requirements with others.
  • Committing the design and requirements into the code by automatically forward engineering a code skeleton to address them
  • Completing the code
  • Performing additional refinements, e.g. customize or refactor the design views using grouping / RQS regions to reduce 'noise' in the design views, to focus on more relevant areas.

Future articles will focus on using Code Rocket for inspecting or documenting legacy code, conducting project management tasks such as review, and team communication.