Link Search Menu Expand Document
  1. Razorpay Ruby on Rails Integration
    1. Prerequisites
    2. Rails Integration
    3. Webhooks
    4. Razorpay Dashboard

Razorpay Ruby on Rails Integration

Prerequisites

  1. Create a Razorpay Account
  2. After creating the account switch to test mode; and go to settings in the left navigation panel. Click on API Keys and click on Generate Keys . Safely store the Id and Secret.

        Razorpay admin panel

Rails Integration

  1. Open the rails credentials and put the key_id and key_secret obtained in the previous step under test, development and staging environments.
  2. In the Gemfile add the gem razorpay and do bundle install.
  3. Create a file inside the config/initializers folder called razorpay.rb. Here require the razorpay library and set it up like so

     require 'razorpay'
    
     Razorpay.setup(Rails.application.credentials.dig(:razorpay_key_id),Rails.application.credentials.dig(:razorpay_secret_token)
    
  4. Next, create a module called razorpay_payment.rb inside the concerns folder, here generate the Razorpay Order like so

     order = Razorpay::Order.create amount: order_amount, currency: cart.total_amount.currency.iso_code, receipt: cart.uuid, payment_capture: 1
     cart.update!(razorpay_order_id:order.id) 
    

The options payment_capture: 1 tells Razorpay that the payment that will be made against this order will be captured automatically. The receipt argument is an optional one.

The response that will be stored in the order variable is structured like this

{
	"id": "order_DBJOWzybf0sJbb",
	"entity": "order",
	"amount": 50000,
	"amount_paid": 0,
	"amount_due": 50000,
	"currency": "INR",
	"receipt": "rcptid_11",
	"status": "created",
	"attempts": 0,
	"notes": [],
	"created_at": 1566986570
}

Make sure to store the id that's returned by razorpay in this step in the database as this will be used to verify and fetch Cart or whatever you're making the order for.

  1. Write a mutation that the FE will hit to create a Razorpay Order.

    Example -

     field:createRazorpayOrder, Types::Objects::RazorpayOrderResponseType do
         description "Create a Razorpay order for checkout"
         argument:cart_uuid, !types.String
    
         resolve -> (_, args, _) {
             order_response = []
             cart = Cart.find_by(uuid:args[:cart_uuid])
             raise Exceptions::InvalidCartId.new("Cart not found") if cart.nil?
             order_response = cart.find_or_create_razorpay_order()
             order_response
         }
     end
    
  2. Return back the order response to the client-side application with the needed values. Order's id and amount_due is mandatory as that will be needed to show the Razorpay pop-up.
  3. The client side will make the payment against the given order_id and Razorpay will generate razorpay_payment_id and razorpay_signature for the razorpay_order_id created in the previous step and send it to the client side callback or handler function. You can request the payment_response from the client side to verify the payment using the method provided by Razorpay to verify the payment like so

     Razorpay::Utility.verify_payment_signature(payment_response)
    
  4. Create a mutation that the client side will hit after the payment is made to verify and then process the cart order, subscription or whatever the payment was done for. Fetch the order from Razorpay using the order_id that was stored in Step 4 and using the order_id given to the server by client side, use the stored order_id ONLY.

     field:verifyRazorpayPayment, Types::Objects::OrderType do
         description "Verify a Razorpay payment"
         argument:cart_uuid, !types.String
    
         resolve -> (_, args, _) {
             cart = Cart.find_by(uuid:args[:cart_uuid])
             fetched_order = Razorpay::Order.fetch(cart.razorpay_order_id)
             order = cart.create_platform_order(fetched_order)
             order
         }
     end
    

    Note: Make sure to have only one method for creating an order or subscription which also will contain the verification of the payment. If the fetched_order status is paid then proceed. This single method could be reused when webhooks will be implemented.

     def create_platform_order(fetched_order)
         return self.order if self.order.present?
         order = nil
         order_creation_status = {}
    
         if fetched_order.status == 'paid'
             Order.transaction do
                 # Create your order
             end
         else
             raise Exceptions::PaymentFailed
         end
     end
    
    

Webhooks

Webhooks (https://razorpay.com/docs/webhooks/) are automated messages sent from apps when something happens. In this case suppose the communication between the bank and Razorpay or between you and Razorpay did not take place. This could be because of a slow network connection or your customer closing the window while the payment is being processed. This could lead to a payment being marked as Failed on the Razorpay Dashboard, but changed to Authorized at a later time.

You can use webhooks to get notified about payments that get authorized and analyze this data to decide whether or not to capture the payment.

  1. Set up webhooks on the Dashboard
  2. Log into your Razorpay Dashboard and navigate to SettingsWebhooks.
  3. Click + Add New Webhook.
  4. In the Webhook Setup modal: 1. Enter the URL where you want to receive the webhook payload when an event is triggered. We recommended using an HTTPS URL. 2. Note : Webhooks can only be delivered to public URLs. If you attempt to save a localhost endpoint as part of a webhook set-up, you will notice an error. Please refer to the test webhooks section for alternatives to localhost. 3. Enter a Secret for the webhook endpoint. The secret is used to validate that the webhook is from Razorpay. Do not expose the secret publicly. Learn more about Webhook Secret. 4. In the Alert Email field, enter the email address to which notifications must be sent in case of webhook failure. 5. Select the required events from the list of Active Events. Sample payloads for all events are available. Webhook
  5. Click Create Webhook.

Once created, it appears on the list of webhooks:

Webhook list

Watch the short video below for more details. Razorpay webhook setup

Add a listener for the webhook in the code

  1. Add a post route in routes.rb that will listen for the webhook events.

     post "/webhooks/process/:webhook_source",  controller: :webhooks, action: :process 
    
  2. Create a controller for this route which will handle the webhook event and also manage in case the particular webhook fires multiple times to avoid multiple order creation for the same webhook event. We'll need a model to store the webhook events which is discussed in later steps.

     class WebhooksController < ApplicationController
    
         def process(webhook_source)
             case params[:webhook_source]
             when 'razorpay'
                 Razorpay::Utility.verify_webhook_signature(request.raw_post, request.headers["X-Razorpay-Signature"], Rails.application.credentials.dig(:razorpay_webhook_signature)
                 webhook_event = WebhookEvent.find_by(webhook_event_id:  request.headers['x-razorpay-event-id'])
                 process_razorpay(params, request) if webhook_event.nil?
             end
         head:ok
         end
    
         private
         def process_razorpay(params, request)
             WebhookEvent.create!(source: params[:webhook_source], payload: params.as_json, event_type: params[:event].gsub('.', '_'), webhook_event_id: request.headers['x-razorpay-event-id'])
         end
     end
    
    
  3. Generate a WebhookEvent model with the following table columns source:integer, payload:json, event_type:string, status:integer, webhook_event_id:string.

  4. Create an after_commit method

     def perform_webhook_job
         ProcessWebhookJob.perform_later(self)
     end
    

    The above ProcessWebhookJob will be discussed in later steps.

  5. Define an instance method which will be called in the ProcessWebhookJob to handle the webhooks. The method is generalized so it's able to handle webhooks other than Razorpay as well.

     def process_webhook
         case source
             when 'razorpay'			
                 send("handle_razorpay_#{event_type}")
             end
     end
    
  6. Create a new file called process_webhook_job.rb. Here write a perform method which will call the process_webhook model instance method.

     def perform(webhook_event)
         webhook_event.process_webhook
     end
    
  7. Create a new concern in your model concerns folder called razorpay_webhook.rb. Here the actual handler method will be written.

  8. Fetch the razorpay order id from the webhook payload

     razorpay_order_id = payload.dig('payload', 'order', 'entity', 'id')
    
  9. Using this order id find the cart and then go ahead with the creation of the product order or subscription.

     def handle_razorpay_order_paid
         razorpay_order_id = payload.dig('payload', 'order', 'entity', 'id')
    
         cart = Cart.find_by(razorpay_order_id: razorpay_order_id) 
         if cart
             fetched_order = Razorpay::Order.fetch(cart.razorpay_order_id)
             cart.create_platform_order(fetched_order)
         end
     end
    

Razorpay Dashboard

  1. Login to the Razorpay dashboard (http://dashboard.razorpay.com/) and sign in.
  2. Go to 'Transactions' in the left navigation panel.
  3. Here the 'Payments' and 'Orders' tab will be present and you can check the payments and orders to verify them yourself.

    Dashboard

  4. If you want to refund a particular payment that option will also be available, click on the payment_id in the 'Payments' tab and click on 'Issue Refund'

    Refund

  5. To generate live keys switch to 'live mode' and follow the instructions given in Prerequisites step 2.

Note: