Dani 5,664 The Queen of DaniWeb Administrator Featured Poster

I'm trying to debug my PayPal IPN code. Here is my PHP code:

if ($this->input->post('payment_status') == 'Completed' AND in_array($this->input->post('txn_type'), array('web_accept', 'subscr_payment')))
{
    $query = 'cmd=_notify-validate&' . http_build_query($this->input->post());

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, '');
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $query);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $result = curl_exec($ch);
    curl_close($ch);

    if ($result == 'VERIFIED')
    {   
        $donation = new Donation;
        $donation->insert(array(
            'userid' => $userid,
            'amount' => $this->input->post('mc_gross'),
            'timestamp' => now(),
            'paypal' => $this->input->post('payer_email'),
        ));
    }
}

The official documentation is here:

It only seems to be working about 75% of the time. I think that for the remaining 25%, the payment_status isn't 'Completed' or an invalid value is spcified for txn_type. I don't want it to work on refunds, etc. From what I can tell, there is no distinction between one that worked and one that didn't (i.e. it's not like one was an eCheck and one wasn't, etc). Anything I can look into?

Dani AI

Generated

— intermittent failures like this are usually caused by how the IPN payload is sent back to PayPal (encoding/order changes, framework filtering) or by legitimate non-Completed statuses (eChecks, Pending, subscription lifecycle messages). Capture the exact raw IPN for every callback and inspect the failing 25% before changing logic.

Use the raw POST body when you re-post to PayPal and the newer ipnpb endpoint. Do not rebuild the POST with http_build_query() on a sanitized array (CodeIgniter's $this->input->post() can alter values). Example approach: read php://input (or $this->input->raw_input_stream in CI), prepend cmd=_notify-validate, post that raw string to https://ipnpb.paypal.com/cgi-bin/webscr with HTTP/1.1, Connection: Close, SSL verification enabled and a short timeout. Trim the response before checking for VERIFIED.

Always log:

  • the raw IPN body,
  • the cURL/http response and any curl_error(),
  • the txn_id, txn_type, and payment_status values for each IPN.

Don’t insert a donation until you have VERIFIED and payment_status == "Completed". If you get Pending, store the IPN and wait for a follow-up IPN that changes status to Completed. Also check txn_id uniqueness, receiver_email, mc_gross and mc_currency to avoid duplicates and fraud. If you see unexpected txn_type values, log them and update allowed types (subscr_payment, recurring_payment, web_accept, etc.) after confirming their semantics.

For PayPal’s recommended verification endpoint and a full list of IPN variables and statuses, see the PayPal IPN docs: and .

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.