Posted almost 8 years ago by Philip Ingram
As I’ve been recently working with the PayPal API recently, I thought I’d put my solution to how I ended up using their IPN.
IPN, or Instant Payment Notification, is how PayPal sends back the response to your API call.
When you send an e-commerce type payment, say from your checkout, to PayPal, you also send a NotifyUrl with it. PayPal will use this Notify Url to send back the response of what happened to the transaction, e.g., was the payment successful.
So, according to the definition above, we’re going to get a ‘message’ back regarding the success of the transaction. That means we need a controller to collect this response and then perform some business logic to complete the customer’s transaction on our website.
I’m assuming two things, one you are already comfortable with rails and two, that you are using Active Merchant . The starting point for this whole post can be found in their integration notificiations documentation. I’m simply making it a little easier to read and current to Rails 2.3.4.
1. Create a controller to handle your notifications.
script/generate controller Notifier
2. In your new controller you can add the following code snippet:
class NotifierController < ApplicationController include ActiveMerchant::Billing::Integrations #put this line in to bypass Rails forgery protection. protect_from_forgery :except => :paypal_ipn def paypal_ipn #instantiate the incoming request notify = Paypal::Notification.new(request.raw_post) #Make sure you pass the CheckoutTransaction ID
#Used by Active Merchant to ensure this request is #really sent by paypal. if notify.acknowledge begin #if your order total is the same as the amount if notify.complete? and sprintf(“%.02f”, order.amount) == params[‘payment_gross’] #Add your own logic here, mine is below. order.success = true order.message = notify.status billing.update_attribute(:next_billing_date, Date.today >> 1) billing.update_attribute(:last_billing_date, Date.today) else #Used for when the ‘spit hits the fan’ logger.error("Failed to verify Paypal’s notification, please investigate") end rescue => e #Failure logic order.success = false order.message = notify.status raise ensure order.save end end #i can’t remember when this changed, but in recent #Rails memory, you need to pass true to render :nothing, #or Rails will look for a :nothing view. not good eats. render :nothing => true end
- in the purchase and include any other variables
#you need here.
order = CheckoutlTransaction.find(notify.invoice)
billing = UserTotals.find_by_user_id(order.user_id)
As you can see from the comments within the code snippet,
3. Fix your routes to something like this.
map.paypal_ipn "/notifier/paypal_ipn", :controller => "notifier", :action => "paypal_ipn"
PayPal has done a good job with this IPN and it’s quite useful for ensuring your Orders are only completed after the transaction has been successful.