Getting Started with PayPal IPN and PHP

I was recently asked to integrate PayPal IPN into a website that sells online article subscriptions. Basically, the client wanted all users who signed up via PayPal to instantly have access to the website (as opposed to making them wait for someone to manually approve each transaction). The backend was coded in PHP and featured a MySQL database for storing users' information.

I'm going to explain the important steps I took to make this happen. If nothing else, this article will get you on the right track to interfacing with PayPal IPNs.

It should be mentioned that the type of payment submission used to generate these transactions is not relevant. This particular website was using the default PayPal shopping cart, but it's perfectly alright to use an alternative payment solution (Website Payments Pro, Payflow Pro, or one of the many PayPal supported shopping carts work just fine).

How IPN Works

It's easier to explain how IPN works with a simple flowchart, then send you off to read more details about it.

IPN flowchart

Now you won't have such an overwhelmed feeling when you visit the PayPal Integration center for the complete information.

Enabling IPN

The first step to getting IPN working is to, well, enable it. Login to PayPal and select the Profile tab. Select Instant Payment Notication Preferences. IPN will be turned off by default. Click the Edit button.

Now we need to determine where the script that handles the communication with PayPal will be located. Let's just call it something like The location we put in this box is important, so write it down or something.

Creating a Script to Handle IPNs

The PHP Paypal IPN Integration Class

Now that notifications are enabled, we need to create a script that can communicate with PayPal when IPNs are sent. For this task, I found the PHP Paypal IPN Integration Class written by Micah Carrick.

The download (version 1.2.1 at the time of this writing) consists of 2 PHP files. Let's copy paypal.class.php to the web server and keep paypal.php off to the side for now.

Creating and Testing the Script

Next, let's create paypal_ipn.php:

$p = new paypal_class;
$p->ipn_log_file = 'paypal.log';
// testing only - comment this out for production
$p->paypal_url = '';
if( $p->validate_ipn() ) { }

After uploading paypal_ipn.php to the web server, I decided to send out a test IPN. To avoid having to set up a fake company, bank account, email address, users, etc. in the PayPal Sandbox, I went to the IPN Script Testing Environment provided by EliteWeaver UK.

It probably would have been better to get this working using the PayPal Sandbox first, then move it over to production. In fact, if you have the time (and patience) I strongly recommend it. This application was very simple and didn't require the test environment, but more complex applications and novice developers may.

There are a lot of configuration options, but let's keep it simple. We'll change the IPN Handler to the exact URL of our paypal_ipn.php file. In this case that would be Now, if we set everything up correctly, clicking Submit IPN should result in a success message.

After you receive the test IPN, double check that the script is writing to the log file. This file can be critical to you if something goes wrong somewhere down the line and you're trying to troubleshoot a bug.

If the test fails, double check that the appropriate files have been uploaded and the correct URL was specified as the IPN Handler. Once the script passes the testing environment, we can comment out this line in paypal_ipn.php:

//$p->paypal_url = '';

Now, when executed, the script will contact the PayPal server instead of the test environment. It won't really do us any good as it is, however. The IPN will validate, but you'll have to look in the log file to see anything useful. That doesn't help our customers who expect to be processed immediately.

Processing IPNs

This part is very simple, but it's also quite tedious. Once the IPN is validated, all of the transaction's information will be stored in the $p->ipn_data array. For example, $p->ipn_data['txn_type'] might have a value of subscr_signup and $p->ipn_data['subscr_date'] would be something like 13:31:07 Sep 03, 2007 PDT. The elements returned to you in the array will vary depending on the type of transaction (i.e. subscription, purchase, etc.).

For a complete list of what can be returned in the $p->ipn_data array, see the IPN Variable Reference chart.

Unfortunately, handling purchases, refunds, subscriptions, payments, cancellations, etc. is beyond the scope of this article. But now that we're receiving all of the transaction data in the form of a simple PHP array, it should be evident how to code the rest of the script.

To give you a hint, it involves using a lot of conditionals to determine what type of transaction was made, what item(s) were purchased, whether or not the payment was successful/pending/failed, etc. The bad news is that it's different for every website so there is no plug-n-play code to just make it all work.

I would recommend mapping out all of the possible types of transactions that will occur on your website and start from there, rather than trying to account for every one the IPN supports. Just be careful to check for important things, such as whether or not the IPN was successful and whether or not the payment was actually completed, because you will get IPN notifications for virtually all activity between you and your customers.


If you get stuck, there are a few excellent resources available to get you back on track. I am by no means an expert on PayPal integration (nor do I want to be), so contacting me probably won't get you very far if you're having difficulty. Some of the tools I used to accomplish this integration were:

And if you really get into a bind and need to hire an expert, there's always the PayPal Certified Developer Directory.

Author avatar

About the author

Creator of Surreal CMS and other web things. Follow me for tweets about JavaScript, CSS, and web programming.