On this page
No Headings
Last updated: June 18, 2026
Important: NVP/SOAP is a legacy integration method. We accept new integrations and support existing integrations, but there are newer solutions. If you're starting an integration, we recommend our latest solutions.
IPN is a message service that sends you a notification when any type of transaction occurs in your account. The messages are received and processed by your server(s).
To receive and process Instant Payment Notification (IPN) messages:
Note: For instructions on using the PayPal APIs, how to use the sandbox for testing, and how to move your app into production, see Apps 101.
To receive and process IPN messages:
Create a listener that:
To create a basic listener that echoes IPN messages to a browser window:
Capture the IPN messages that PayPal sends to your listener
After receiving an IPN message from PayPal, you must respond to PayPal with a POST message that is an exact copy of the received message but with "cmd=_notify-validate" added to the end of the message. Append to your message a duplicate of the notification received (the same IPN fields and values in the exact order you received them):
<?php
// STEP 1: read POST data
// Reading POSTed data directly from $_POST causes serialization issues with array data in the POST.
// Instead, read raw POST data from the input stream.
$raw_post_data = file_get_contents('php://input');
$raw_post_array = explode('&', $raw_post_data);
$myPost = array();
foreach ($raw_post_array as $keyval) {
$keyval = explode ('=', $keyval);
if (count($keyval) == 2)
$myPost[$keyval[0]] = urldecode($keyval[1]);
}
// read the IPN message sent from PayPal and prepend 'cmd=_notify-validate'
$req = 'cmd=_notify-validate';
if (function_exists('get_magic_quotes_gpc')) {
$get_magic_quotes_exists = true;
}
foreach ($myPost as $key => $value) {
if ($get_magic_quotes_exists == true && get_magic_quotes_gpc() == 1) {
$value = urlencode(stripslashes($value));
} else {
$value = urlencode($value);
}
$req .= "&$key=$value";
}
// Step 2: POST IPN data back to PayPal to validate
$ch = curl_init('https://ipnpb.paypal.com/cgi-bin/webscr');
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $req);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Connection: Close'));
// In wamp-like environments that do not come bundled with root authority certificates,
// please download 'cacert.pem' from "https://curl.haxx.se/docs/caextract.html" and set
// the directory path of the certificate as shown below:
// curl_setopt($ch, CURLOPT_CAINFO, dirname(__FILE__) . '/cacert.pem');
if ( !($res = curl_exec($ch)) ) {
// error_log("Got " . curl_error($ch) . " when processing IPN data");
curl_close($ch);
exit;
}
curl_close($ch);When PayPal receives your POST message, it sends a message back to your listener to indicate the validity of the initial notification. PayPal's message has an HTTP status code of 200 and a body that contains either VERIFIED or INVALID.
Before processing the IPN message, ensure that the message is valid a follows:
<?php
// inspect IPN validation result and act accordingly
if (strcmp ($res, "VERIFIED") == 0) {
// The IPN is verified, process it
} else if (strcmp ($res, "INVALID") == 0) {
// IPN invalid, log for manual investigation
}
?>Parse the message for information on the transaction referenced by the IPN, the type of notification sent, and the associated transaction status. Take the appropriate action(s) based on the notification received:
<?php
// inspect IPN validation result and act accordingly
if (strcmp ($res, "VERIFIED") == 0) {
// The IPN is verified, process it:
// check whether the payment_status is Completed
// check that txn_id has not been previously processed
// check that receiver_email is your Primary PayPal email
// check that payment_amount/payment_currency are correct
// process the notification
// assign posted variables to local variables
$item_name = $_POST['item_name'];
$item_number = $_POST['item_number'];
$payment_status = $_POST['payment_status'];
$payment_amount = $_POST['mc_gross'];
$payment_currency = $_POST['mc_currency'];
$txn_id = $_POST['txn_id'];
$receiver_email = $_POST['receiver_email'];
$payer_email = $_POST['payer_email'];
// IPN message values depend upon the type of notification sent.
// To loop through the &_POST array and print the NV pairs to the screen:
foreach($_POST as $key => $value) {
echo $key . " = " . $value . "<br />";
}
} else if (strcmp ($res, "INVALID") == 0) {
// IPN invalid, log for manual investigation
echo "The response from IPN was: <b>" .$res ."</b>";
}
?>Log in to your PayPal business account and specify the Notification URL to your IPN listener. For detailed instruction about how to specify the Notification URL, see Identifying your IPN listener to PayPal. As an example, the web server where you host a PHP listener might resemble the following URL:
https://example.com/ipnListener/ipn-Listener.phpIn addition to enabling the IPN service and setting the Notification URL location through your PayPal account, you can also set the location using the NOTIFYURL parameter in an API call. By dynamically setting the Notification URL, you can set up different listeners for different needs (such as if you are supporting different merchant site with a single PayPal account).
Run your listener on a server that hosts the URL you specified as your Notification URL in Step 1.
Your listener must always be accessible at the specified website—PayPal can send notifications at any time of day.
Tip: View IPN Code Samples for several different programming languages.
PayPal sends IPN messages for every type of transaction or transaction status update (including payment and subscription notifications), and each notification type contains a unique set of fields. You need to configure your listener to handle the fields for every type of IPN message you might receive, depending on the types of PayPal transactions you support. For a complete guide on the different types of IPN messages and the data fields associated with each type, see the IPN Integration Guide.
Consider the following processes in your notification handler to properly direct the notifications and to guard against fraud:
Completed, Pending, and Denied. Don't send inventory unle the transaction has completed!txn_type or reason_code of a VERIFIED notification to determine your processing actions.