iie labs

Using the PayPal IPN with Rails

Posted almost 5 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.

What is IPN Notification?

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.

Using IPN’s with Rails

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
  1. 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)
#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

end

As you can see from the comments within the code snippet,

  • we’re verifying that paypal is the sender of this request.
  • if it is, we then look for the Order and any other variables you need to update.
  • as long as the amount is the same as the one we are expecting, we then process the order as if it were a complete good order.
  • if anything goes wrong, you’ll see that error message in your logs.

3. Fix your routes to something like this.


map.paypal_ipn "/notifier/paypal_ipn", :controller => "notifier", :action => "paypal_ipn"

Conclusion

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.

Comments

blog comments powered by Disqus