0

I am using Node.js for my server and paypal-ipn for IPN verification. When I send an IPN from the Simulator to myself (my IP + port forwarding), I see IPN was sent and the handshake was verified. message on the Simulator page. So my listener is working correctly.

This is my server code:

ipn = require('paypal-ipn');
app.post('/ipn', function(req, res){
    res.sendStatus(200);

    ipn.verify(req.params, {'allow_sandbox':false}, function callback(err, msg){
        if(err){
            console.log(err);
        } else {
            console.log('Verify no error.');
            if(params.payment_status == 'Completed') {
                console.log('Payment completed.');
            }
        }
    });
});

The problem is that I don't have the test_ipn variable in req.params. How I know that? I have intentionally set allow_sandbox to false.This is a chunk of the code from paypal-ipn:

if (params.test_ipn && !settings.allow_sandbox) {
    process.nextTick(function () {
        callback(new Error('Received request with test_ipn parameter while sandbox is disabled'));
    });
    return;
}

If allow_sandbox is disabled (which it is) and I have test_ipn set, I should be seeing Received request with test_ipn parameter while sandbox is disabled, but I don't. This means the other part of the condition is not met - test_ipn is missing. I see this instead:

Error: IPN Verification status: <HTML><HEAD>
<TITLE>Access Denied</TITLE>
</HEAD><BODY>
<H1>Access Denied</H1>

You don't have permission to access "http&#58;&#47;&#47;www&#46;paypal&#46;com&#47;cgi&#45;bin&#47;webscr" on this server.<P>
Reference&#32;&#35;18&#46;8d5e6cc1&#46;1462971151&#46;3d758294
</BODY>
</HTML>

    at IncomingMessage.response_end (C:\Users\Hristiyan\Desktop\StickGame\node_modules\paypal-ipn\lib\paypal-ipn.js:57:18)
    at emitNone (events.js:91:20)
    at IncomingMessage.emit (events.js:185:7)
    at endReadableNT (_stream_readable.js:926:12)
    at _combinedTickCallback (internal/process/next_tick.js:74:11)
    at process._tickCallback (internal/process/next_tick.js:98:9)

Notice that it attempts to use the live paypal URL, not the sandbox one.

With allow_sandbox set to true, I get the same thing. That's because paypal-ipn receives a request without test_ipn set and thinks the IPN is real when it is not.

I also tried to add test_ipn to the request myself, but then, I have manually altered the initial request, which makes the transaction invalid and shows this:

Error: IPN Verification status: INVALID
    at IncomingMessage.response_end (C:\Users\Hristiyan\Desktop\StickGame\node_modules\paypal-ipn\lib\paypal-ipn.js:57:18)
    at emitNone (events.js:91:20)
    at IncomingMessage.emit (events.js:185:7)
    at endReadableNT (_stream_readable.js:926:12)
    at _combinedTickCallback (internal/process/next_tick.js:74:11)
    at process._tickCallback (internal/process/next_tick.js:98:9)

On my PayPal sandbox accounts, I have Review test payments before they're completed. set to On.

dodov
  • 5,206
  • 3
  • 34
  • 65

1 Answers1

3

Turns out that not only the test_ipn parameter was missing, but all of the other ones regarding the payment as well. When I did console.log(req.params), I got an empty object {}.

What I had to do was to add body-parser which... parses the request body, makes things work and puts the actual IPN parameters in req.body. Once I added that, the transactions became verified.

Here's the code:

ipn = require('paypal-ipn');
bodyParser = require('body-parser');

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({     // to support URL-encoded bodies
    extended: true
})); 
app.post('/ipn', function(req, res){
    var params = req.body;

    res.sendStatus(200);

    ipn.verify(params, {'allow_sandbox':true}, function callback(err, msg){
        if(err){
            console.log(err);
        } else {
            console.log('Verify no error.');
            if(params.payment_status == 'Completed') {
                console.log('Payment completed.');
            }
        }
    });
});

Nowhere was mentioned that you need to parse the request. At least I didn't see it anywhere. Make sure that you install the body-parser first with npm install body-parser or npm install body-parser --save (to put body-parser in your package.json dependencies).

Go here for more information.

Community
  • 1
  • 1
dodov
  • 5,206
  • 3
  • 34
  • 65