Paypal express checkout using ActiveMerchant and Instant Payment Notification (IPN)

Instant Payment Notification (IPN) is a message service that notifies you of events related to PayPal transactions.

You can use IPN messages to automate back-office and administrative functions, such as fulfilling orders, tracking customers, and providing status and other transaction-related information or other kind of things, like emailing your customers upon purchase and offers.

Remember that if you are using Express Checkout or Direct Payment, the PayPal API notifies you of the status and details of the transaction immediately and automatically. This means that you need not use IPN for knowing the transaction status, because you will know the transaction status immediately.

This is the IPN flow:


1 A user clicks a PayPal button to kick off a checkout flow; your web application makes an API call; your back-office system makes an API call; or PayPal observes an event.

2 PayPal HTTP POSTs your listener a message that notifies you of this event.

3 Your listener returns an empty HTTP 200 response.

4 Your listener HTTP POSTs the complete, unaltered notification back to the PayPal.

Note: This message must contain the same fields, in the same order, as the original notification, all preceded by cmd=_notify-validate. Further, this message must use the same encoding as the original.

5 PayPal sends a single word back – either VERIFIED (if the message matches the original) or INVALID (if the message does not match the original).

IPN sends post data to the IPN listener so… have a route defined for this.

This is a basic payment method:

def payment
  item = Item.find(params[:id])
  response = EXPRESS_GATEWAY.setup_purchase(item.price_in_cents,{
    :ip                => request.remote_ip,
    :currency_code     => '...',
    :return_url        => success_url(item)
    :notify_url        => notify_url(item),
    :cancel_return_url => cancel_url(item)
  item.update_attribute :express_token, response.token
  redirect_to EXPRESS_GATEWAY.redirect_url_for(response.token)

This is the success url:

def success
  details = EXPRESS_GATEWAY.details_for(express_token)
  response = EXPRESS_GATEWAY.purchase(item.price_in_cents,{
    :ip               => request.remote_ip,
    :currency_code    => '...',
    :token            => express_token,
    :payer_id         => details.payer_id

  if response.success?
    flash[:success] = "Your transaction was successfully completed"
    flash[:error] = "Your transaction could not be compelted"


…and here is a typical handler for IPN with ActiveMerchant:

class BackendController < ApplicationController
  include ActiveMerchant::Billing::Integrations

  def paypal_ipn
    notify =

    order = Order.find(notify.item_id)

    if notify.acknowledge

        if notify.complete? and == notify.amount
          order.status = 'success'

          logger.error("Failed to verify Paypal's notification, please investigate")

      rescue => e
        order.status        = 'failed'

    render :nothing

One more thing: aknowledge method has to be called after a new ipn arrives. Paypal will verify that all the information we received are correct and will return a ok or a fail.

This is the acknowledge method on ActiveMerchant module:

def acknowledge(authcode = nil)
  payload =  raw

  response = ssl_post(Paypal.service_url + '?cmd=_notify-validate', payload,
    'Content-Length' => "#{payload.size}",
    'User-Agent'     => "Active Merchant --"

  raise"Faulty paypal result: #{response}") unless ["VERIFIED", "INVALID"].include?(response)

  response == "VERIFIED"

Here are some references

ActiveMerchant Notification module:

ActiveMerchant IPN Documentation:

Paypal IPN Documentation:

Leave a Reply