#142 PayPal Notifications
PayPal's IPN (Instant Payment Notification) service allows your app to get confirmation when an order is processed. In this episode I use IPN to mark a cart as purchased.
- Download:
- source code
- mp4
- m4v
- webm
- ogv
It's annoying to wait until next episode for production use! :-)
Thanks, Ryan!
To test this locally you could quite easily setup a dynamic dns to point a public domain name to your local environment, such as dyndns.
I've done that on a couple of occasions when working with external services which need to hit my machine as part of the applications natural processes.
Or you can use localtunnel. See http://progrium.com/localtunnel/. It works like a charm.
It is interesting how other people do these kind of things.
However I am still a bit unsure why you are not using ActiveMerchant ?
Don't you find it makes things easier ?
Thanks, and keep up the good work!
Hamza
David,
I'll respond to you by email.
I'm very appreciate Ryan, and don't want to start flame here.
Thanks.
I think recurring billing would be an interesting and useful topic. I know that certain payment gateways support it, but it can be complicated. You would need a background task to scan periodically and make charges...
Thanks Ryan and keep up the good work.
Hey,
I'm working on an e-shop (php but nevermind), and wanna ask something.
Is it safe enough to check the notification for the amount paid to ensure that payment was not tampered?
Hi Ryan,
Paypal's Order Management integration guide says you need to use a "shared secret" or a "postback". I did not see you use either.
See page 26th of the guide: "After your server receives an Instant Payment Notification, you must confirm that the notification is authentic. This is known as notification validation."
Can you comment on this? Am I missing something?
Thanks,
John
No questions, no suggestions, no complaints, just THANKS!
Ryan President ! :)
Great Tutorial Again!
@Ryan:
If you continue to support us with this high quality screencasts, I'll maybe use the learned things to open my own business ;)
Happy New Year to everyone! (not yet but in a few hours ;) )
Happy New Year, Ryan!
Thank you for all your work this year.
Please, continue on the next year.
Thanks thanks thanks!!!
Hello!
Thanks for this tutorial, it is really great, but i am somehow stuck on the serialize part....
In a LOG i can see i get all the information from PayPal, but serialize is somehow failing.
Anyone else with a same problem?
What could be a trick?
Thanks
Hey Ryan,
I have taken what you have done here (great workup, by the way!) and have translated it to use Google Checkout using the google4r-checkout gem. It is really great! Let me know if you want me to pastie you the source for a Railscast episode in this series :)
Thanks again!
Hey Ryan:
Would you mind addressing how to validate non-model backed form components? I'm specifically talking about forms where you use a model to save stuff like the customer's name and phone number, but you don't want to save sensitive data like their credit card number to the database for security reasons.
The same question was raised in a different context by creatop in the comments of Episode 37: "Nice, but what about more complicated non-model forms with many fields with validation required?"
It seems like a pretty common scenario to me - but for some reason there is absolutely no documentation on it (or if there is, I've wasted the last five hours for nothing...haha).
Big thanks. I was looking all the time for this. Greetings, Jacko
@Hamza, I plan to cover ActiveMerchant in future episodes.
@zero0x, right, this is one of the security issues I plan to cover in the next episode.
@Josh, that sounds great. I don't plan to cover Google Checkout in this series, but maybe if there's enough demand I'll make an episode for it later.
@Patrick, using ActiveRecord's validations on a non-database backed model can be difficult. I am delaying talking about this issue until Rails has some better support for this built in. But in the meantime you may want to check out some external validation plugins. Sorry I don't know of the best one off the top of my head.
I personally do not run into this issue because I prefer to keep a record of user input. So, every model that has a decent size form is backed by a database.
Great screencast, Ryan!
Paypal kind of bums me out. I dislike the idea of ipn. For MassPay transactions, I really wish there was a query/request you could send to get the status of payment, but unfortunately I haven't been able to find it.
@Dan: it exists and it is compulsory for validating a purchase! It's just that Ryan didn't get into that yet. I guess he'll talk about it in the next episode.
At this stage of the app you still cannot mark a cart as being purchased/paid.
FYI Paypal provides on their developer website, a Ruby on Rails app in which you can dive in to understand the payment process, but beware it requires a lot of cleaning up.
People interested in PayPal for Rails may want to check out the Spree[1] commerce project which has excellent PayPal support.
There's also a nice extension[2] that provides integrates support for Paypal Website Standard.
[1] http://spreehq.org
[2] http://github.com/Gregg/spree-pp-website-standard/tree/master
Josh or Ryan,
Can you PLEASE post a tutorial using google4r-checkout? Thanks!
- Jane
Before considering PayPal, consider this:
http://blog.apparentsoft.com/business/124/is-paypal-good-for-your-microisv-business-a-short-paypal-horror-story/
I also would love to see a Railscast on google4r-checkout. It seems like a great plug-in and not nearly as klunky as working with PayPal. However, I still have a lot of questions after reading through the google4r-checkout documentation. I'm sure Ryan would answer most of them with his excellent Railscast presentations.
Thanks Ryan! Love your screencasts. I followed all your PayPal tutorials and everything works as expected. But when I test my code live, the IPN doesn't seem to get through . I keep getting error messages in the PayPal IPN-log:
IPN delivery failed. HTTP error code 500: Internal Server Error
Any ideas?
Update: I found my problem. There was a http-user-agent check in my application controller, which caused the IPN to bounce.
Again: thanks for your amazing screencasts.
Hi Ryan,
Based on the information you provided, I am trying to implement paypal IPN and save the donors (non-profit website) information to my database. To accomplish this- after paypal sends IPN(tranx is complete) I am saving the params (some of them) to the db. But the fact is that paypal sends IPN multiple times and every time it saves the params to the database making duplicate entries. Is there any way to control this?
Good video, one thing that might trip people up is that in the after_create method inside the payment_notification model the cart was not able to be found, it always returned as nil for me so the whole process would fail since it couldn't update the attribute.
To fix this I just defined a cart variable and find the cart by id using the params[:invoice] as we set this in the user model at the start. All worked well then.
Thank for this very nice railscast. I have one little critisism however. I think is it better to send a different secret with every paypal checkout. It's not hard to do and much more secure.
I get an error:
TypeError (can't convert HashWithIndifferentAccess into String)
from serialize :params, which is generated from
def create
PaymentNotification.create!(:params => params, :cart_id => params[:invoice], :status => params[:payment_status], :transaction_id => params[:txn_id])
render :nothing => true
end
Any ideas?
What's the difference between the return_url and notify_url?
The return_url was demonstrated in the previous episode but why can't the notify_url be shown working in this episode, with localhost? Wouldn't Paypal be doing the same thing for both - FORM HTTP POST?
In rails 3, i had to change the protect_from_forgery call to: skip_before_filter :verify_authenticity_token, :only => [:create]
if you need to recreate the dev db , ( migrate / seed categories-products) it raises an issue :
the cart_id is used as the invoice_id , so it's already paid in the Sandbox ...
should it be better to generate the cart_id like the migration?
( based on Time_now + cart_id ) ??
just to add another issue using webrick in localhost dev..
when the buyer hit returns... Paypal send all information about the transaction...
Paypal returns a long GET URI , too long for standard webrick processing ....
we can add rm = 2 in the values passed to Paypal and get a POST returned but in this case it should be routed to a :post transaction create , and not to Product index as in the cast....
I have been able to make the IPN works for some use case however, when i pay without paypal account (mastercard,visa...) my app receive the params but the create! method fails silently. The logs contain the params sent by paypal, and there is no significative difference between an IPN from a paypal account and a non-paypal payment.
How can i know what fails in the create! method?
I have just run into the same problem! Has any one found a fix?
Great episode still really useful
I'm currently in a position where my code is not on staging, but I'm using this service showoff.io to use the ipn simulator.
Perhaps someone else's in this same position this tool will make your localhost available on internet
Thanks
Try Localtunnel
I get the following error when using it:
I'm using Rails 3.2.
Dean, could u solve this issue? I'm having the same one :(
My bad, found it.
Running the scaffold generator without the nifty gem creates a field in the migration called 'create'
Hi Ryan,
Is there any way to use paypal notification in combine with PayPal Recurring Payment?
Thanks,
Dat
I would also like to do the same in an app I am working on at the moment :)
Please note that for non-US payments payment_fee and payment_gross fields are not populated. You have to take values from mc_fee and mc_gross instead
Hi Ryan,
I tried to follow your paypal notification tutorial on screen cast but It didn't work for me. I'm currently using rails 4. However, Paypal basic work well. thanks in advance !
This episode code is upgraded to work with Rails 5. Checkout the code with hash 3621d71c558ac16aa0b8e56abcdba1b88ffcb562