Skip to content


Cecile Veneziani edited this page · 2 revisions
Clone this wiki locally

Adyen sends notifications to your server to inform you about any activity on their side. Adyen is able to send these notifications as SOAP requests or as simple HTTP POST requests. For now, this library only supports handling HTTP POST notifications, because handling SOAP requests would require setting up a SOAP server.

It is advised to always store every (non-duplicate) notification that you receive for accountability reasons. Because of this, the library provides an ActiveRecord based class to store them in the database.

Creating the notification model

Generate the notification model and its migration with:

$ rails g adyen:notification
$ rake db:migrate

Receiving notifications via HTTP POST

In the Adyen merchant environment, you can provide an URL to which the notifications should be posted. Make sure that you choose HTTP POST as method instead of SOAP. For security reasons, it's best to choose an https-based url and use authentication credentials as well.

Adyen sends the notification details as POST parameters to your action. For more information about what information is being sent, please refer to the Adyen integration manual. You can store all this information from the request into a record with Adyen::Notification::HttpPost.log(request). You can access all fields using snake_case notation instead of the camelCase notation Adyen uses, so eventCode becomes @notification.event_code. After it has been stored, you can perform some action based on its contents. After the notification has been handled, you can set the processed field to true.

An example controller implementation:

class AdyenController < ActionController::Base
  before_filter :authenticate

  # POST
  def notify
    @notification = AdyenNotification.log(params)
  rescue ActiveRecord::RecordNotUnique, ActiveRecord::RecordInvalid => e
    # Validation failed, because of the duplicate check.
    # So ignore this notification, it is already stored and handled.
    # Always return that we have accepted the notification
    render :text => '[accepted]'

  # Enable HTTP basic authentication
  def authenticate
    authenticate_or_request_with_http_basic do |username, password|
      username == 'something_you_chose' && password == 'very$ecret'

And the corresponding AdyenNotification model : (you can retrieve the original notification in all the notifications associated to a 'AUTHORIZATION' notification)

# app/models/AdyenNotification.rb
class AdyenNotification < ActiveRecord::Base
  belongs_to :user, :class_name => "User", :foreign_key => "merchant_reference"
  belongs_to :original_notification, :class_name => "AdyenNotification", :foreign_key => "original_reference", :primary_key => "psp_reference"

  def handle!
    if success?
      case event_code
      when 'AUTHORISATION'

        # A payment authorized successfully, so handle the payment
        # ...
        # flag the notification so we know that it has been processed
        # User.find(shopper_reference.to_i).renew_premium!(1.month)
        time_of_premiumness = AMOUNTS.invert[(value * 100).to_i].months
        update_column(:processed, true)
      when 'CANCEL_OR_REFUND'
        time_of_premiumness = AMOUNTS.invert[(original_notification.value * 100).to_i].months
        update_column(:processed, true)
        # Handle a new recurring contract
        # ...
        update_column(:processed, true)

To test that, you just have to test your model with cucumber:

Feature: Notifications
  In order to be more accurate
  As an admin
  I want to be able to refund or cancel some payment

    And I have signed in with ""

  Scenario: Refund someone
    Given The application receive a valid subscription request for user ""
    Then "" should be a premium member
    Given The application receive a valid cancel or refund request for user ""
    Then "" should not be a premium member

And in your adyen_steps.rb

Given /^The application receive a valid subscription request for user "([^\"]*)"$/ do |email|
  sub_notif = Factory.create :subscription_notification, :user => User.find_by_email(email)

Given /^The application receive a valid cancel or refund request for user "([^\"]*)"$/ do |email|
  u = User.find_by_email(email)
  corn = Factory.create :cancel_or_refund_notification, :original_notification => u.last_successful_operation, :user => u

Then /^"([^\"]*)" should be a premium member$/ do |email|
  User.find_by_email(email).premium_member?.should be(true)

Then /^"([^\"]*)" should not be a premium member$/ do |email|
  User.find_by_email(email).premium_member?.should be(false)

And in your Factorygirl factories:

Factory.define :user do |user|
  user.first_name "Kevin"

Factory.sequence :psp_reference do |n|

Factory.define :adyen_notification do |notification|                   false
  notification.user                   {Factory{:user}}
  notification.merchant_account_code  "mac"
  notification.processed              false
  notification.psp_reference          { :psp_reference}
  notification.currency               "EUR"

Factory.define :successful_adyen_notification, :parent => :adyen_notification do |notification|
  notification.success                true

Factory.define :subscription_notification, :parent => :successful_adyen_notification do |notification|
  notification.event_code             "AUTHORISATION"
  notification.payment_method         "visa"
  notification.operations             "CANCEL CAPTURE REFUND"
  notification.reason                 "40735:1111:12/2012"
  notification.value                  74.97
  notification.processed              true

Factory.define :cancel_or_refund_notification, :parent => :successful_adyen_notification do |notification|
  notification.event_code             "CANCEL_OR_REFUND"
  notification.original_notification  {Factory{:subscription_notification}}

The Adyen::Notification model uses validations to check whether the notification is a duplicate. Duplicates can safely be ignored.

Something went wrong with that request. Please try again.