Ensure we're handling Adaptive Payments IPNs correctly.

Issue #37 closed
Drew Angell repo owner created an issue

Adaptive Payments IPNs have goofy parameter names like transaction[0].id. If you try to parse that with $_POST['transaction[0].id'] it will not work correctly.

Here is an article with some details and a function that can be used to correctly parse IPN data no matter how the parameters are named: http://enjoysmile.com/blog/24/paypal-adaptive-payments-and-ipn-part-two/

We may be doing this already, but I haven't tested Adaptive Payments specifically yet, so I'd like to do that and get this handled if necessary.

Comments (36)

  1. Drew Angell reporter

    Adaptive Payments IPNs have different parameters in place than regular IPNs, so we need to make sure to handle that, too. For example, here is a sample IPN from a Preapproval API request.

    Array
    (
        [max_number_of_payments] => 100
        [starting_date] => 2015-03-01T00:00:21.000-08:00
        [pin_type] => NOT_REQUIRED
        [max_amount_per_payment] => 20.00
        [currency_code] => USD
        [sender_email] => guy.louzon-buyer@gmail.com
        [verify_sign] => AFcWxV21C7fd0v3bYYYRCpSSRl31AiHQSQchSGUInXdtl6zomfkZ7H4C
        [test_ipn] => 1
        [date_of_month] => 0
        [current_number_of_payments] => 0
        [preapproval_key] => PA-2M0807730Y425554F
        [ending_date] => 2015-12-31T23:59:21.000-08:00
        [approved] => true
        [transaction_type] => Adaptive Payment PREAPPROVAL
        [day_of_week] => NO_DAY_SPECIFIED
        [status] => ACTIVE
        [current_total_amount_of_all_payments] => 0.00
        [current_period_attempts] => 0
        [charset] => windows-1252
        [payment_period] => 0
        [notify_version] => UNVERSIONED
        [max_total_amount_of_all_payments] => 2000.00
    )
    

    Notice it has "transaction_type" instead of "txn_type" and the value for it is formatted a little differently than the others.

    Here's another example for a Pay API request.

    Array
    (
        [payment_request_date] => Tue Nov 04 12:51:05 PST 2014
        [return_url] => http://paypal.angelleye.com/paypal/class/1.2/Pay_Return.php
        [fees_payer] => EACHRECEIVER
        [ipn_notification_url] => http://sandbox.angelleye.com/paypal/ipn/ipn-listener.php
        [sender_email] => drew@angelleye.com
        [verify_sign] => AJ0Nr1TRh5d1QroUFs4c5CWoVzpDAyv3Za9yB1I9OfVJn5IIhIs2P1tc
        [test_ipn] => 1
        [transaction] => 
        [cancel_url] => http://paypal.angelleye.com/paypal/class/1.2/Pay_Cancel.php
        [pay_key] => AP-6T355566UC503483F
        [action_type] => PAY
        [transaction_type] => Adaptive Payment PAY
        [status] => COMPLETED
        [log_default_shipping_address_in_transaction] => false
        [charset] => windows-1252
        [notify_version] => UNVERSIONED
        [reverse_all_parallel_payments_on_error] => false
    )
    
  2. Drew Angell reporter

    Something that's good to understand when it comes to Adaptive Payments IPNs, too, is that they are application specific.

    Somebody with application making calls against PayPal's Adaptive Payments platform can include an "IPNNotificationURL" in their API request. Unlike other APIs, though, this will NOT override the IPN setup in the receiver's PayPal account. Instead, this is treated as an app specific IPN, and PayPal would send notifications similar to what I provided above in those cases, so the app owner can automate procedures based on transactions the app submits whether those transactions actually hit their own PayPal account or not.

    If the receiver PayPal account has IPN configured in their PayPal profile that would still be triggered and their own IPN solution would receive a notification that they would expect.

  3. Drew Angell reporter

    I don't have an actual IPN sample for the CreateAccount API, but here is a link to details about what to expect from such IPNs.

    You'll notice on these there is no txn_type or transaction_type at all, and there are actually 3 separate IPNs you might expect associated with CreateAccount.

    • One when the CreateAccount request takes place.
    • One when a password is set for the new account
    • One when the user logs in to the new PayPal account.

    Samples of each of those are provided at the link above.

  4. Drew Angell reporter

    By the way, I do have Adaptive Payments calls setup through my library that I can use to trigger IPNs if you'd like me to, so we can test actual Adaptive IPNs against our plugin. Just let me know if you need me to do that.

  5. jignesh kaila

    As per my understanding below are three different type of Adaptive Payments IPNs:

    1) Pay Message Variables

    • The Pay Message Variables type have transaction[n].id and transaction[n].status so we can easily store to our custom post type.

    2) Pre approval Message Variables

    • The Pre approval Message Variables type have no any transaction_id and payment_status or transaction_status variable.

    • this transaction contain preapproval_key, Can I used as transaction_id ( primary_key )?

    • this transaction contain "approved" variable with true/ false value. Can we used transaction_status as approved/denied using "approved" variable?

    3) Adaptive Accounts IPN Messages

    • Adaptive Accounts IPN Messages transaction have no any transaction_id and payment_status or transaction_status variable.

    • this transaction contain "account_key" and "confirmation_code" variable, Can I used account_key OR confirmation_code as transaction_id ( primary_key )?

    • there is no any transaction_type and transaction_status or payment_status variable, how can I manage from admin side ?

    I have study this URL: https://developer.paypal.com/docs/classic/ipn/integration-guide/IPNandPDTVariables/#id0993D0E0EBF for my understanding.

    Please let me know your suggestion for the same.

  6. Drew Angell reporter

    There are more than three different types. Those are just the three that I mentioned and had samples for.

    The general idea of what I wanted to check with this issue is that our solution can handle IPNs with parameter names like Adaptive Payments uses.

    Also, that the txn_type parameter is actually called transaction_type when it comes to Adaptive Payments IPNs. I think we need to adjust some logic to handle that don't we? As you mentioned, some Adaptive IPNs don't have a transaction_type at all, so we need to check for other things to decipher whether it's an Adaptive IPN or not.

    So I'd like to keep this simple to start. What we can do is create a single "type" called Adaptive Paments and put all of the Adaptive IPNs into that type.

    We also just need to make sure the system parses and saves the data correctly given that the parameter names are unique and PHP $_POST[] doesn't work with them directly. The original comment I made for this issue has a link to a thread with a function that will parse this if we need it. Maybe we're already doing that..??

  7. jignesh kaila

    I am almost done with this issue, I will be testing by tomorrow and let you know for the same.

  8. jignesh kaila

    I have finalised adaptive payments from end for all the case and call. Please review it from your end and let me know your thoughts/feedback for the same.

    Once you confirm will push it to development branch.

  9. Drew Angell reporter

    I ran a Pay API test and the IPN tool did pick up data from the IPN, however, it came through as invalid with no title...

    IPN Invalid

    Array
    (
    [transaction] => Array
        (
            [1] => usb_1329725429_biz@angelleye.com
            [0] => USD 10.00
        )
    
    [payment_request_date] => Sun Mar 22 12:28:04 PDT 2015
    [return_url] => http://paypal.angelleye.com/paypal-php-library/paypal/class/1.2/Pay_Return.php
    [fees_payer] => EACHRECEIVER
    [ipn_notification_url] => http://woo.angelleye.com/?AngellEYE_Paypal_Ipn_For_Wordpress&action=ipn_handler
    [sender_email] => drew@angelleye.com
    [verify_sign] => A88B4BzsTYDDRpi7KJ0KIdd-FdBaA.WRiS3GmUFXOk4vCZNgDEn9GZU8
    [test_ipn] => 1
    [cancel_url] => http://paypal.angelleye.com/paypal-php-library/paypal/class/1.2/Pay_Cancel.php
    [pay_key] => AP-6BS15786DY046760X
    [action_type] => PAY
    [transaction_type] => Adaptive Payment PAY
    [status] => INCOMPLETE
    [log_default_shipping_address_in_transaction] => false
    [charset] => windows-1252
    [notify_version] => UNVERSIONED
    [reverse_all_parallel_payments_on_error] => false
    [IPN_status] => Invalid
    [cart_items] => Array
        (
        )
    
    )
    

    Also, I don't really like the way that transaction array is getting put together. The data within it is just in 0,1,2,etc. I'd rather have that come out like $transaction['email_address'] and $transaction['amount'] as opposed to $transaction[0] and $transaction[1].

  10. Drew Angell reporter

    Also, no category/filter shows up for this type of transaction on the PayPal IPN list. I'd like to go ahead and make an "Adaptive Payments" label and get all of the Adaptive IPNs to show up under that filter.

  11. Drew Angell reporter

    I did another test with the Preapproval API and this one came through as Verified.

    Array
    (
    [max_number_of_payments] => null
    [starting_date] => 2015-03-22T00:00:46.000-07:00
    [pin_type] => NOT_REQUIRED
    [currency_code] => USD
    [sender_email] => drew@angelleye.com
    [verify_sign] => AFcWxV21C7fd0v3bYYYRCpSSRl31APr2dgABrFtNyMXsIA3sRNITy2xD
    [test_ipn] => 1
    [date_of_month] => 0
    [current_number_of_payments] => 0
    [preapproval_key] => PA-1VP43885NK6074217
    [ending_date] => 2015-12-31T23:59:46.000-08:00
    [approved] => true
    [transaction_type] => Adaptive Payment PREAPPROVAL
    [day_of_week] => NO_DAY_SPECIFIED
    [status] => ACTIVE
    [current_total_amount_of_all_payments] => 0.00
    [current_period_attempts] => 0
    [charset] => windows-1252
    [payment_period] => 0
    [notify_version] => UNVERSIONED
    [IPN_status] => Verified
    [cart_items] => Array
        (
        )
    
    )
    

    I think the problem is with the transaction array that we've added to the Pay IPN result. We need to make sure we've verified the IPN with PayPal before we start adding any additional data formatting, otherwise it won't match and verify correctly with their system.

  12. Drew Angell reporter

    I know these are getting entered as "no title" because there isn't a specific transaction ID on them. However, the Preapproval API does return a preapproval_key that we could use for the title/name on those types of IPNs.

    The Pay API returns a pay_key.

    Let's go ahead and use those for the name/title for those IPN types.

  13. Drew Angell reporter

    We seem to be validating correctly now, so that's good, but I still want to make one more adjustment to the way we're adding our parsed transaction data. Right now, we're providing it like this...

     [transaction] => Array
        (
            [1] => usb_1329725429_biz@angelleye.com
            [0] => USD 10.00
        )
    

    So it's just using numeric values for the array index which isn't as help as it could be. Instead, I want to use the names from the parameters as the indexes here. For example, the receiver's email address is getting sent in a parameter like transaction[0].receiver, so in our array it should be $transaction['receiver'] instead of $transaction[1]. Then the amount would be $transaction['amount'] instead of $transaction[0]. So here is how I would expect to see that...

     [transaction] => Array
    (
        [receiver] => usb_1329725429_biz@angelleye.com
        [amount] => USD 10.00
    )
    

    Hope that makes sense. Let me know if you have any questions.

  14. Drew Angell reporter

    Actually, as I was typing that last comment I realized that something else wasn't right quite right. I just ran a test with 2 receivers instead of just 1 and this is the result I got...

     [transaction] => Array
        (
            [0] => NONE
            [1] => Completed
        )
    

    I would expect to see an array of transactions with 2 payments, each one with a receiver and an amount. I'm pretty sure we had that working previously, but I guess I can't remember for sure now..??

  15. Drew Angell reporter

    Keep in mind that what you could do is just use the NVP string to get the IPN verified with PayPal. After that you can go ahead and turn it back into an array to handle the data. Again, I feel like the transactions were getting parsed correctly before, but we weren't validating. Now we're validating, but that change has caused the transactions to get parsed incorrectly.

    I'm just not 100% on that, but please take a look. We definitely need to get that resolved.

  16. jignesh kaila

    I am done with parsing "Adaptive Payments IPN" and push to development branch.

    In the adaptive payment txn_type and payment_status is not available, so our developer hook will not work with adaptive payment

    Can I make new hook for Adaptive payment ipn response?

  17. Drew Angell reporter

    Yes, let's go ahead and make hooks specific to adaptive payments. It does have "transaction_type" so we can do one based on that. (ie. paypal_ipn_for_wordpress_adaptive_payment_pay, paypal_ipn_for_wordpress_adaptive_payment_preapproval, etc.)

  18. Log in to comment