|
Handling Instant Payment Notification (IPN)
If you are not familiar with PayPal IPN, please visit this page for learning
about
Post Payment Notifications
before proceed to this documentation.
As you know, IPN provides immediate notification and confirmation
of PayPal payments you receive. Using IPN, you receive a notification
in the following cases:
- When a payment is first sent, indicating that the status of the payment is Completed
or Pending.
- When a payment clears, fails, or is denied, if the status was pending.
The Payment Button Controls (BuyNow Button, Donation Button, Subscription
Button, Upload Complete Cart Button but NOT the Add to Cart Button) are designed
such a way so that, IPN can be handled like handling an event of a standard
asp.net control. You wont have to worry about any settings in your PayPal
profile. Only
you need to make sure that you have a PayPal premier or business account rather
than just a personal account. So, if you place an instance of BuyNow Button,
Donation Button etc, then you can use the
same aspx page to place your IPN handling logic and this design pattern gives you
the flexibility to use a single aspx page for managing all of your eCommerce related
business logics. In order to start, simply attach an event handler method to the
IPN_Notified event of your
Payment Button Control (i.e. BuyNow, Donation etc..) as shown in the following figure.
When PayPal calls your
aspx page for notifying IPN, your aspx page that holds the control wont render any
html to PayPal as PayPal do not need to see your html contents. The control programmatically
suppresses all Html contents of
the page. Moreover, suppressing html rendering increases
the performance and reduces the PayPal postback time.
What is the use of IPN ? How to use it ? What to expect from this event ?
IPN can be used to manage and customize a variety of PayPal-enabled APIs and
communications, including:
- Customize your website's response to customer purchases in real-time
- Track customers via IPN "pass through" variables
- Deliver access keys for software downloads and other digital goods
- Automate your fulfillment operations
- Track affiliate sales and commissions
- Store transaction information in your own database
Please note: IPN_Notified event is a non visual event. The customer will not see
the IPN_Notified event being fired. It is fired in the background. PayPal
notifies your website asynchronously. So, do not perform any User Interface
related task in the IPN_Notified event handler. For example, do not set any
TextBox Text value or Label's Text property etc UI related tasks as the UI is
never visible to your customer. The
PayPal_Returned
event is specialized for this purpose like UI related tasks. Although there is no
harm in getting and setting UI Control Properties in IPN_Notified event, but it
will be useless. Because, PayPal asynchrnously calls your website and it is
*PayPal* who sees the IPN_Notified event being fired and this *see*ing is
happened in the background. As PayPal does not need to understand any of your
page's UI as it only expects the "200 ok" http status from your website and
nothing else, this control supress all HTML rendering when the IPN_Notified
event fires.
Usually IPN_Notified event is fired as soon as
the payment is completed while your customer is in the PayPal website. Once your
customer comes back to your website, the
PayPal_Returned
event is fired. So, we can assume that, any stored information (in your
database) which was stored in the IPN session is ready to be retrieved (from
your database) in the PayPal_Returned event. So, in PayPal_Returned event, you
can show your customer a summary of tasks done in IPN_Notified event.
When the IPN_Notified event is fired, all transaction information becomes available as strongly typed objects (categorized
collection of composite properties and collections) through the Event Argument Class.
Please note: when you are using SpiceLogic PayPal control, you are not limited
to receive only PayPal provided transaction data. You can pass unlimited data
from your Payment Button which will not be even sent to PayPal, rather it will
be saved in your server and when IPN_Notified event is fired, you will be able
to retrieve those data. Please visit the page for
Passing Additional Data Items
for more details.
There are cases when you may not want to use the
same Button hosting page to be your IPN handler page. Specially when you are
using ADD TO CART Button you must use a dedicated page for handling IPN. In order to point a
different page to be your IPN handler, please
Click
Here
to learn about
Handling
IPN from a dedicated page
.
Practicing Mediator Design Pattern:
If you have many Payment Buttons (i.e. BuyNow button, Donation Button etc..) in
a same page, then you can use a common IPN_Notified event handler for all of the
button's IPN_Notified Event. But, if you have many Payment Buttons in your web
applications where those are not in the same page and if you want to centralize
all of your IPN related logic in a single method, then you should
Handle IPN from a dedicated page
.
IPN Notification Validation: Preventing Fraud
After your server receives Instant Payment Notification, PayPal requires your site
to confirm that your server received it. This is known as notification validation, which is a means for PayPal
to help you prevent spoofing or “man-in-the-middle” attacks. When you are using
this control, you wont need to worry about this phase. This control sends a POST
back to PayPal after it receives the IPN and verify the correctness of the data
and an event argument object (e.IPN.Status) holds the result of this validation. You just need to check the value
of e.IPN.Status in your IPN_Notified event handler as follows:
if(e.IPN.Status == PayPalIPN.StatusCodes.Verified)
{
// Verified
}
Once you have checked that the validation result was Verified, you must check the price, transaction ID, PayPal receiver email address and other data sent to you by IPN to ensure that they are correct. By examining these data you can be sure that you are not being spoofed.
When you receive a VERIFIED response, perform the following
checks:
- Check that the
e.PaymentInfo.PaymentStatus is Completed. For example, the following snippet
shows the usage.
if (e.PaymentInfo.PaymentStatus == IPNPDTPaymentInfo.PaymentStatusValues.Completed)
{
// Completed.
}
- If the payment status is Completed, check the e.TransactionID
against the previous PayPal transaction you have processed to ensure it is not a
duplicate.
- After you have checked the
e.PaymentInfo.PaymentStatus and e.TransactionID,
make sure the e.ReceiverEmail is an email address registered in your PayPal account.
- Check that the price,
e.PaymentInfo.McGross, and currency,
e.PaymentInfo.Mc_Currency,
are correct for the item,
e.ItemInfo.ItemName or e.ItemInfo.ItemNumber.
-
Once you have completed the above checks, you can update your database based on
the information provided and proceed to automating your product delivery
procedure.
If you find e.IPN.Status == PayPalIPN.StatusCodes.Invalid,
you should investigate.
In some cases, this response is caused by an IPN error, possibly from a change in
the IPN format. To determine if it is an IPN error, first examine your code.
How to Test IPN ? Is it possible to test the IPN feature right from my
localhost (or Desktop Computer) ?
In a word, you CANNOT test IPN right from your development environment
unless your development environment got a public domain which is accessible from
outside world using a browser. What does it mean ? Well, as we explained, IPN is
a Server to Server Communication. When a transaction request is made from your
browser to PayPal server, the control will also notify paypal about your url of
the page where the BuyNow button is hosted. PayPal will send notification to
that page but, notice, when you are testing from your environment, you got an
url like, http://localhost/xxxxxx.aspx .....
Right ? Is this url http://localhost/xxxxxx.aspx accissible
from outside your PC ? NO, right ? So, when PayPal receives the transaction
request, PayPal will send IPN to the url
http://localhost/xxxxxx.aspx and as usual, PayPal will not find this url and
the IPN will be lost. You will see that your IPN_Notified event is not being
fired. So, in order to test IPN, you do need to upload your test page to your
production server where your payment button hosting page got a real URL which is
accessible by public. This problem is not prominent for all other feature of
this control. You can test anything else of this control right from your
localhost. Just the IPN is tricky. This limitation is not there for testing PDT
though. You can test PDT
right from your localhost.
How to Debug IPN ?
Again, in order to debug IPN, you must upload your test page to a public
domain server (your production server) where you got a real URL for your button
page which is accessible by outside world (so that PayPal server can access that
page). As you understood that, IPN is an asynchronous event, which is exposed
only to the IPN sender (PayPal) and so, you cannot set a breakpoint on your
IPN_Notified event handler method and step through the lines. You may use Debug
/ Trace methods to log the messages within your IPN_Notified event handler
method. The IPN_Notified Event argument object's IPN.ToString() method is overriden
and it contains a set of useful information like what was the raw string posted
to your server as IPN, which string was sent back to PayPal (or IPN sender)
server, what was the Http status code received after sending back the data to
IPN for verification etc. Here is a sample ToString() value returned by
e.IPN.ToString() from the IPN_Notified Event Argument Object of a BuyNow button.
How to get this string ? Ok, handle the IPN_Notified event and in your event
handler method, assign the value of e.IPN.ToString() to a string type variable.
Then, you may email that string value to yourself or store that to your database
or any of your WRITE PERMISSION given folder in your server as a text file. The
following snippet shows the usage:
protected void BuyNowButton1_IPN_Notified(object sender, BuyNowIPNNotifiedEventArgs e)
{
string ipnDebugData = e.IPN.ToString();
File.WriteAllText(MapPath(string.Format("~/MyLogDir/ipn_{0}.txt", e.TransactionID)), ipnDebugData);
}
You can also get the data in parts by dedicated properties. For example,
e.IPN.Status will give you the enumerated status code. e.IPN.OriginalRawData
will give you the original unmodified IPN data posted by PayPal (or the IPN
sender) etc.
In order to access the specific variable string data (for both IPN & PDT) received
by PayPal, you can use a NameValueCollection type event argument property named
"PostedData". For example, you can get the Payment date as strongly typed object
like this : DateTime paymentDate = e.PaymentDateTime;
but if you want to see what was the actual string for "payment_date" variable posted
by PayPal in case you are suspecting that you are getting wrong data. So the following
snippet will give you the exact string for the PayPal variable "payment_date"
string PayPal_Posted_DateTime_String = e.PostedData["payment_date"];
Also, if you want to get a value of a new ipn data which is not available from
this control's IPN_Notified event argument object (it is highly unlikely unless
the ipn version is updated very recently by PayPal and our development team took
some time to synchronize our control with that ipn version. Also we may find
some undocumented and unimportant variables introduced recently which is not
included in the IPN_Notified event argument object. For example, we did not find
'protection_eligibility' variable important to include to the type safe list of
properties as it is not even well documented by PayPal.), you can get that value
from e.PostedData NameValueCollection like this:
string ProtectionEligibility = e.PostedData["protection_eligibility"];
Membership users, please note:
If you are using ASP.NET Memberhsip feature in your website, then, you need to
allow PayPal to see your page where you placed your IPN_Notified event handler
code. That meanst, if you are handling IPN_Notified event right from your
Payment button (BuyNow button, Donation button etc), then, the page that hosts
your Payment button should be visible to all. If you are
Handling IPN from a dedicated page
then, your IPN handler page should be accessible to all users.
Assume that you hosted your BuyNow button at "Products/Purchase.aspx" page.
Then, you need to add the following section to you web.config file.
If you do not permit paypal to post IPN to your page, then, you will find that
IPN_Notified event is not being fired.
By this time, I hope you already realized that, IPN is a different SESSION
created by PayPal to your website and this SESSION is not the same SESSION
created by your customer to your website. Since any asp.net designer wanting to set up a site
where users pay a membership fee to join, would very likely want to put a user
in a Role on IPN_Notified event handler method. It will be a common mistake if
you assume that the Customer is logged in as a member in the IPN SESSION.
So, how would you pass the username of the Customer to the IPN_Notified event so
that you can write code to add your customer in a paid member role by the
customer's user name ? Yes, we have designed a very special property named
"Additional Data Items". This is a Dictionary type property which can be
populated either in design time or programmatically. So, you can pass your
customer's username by Additional Data Items to the Payment Button and you can
access that data right from IPN_Notified event handler method. Once you retrieve
that user name of the customer from Additional Data Item, you can add him/her to
your paid member role. In order to learn about Additional Data Items, please visit this page
.
Code Example:
|
Please Wait..............................
|
|
Hosting Trust Level issue:
Please note: Although we tried as much as possible to make this control
compatible with Medium Trust Configuration hosting, yet In order to handle IPN, you must have FULL TRUST level
configuration in your hosting. If you do not have FULL TRUST configuration, then
you will always get
e.IPN.Status
==
PayPalIPN.StatusCodes.Communication_Error
Explanation:
In the notification validation process, the control sends a POST back to PayPal
after it receives the IPN and verify the correctness of the data.
In order to post to a website, the component needs to call one of the method
from the WebClient class library available from System.Net namespace.
Now, executing WebClient class methods requires Full Trust configuration in the
hosting and if you do not have full trust configuration, then not only using
this control, but also you cannot get any status code using any other control at all.
But, but, if you got any solution about calling a website from the web
application in medium trust level, simply let us know and we will modify our
control to make it compatible with medium trust hosting and offer you a FREE
developer license for this control.
SSL Not Required for IPN
Because credit card and bank information is not transmitted
in Instant Payment Notification (IPN), PayPal does not require Secure Sockets Layer
(SSL) to encrypt IPN transmissions.
Still Confused ?
If you are still confused, please check the sample application that comes with
the setup.exe file you have downloaded from our website. Also please do not
hesitate to ask us as many questions as you want from our
Help Desk
.
|