Parsing PayPal Subscription Ran Out - paypal-ipn

On PayPal subscriptions, it appears that all I need to do is treat it like a regular IPN except look at the txn_type field. When I see one of the following status codes, I send an email to the admin to consider expiring that member manually in the admin panel of my software I'm building in PHP.
The statuses appear to be one of the following to indicate the customer either cancelled, had an end of term, or simply isn't paying anymore. Can anyone confirm that these are the right statuses to check for, or have I included a couple that aren't right?
subscr_cancel
subscr_eot
subscr_failed
recurring_payment_failed
recurring_payment_suspended_due_to_max_failed_payment
recurring_payment_outstanding_payment_failed
recurring_payment_profile_cancel
recurring_payment_expired

If you've gone through the subscription button mechanism, and it's not one of the pre-approved recurring payment things then you'll only see the "subscr" prefixed ones, I think.
I personally don't respond to "subscr_cancel" in my app. The IPN for that is sent the moment the users cancels. I don't want to disable their access at that point so I wait for the "subscr_eot" one and do it then.
So if they sign up for a year, and cancel the next day, they still have access to the end of the year, which is when PayPal will send the "subscr_eot". They'll always send both.

I found that these are the ones to watch regarding "end of membership" type reactions in my code:
subscr_cancel
subscr_eot
recurring_payment_profile_canceled
recurring_payment_expired
All others are just "noise" regarding "end of membership" status. For instance, to react to any payment "failure" type IPNs would be wrong because eventually PayPal may rectify that problem with the customer after a reattempt, and so cancellation and expiration events are really what you should look for.

I know i'm kind of late in this post, but here is a quick solution (php) for your question:
switch ($_POST['txn_type']) {
case 'cart':
//for products without subscription
break;
case 'subscr_payment':
//subscription payment recieved
break;
case 'subscr_signup':
//subscription bought payment pending
break;
case 'subscr_eot':
//subscription end of term
break;
case 'subscr_cancel':
//subscription canceled
break;
}

Related

PayPal IPN and AutoReturn

I have an ipn listener that update my transactions (from pending to completed) and my contracts payments from finished to paid. This is perfect! I has also a return page... From PayPal to my site... This page show "thanks" and "button to allow download their last paid online contract" (paid with PayPal). My problem is that.... Ipn listener sometimes comes 3 seconds after my return page is shown to the the user....
In my return page in this case. Has the transaction and contract unpaid... And when ipn listener catch the results... Then this transaction and contract change to paid status. But ipn listener is executed at back-end. In my server. And my return page was shown 3 o 2 seconds before to my user. What can I do?
Should I add a timer (a delay) in my return page waiting until ipn updates my transaction and contract status? And then, show to the user a button "you can download your last paid contract!". Or better I should forget this step. And in my return page always without wait show to user "thanks for your payment". "you can download your last paid contract!"
You should not regard or show the transaction as complete, or allow any further business action to occur, until you have actually received the money, and only the IPN tells you that.
You need to adjust what you show on your return page accordingly.
All you should really do here is thank the customer for his business and tell him that the download or the delivery or whatever it is will become available immediately PayPal has notified you of the actual transfer.
And note that it can take a lot longer than three seconds. If they chose to fund the payment from their bank account, it can take 3-5 days: and there is always the possibility of that process failing altogether due to insufficient funds.
So don't be too optimistic in designing your return page. The deal isn't done until the money is in the bank.
This page show "thanks"
Good.
and "button to allow download their last paid online contract"
Bad. That should be somewhere in 'My Account'.
I also have my return page wait for the IPN notification to come into my server, and you can definitely make that work if you do it right.
Initially, the return page polls on a field in my back-end database that the IPN handler updates. Then, when the return page sees that field update, the customer gets his 'here are the items you paid for' button.
I also have a one minute timeout on this process. When that expires (although I can't remember the last time that actually happened), I display a catch-all error message ('There was a problem processing your transaction') and invite the customer to contact me for help.
I also tell them that their license key (which is what they are buying, in my case) might be on its way by email, since, usually, it is. IPN notifications can sometimes take a little while to arrive for some reason but my IPN handler sends out a confirmation email as a backup so they will get that in due course. That usually sorts things out, I rarely need to get directly involved.
If PayPal puts the transaction on hold, it doesn't seem to ever forward the customer to the return page (I have certainly never seen that happen). Instead, I assume it lets the customer know that he must wait for the funds to clear and leaves it at that.
An IPN notification does get sent however when the transaction eventually clears, and then you can have your handler send that email.
Lest this sounds like a lot of work, you should be sending an email from your IPN handler anyway since customers like to have a record of their purchases. Once you put that mechanism in place, the rest is easy.
Note: Watch out for IPN transactions flagged as 'echeque'. The funds haven't cleared yet, you will get another notification when they do. Then you can send them their contract by email. If memory serves,this does forward them to your return page so you have to handle that by letting them know that they must wait. In practise, this doesn't seem to happen very often.
Suggestion: have your scripts send you an email when something unexpected happens. This has saved my bacon more than once when PayPal have changed the names of the fields passed to the IPN handler for no obvious reason.
Summary: This is a practical, experience-based write-up of the way my website works, and it works well. I hope readers of this post find it helpful, despite the mysterious downvotes.

Payment status remains "Pending"

I integrated PayPal in my web shop in order to allow instant payments with automatic product delivery (already had this before but only with instant wire transfers via sofort.com). I integrated it with the help of the example provided by PayPal (I'm using ReviewOrder.php, GetExpressCheckoutDetails and DoExpressCheckoutPayment).
It's working great if they pay with PayPal balance or a linked credit card. However, some customers from Germany don't have balance in their accounts but only a bank account linked to their account. The payments go through and they receive their product, however I noticed the payment status would remain "Pending" for 1 month and change to "Expired" afterwards, so effectively no money arrives.
Why is this happening? Or is there any way to deny such payments? (Payments from backup funds)
Any help would be appreciated.
Its hare to day with out looking at the transaction specifically. But there are several things that can cause your payment to be pending, such as your preferences that you may have set in the account. Check to make sure you dont have your preferences set to ask me before accepting a payment in a currency that you do not hold. Did the buyer pay with an eCheck? If so, it could be waiting for the payment to clear. If this is in the sandbox, you have to manually clear the payment. If you are still not able to determine the cause of the pending payment, if you provide the transaction id, I will check it on my end.
Hey guys I managed to find a solution to this odd problem after all.
It turned out I had the following code in my implementation where I actually initialized the payment process:
$_REQUEST['paymentType'] = "Order";
This was a mistake though, since this payment type won't place a hold on the funds and if the DoCapture call is never called this payment will remain pending for about one month and then expire entirely (as described in my question, so this is what actually happened to me). The bad thing is that it's impossible for such payments to even accept them manually from within PayPal (not even the local PayPal phone support was able/wanted to accept these payments for unknown reasons because they told me they'd come up with a solution and contact me via Email within 24 hours but they never did).
So in order to fix this issue I changed the payment type to Sale which instantly captures the payment rather than waiting for sort of approval or a capture call. It worked fine for two weeks now and I think I'll leave it like this now.
$_REQUEST['paymentType'] = "Sale";
I lost about 110€ because this stupidly trivial detail but at least it's working fine now and I was able to re-enable PayPal as a payment form. I hope they'll at least add an option to manually accept these payments if the DoCapture call was not implemented because it worked fine without it for most of the payments as well and after all this is still about real money, so this absolutely would be an essential thing to have....
This can happen also if you are trying to accept a payment in a different currency of your account. To avoid that you must create a "PayPal balance" in the currency of the payment.
IPN is also giving hints on the pending reason in this case:
[pending_reason] => multi_currency

paypal ipn max time for incomplete transaction

Hey guys was hoping you could help me out.
I am integrating paypal (for the first time) in a website using PHP. From what I have read, there are two methods for confirming a successful transaction, PDT and IPN.
Now the thing is, the item's being sold can have a limited stock. So if suppose a person reserves an item and is taken to the PAYPAL site for final payment, I have to stop all other people from making a purchase since the last piece of the item will be "reserved".
But suppose the person (who has reserved the final piece of the item) goes to the paypal page, and then simply closes it. Will this result in a "fail" ipn coming to me (so I should un-reserve the item so others can buy)?
If so, how long will it take for the failed IPN to come?
If not, how exactly should I handle this.
And is there any scenario where an IPN does not come?
You could use the Express Checkout API.
With EC, the payment is a two step process. In the first step, you make an API call (SetExpressCheckout) where you set up the transaction, and redirect the buyer to PayPal. Once there, the buyer authorizes the payment, and returns to your site.
At this point no money has changed hands. You need to make a second API call in order to capture the funds (DoExpressCheckout).
You can hold the item for a specific period, and if the buyer abandons the transaction, or is very slow to approve the payment, you can release the item back to the public. If he eventually approves it, and does come back to your site, you would simply skip the second step, and inform the user that his transaction timed out. No money changes hands, no items are double sold.

How do I deal with PayPal customers who can't direct return

PayPal states:
Note: If you have turned on Auto
Return and have chosen to turn on
PayPal Account Optional for new users,
a new user will not be automatically
directed back to your website, but
will be given the option to return.
But if some of the customers don't get "Auto Returned", how do I handle them programmatically?
Paypal does not guarantee autoreturn especially when Paypal Account - optional setting is on.
The right way to handle the integration is with Instant Payment Notification (IPN) option. Using IPN Paypal will make POSTS to your page notifying you of payment events. The following link explains the IPN process pretty well.
To summarize, you will write code that will trap posts from Paypal and then make sure to update your billing data accordingly.
Also, IPN messages might be slightly delayed.
Create a script (cron or what) that does check for such payments at paypal perodically (e.g. every hour).
Is this what you mean?
https://www.paypal.com/cgi-bin/webscr?cmd=p/mer/express_return_summary-outside
If not, you may need to be a little more specific with your question. Like - are you using paypal pro? How are your customers checking out? etc. And now that I read the answer below mine, I wonder if you are even talking about the payment process and not something else.

Testing Paypal subscription IPN

I'd like to test paypal subscription IPNs, both the ones received when a subscription is created, and the ones sent later with the next payment (such as monthly if the subscription is $x per month).
However I'd prefer not to wait a month or a day to receive the second IPN. Is there a way to have an IPN sent quicker, such as hourly, using paypal or their sandbox?
On the documentation it says you can only specify years, months, days, and weeks as the subscription period.
PayPal's developer support and documentation is an embarrassment to them. But this particular limitation isn't as debilitating as it seems at first blush.
For testing, define your recurring payment to not have a free trial. When you create a new subscription, your server will receive two IPN messages in quick succession, one to create the subscription and the second to apply a payment. That's basically all you need to test.
If you have a free trial, you'll get basically the same pair of messages, just with a trial period between them. :)
The first message ("create subscription") will look something like this. Note the 'txn_type' -- that's the key bit of information for disambiguating the two messages:
{
"txn_type"=>"subscr_signup",
"subscr_id"=>"unique_id",
"verify_sign"=>"random_gibberish",
"item_number"=>"your_subscription_name"
"subscr_date"=>"14:32:23 Feb 15, 2010 PST",
"btn_id"=>"1111111",
"item_name"=>"Your Subscription Description",
"recurring"=>"1",
"period1"=>"1 M",
# This example is from a "free trial" IPN notification-- if you don't have a
# free trial defined, there will only be 'period1' fields, and they'll
# have the data that appears here in the 'period3' fields.
"amount1"=>"0.00",
"mc_amount1"=>"0.00",
"period3"=>"1 M",
"amount3"=>"34.95",
"mc_amount3"=>"34.95",
"mc_currency"=>"USD",
"payer_status"=>"verified",
"payer_id"=>"payer_unique_id",
"first_name"=>"Test",
"last_name"=>"User",
"payer_email"=>"test_xxxx#example.com",
"residence_country"=>"US",
"business"=>"seller_xxxxxxx#example.com",
"receiver_email"=>"seller_xxxxxxx#example.com",
"reattempt"=>"1",
"charset"=>"windows-1252","notify_version"=>"2.9","test_ipn"=>"1",
}
The second message is the more interesting one in this case. It will essentially be the exact same message you'll get later when the recurring payment is applied. It looks something like this:
{
"txn_type"=>"subscr_payment",
"subscr_id"=>"unique_id",
"verify_sign"=>"random_gibberish",
"txn_id"=>"payment_unique_id",
"payment_status"=>"Completed",
"payment_date"=>"12:45:33 Feb 16, 2010 PST",
"item_number"=>"your_subscription_name"
"subscr_date"=>"14:32:23 Feb 15, 2010 PST",
"custom"=>"data-you-sent-in-a-custom-field",
"id"=>"1",
"payment_gross"=>"34.95",
"mc_currency"=>"USD",
"payment_type"=>"instant",
"payment_fee"=>"1.31",
"payer_status"=>"verified",
"mc_fee"=>"1.31",
"mc_gross"=>"34.95",
"btn_id"=>"1111111",
"payer_id"=>"payer_unique_id",
"first_name"=>"Test",
"last_name"=>"User",
"payer_email"=>"test_xxxx#example.com",
"residence_country"=>"US",
"receiver_id"=>"your_merchant_id",
"business"=>"seller_xxxxxxx#example.com",
"receiver_email"=>"seller_xxxxxxx#example.com",
"protection_eligibility"=>"Ineligible",
"transaction_subject"=>"",
"charset"=>"windows-1252","notify_version"=>"2.9","test_ipn"=>"1",
}
So you can do almost all of your testing without waiting a day. By the time you think you've got it nailed down, you'll be receiving lots of subscription IPN messages the next day.
In addition, here is a link to PayPal's documentation for further reference.
It's possible to resend test IPNs, so you should only need to 'buy' one subscription for testing.
Once you've bought one subscription, here's what to do:
Log into your PayPal sandbox seller account.
Select 'Profile' => 'My Selling Preferences'.
Select 'Instant Payment Notification Preferences' from the third column.
Confirm that IPN is enabled and that the URL is correct.
Click the link to the IPN History page.
Scroll down, tick one or more IPNs and click 'Resend'.
After you confirm, the selected IPN(s) will now be resent to the URL you have specified. You can repeat an unlimited number of times with the same IPN(s).
The excellent answer by #dondo covers the rest.
It used to be that the period specified in days would be treated by the test server as minutes so you'd be called every 3 minutes when specified 'd3'. I think they removed this and I'm not aware of any replacement feature to test subscriptions.
Hey I just wanted to throw a shout out to Neil because that is exactly what I was looking for and I don't have enough reputation to reply or upvote..
Believe it or not paypal still doesn't make it easy to do subscription testing with ipn files :/
So, just because I didn't see it on here and the OP kind of sounded like they were under the impression to only expect two possible responses from papal --
if anyone else is having issues, here are some other txn_type that hit my ipn while doing testing:
//when paypal subscription profile is created for the subscriber
subscr_signup
//payment made for a given billing cycle
subscr_payment
//when subscription fails
subscr_failed
//user cancels subscription - not
subscr_cancel
//end of term - paypal is "done" with that subscriber
subscr_eot
//why I was looking for this thread to begin with lol
recurring_payment_suspended_due_to_max_failed_payment
that last one hit my ipn this morning against every last one of my test subscribers. when I was looking up what that meant, I found that the following are also possible to get:
recurring_payment_profile_created
recurring_payment_profile_cancel
recurring_payment_profile_modify
recurring_payment
recurring_payment_skipped
recurring_payment_failed
I don't know what I did to get that because subscriptions and recurring payments are technically different in PayPal's eyes (subscriptions can possibly never terminate but recurring payments have a cap on the total payments someone can make for any "subscription") but their documentation isn't always straight forward, either, so I dunno. That I'm still working on figuring out as this was a subscription button generated by a sandbox merchant account but whatever.
Happy headaches :)
UPDATE:
I figured out my problem just now - so just so it sounds like I know what I'm doing I'll explain...
I think paypal's subscription sandbox environment is slowly dying. I noticed the other day when I'm messing around in sandbox.paypal.com that I get "Fatal Failure" a lot of times. Refreshing the page seems to correct this most times, although sometimes i have to refresh a few times for the screen to come back.
I am getting the same response from them hitting my IPN file, which explains why every subscription I had got suspended today. Thanks to Neil I was able to resend the IPN response and I captured it into a text file (lol) and then I hit the ipn file reading in the response and throw it back at paypal (its really more complicated than that I'm just making it sound easy).
In any case by refreshing the page I can initiate the paypal handshake more or less on demand and when I do, it's 50/50 - sometimes I get VERIFIED, and sometimes I get Fatal Failure - just like when I try to do much of anything in their sandbox site (Fatal Failure).
Below is an example of part of a failed response I get from them... I get a 200 so I believe hitting their server isn't the issue with connectivity, but I am starting to see a pattern with "Fatal Failure" here and this points to more their end than mine
HTTP/1.1 200 OK
Date: Tue, 29 Sep 2015 02:41:00 GMT
Server: Apache
Fatal Failure
you can also manually create IPN from their sandbox:
https://developer.paypal.com/cgi-bin/devscr?cmd=_ipn-link-session