Razorpay Integration
Razorpay Integration

Razorpay Integration

Created
Apr 8, 2022 8:13 AM
Department
Engineering
Category
Well Documented
Technology
Ruby on Rails
Tags
Date
URL

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.
  3. image

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
  4. require 'razorpay'
    
    Razorpay.setup(Rails.application.credentials.dig(:razorpay_key_id),Rails.application.credentials.dig(:razorpay_secret_token)
  5. Next, create a module called razorpay_payment.rb inside the concerns folder, here generate the Razorpay Order like so
  6. 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 -
  2. 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
  3. Return back the order response to the client-side application with the needed values. Order id and amount_due are mandatory as they will be needed to show the Razorpay pop-up.
  4. 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 so
  5. Razorpay::Utility.verify_payment_signature(payment_response)
  6. 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.
  7. 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.
    6. image
  5. Click Create Webhook.

Once created, it appears on the list of webhooks:

image

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.
  2. post "/webhooks/process/:webhook_source",  controller: :webhooks, action: :process
  3. Create a controller for this route that will handle the webhook event and also manage in case of the particular webhook fires multiple times to avoid multiple order creations for the same webhook event. We'll need a model to store the webhook events which is discussed in later steps.
  4. 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
  5. Generate a WebhookEvent model with the following table columns source:integer, payload:json, event_type:string, status:integer, webhook_event_id:string.
  6. Create an after_commit method
  7. def perform_webhook_job
      ProcessWebhookJob.perform_later(self)
    end

    The above ProcessWebhookJob will be discussed in later steps.

  8. Define an instance method that 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.
  9. def process_webhook
      case source
        when 'razorpay'
          send("handle_razorpay_#{event_type}")
        end
    end
  10. Create a new file called process_webhook_job.rb. Here write a perform method that will call the process_webhook model instance method.
  11. def perform(webhook_event)
      webhook_event.process_webhook
    end
  12. Create a new concern in your model concerns folder called razorpay_webhook.rb. Here the actual handler method will be written.
  13. Fetch the razorpay order id from the webhook payload
  14. razorpay_order_id = payload.dig('payload', 'order', 'entity', 'id')
  15. Using this order id find the cart and then go ahead with the creation of the product order or subscription.
  16. 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.
  4. image
  5. 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’
  6. image
  7. To generate live keys switch to ‘live mode’ and follow the instructions given in Prerequisites step 2.

Note:

  • For more information, you can check out the official Razorpay documentation on this link.