← Back to Blog

A Step-by-Step Guide to Integrating Razorpay with ERPNext for Automated Payments

By WovLab Team | March 08, 2026 | 10 min read

Why You Need to Automate ERPNext Payment Entries with Razorpay

In a fast-paced digital economy, manual data entry is more than just a chore; it's a significant bottleneck that costs your business time and money. For every online payment you receive through Razorpay, a corresponding manual entry must be created in ERPNext. This process is slow, tedious, and fraught with the risk of human error. Studies show that manual data entry processes can have error rates as high as 4%, which can lead to disastrous reconciliation headaches, inaccurate financial reporting, and delayed cash flow visibility. When your finance team spends hours cross-referencing Razorpay settlements with bank statements and then keying them into ERPNext, they aren't performing high-value analysis; they're doing robotic work. The solution is to integrate Razorpay with ERPNext, creating a fully automated workflow that posts payment data in real-time.

Automating this link means that the moment a customer payment is successfully captured by Razorpay, a corresponding Payment Entry or Journal Entry is instantly and accurately created in your ERPNext system. This eliminates the data entry lag, which can often be days, providing you with an immediate and precise view of your company's cash position. It frees up your finance personnel to focus on strategic tasks like forecasting and financial analysis instead of mundane data transcription. Furthermore, automation ensures that every transaction is accounted for, significantly simplifying the audit process and ensuring compliance. The invoice status is updated automatically, customers get their receipts faster, and your entire order-to-cash cycle is accelerated.

The core benefit of integrating Razorpay with ERPNext is transforming your financial operations from a reactive, manual process into a proactive, real-time system. This shift provides unparalleled accuracy and frees up critical resources, directly impacting your bottom line.

Prerequisites: Getting Your Razorpay API Keys and ERPNext Instance Ready

Before you can begin building the bridge between Razorpay and ERPNext, you need to ensure you have the necessary credentials and access permissions from both platforms. This foundational step is critical for a smooth integration process. Think of it as gathering your tools and materials before starting construction. On the Razorpay side, you'll need to generate API keys, which act as secure credentials that allow your ERPNext system to communicate with Razorpay's services. On the ERPNext side, you need administrator-level access to install custom scripts and configure the system to listen for incoming data from Razorpay.

Here’s a checklist of everything you'll need:

  1. An Active Razorpay Account: You must have a live, registered Razorpay account. If you are in test mode, you can use test API keys, but you will need live keys for production payments.
  2. Razorpay API Keys:
    • Log in to your Razorpay Dashboard.
    • Navigate to SettingsAPI Keys.
    • Click Generate Live Key (or Test Key for development).
    • You will receive a Key ID and a Key Secret. The Key ID is public, but the Key Secret must be stored securely and never exposed in client-side code. You will need both for the integration.
  3. An Active ERPNext Instance: Your ERPNext site must be up and running, accessible via a public URL. Localhost installations will not work as Razorpay's servers need a public endpoint to send data to.
  4. ERPNext Administrator Access: You must have a user account with the System Manager role. This is required to create new Server Scripts and customize doctypes, which are essential components of this integration.

Finally, it's highly recommended to perform the initial setup on a development or staging version of your ERPNext instance. This allows you to test the entire workflow without affecting your live financial data. Once you've confirmed everything works as expected, you can then deploy it to your production environment.

Step 1: Setting Up the Razorpay Webhook for Payment Events

The core of this real-time automation is the webhook. A webhook is an automated message sent from an app (in this case, Razorpay) to another app (ERPNext) when a specific event occurs. For our purpose, the key event is a successful payment. By setting up a webhook, you're telling Razorpay, "Hey, every time a payment is captured, send all the details to this specific URL on my ERPNext server." This is far more efficient than constantly asking Razorpay if a payment has been made (a method known as polling).

Follow these steps to configure your webhook in the Razorpay dashboard:

  1. Log in to your Razorpay Dashboard and navigate to Settings in the left-hand menu, then select Webhooks.
  2. Click the + Add New Webhook button.
  3. You will see a form to configure the webhook. The most important fields are:
    • Webhook URL: This is the public URL where your ERPNext instance will listen for incoming data. It should follow this format: `https:///api/method/wovlab_razorpay_handler`. You can name the method (the last part of the URL) whatever you like, but remember it for the next step.
    • Secret: This is a password you create. Razorpay will use it to create a unique digital signature for every webhook it sends. Your ERPNext script will use this same secret to verify that the webhook is genuinely from Razorpay and not a malicious third party. This is a critical security measure.
    • Alert Email: Enter your email to be notified if the webhook fails repeatedly.
    • Active Events: This is where you tell Razorpay which events should trigger the webhook. For our primary goal, you must select payment.captured. This event fires only after the payment is successfully authorized and captured by Razorpay. You might also consider adding `refund.processed` to automate refund entries.
  4. Once you have filled in the details, click Create Webhook. Your webhook is now active and will attempt to send data to your ERPNext URL whenever a selected event occurs.

Choosing the right event is crucial. Using `payment.captured` instead of `order.paid` ensures you are only recording payments that have been fully secured in your bank account, preventing discrepancies from payments that are authorized but not captured.

Step 2: Creating a Custom Server Script in ERPNext to Handle the Webhook

Now that Razorpay knows where to send the data, you need to prepare ERPNext to receive and process it. This is done by creating a Server Script that corresponds to the Webhook URL you defined in the previous step. This script is a piece of Python code that runs on the Frappe framework (the foundation of ERPNext). It will be responsible for three key tasks: securely validating the incoming request, parsing the payment data, and triggering the creation of a new document in ERPNext.

Here’s how to set up the script:

  1. In your ERPNext desk, type "Server Script" in the awesome bar and navigate to the Server Script List.
  2. Click + Add Server Script.
  3. Fill in the form with the following details:
    • Name: Give it a descriptive name, like "Razorpay Webhook Handler".
    • Script Type: Set this to API. This makes the script accessible via the API endpoint we specified in Razorpay.
    • Method Name: This must exactly match the method name from your Webhook URL (e.g., `wovlab_razorpay_handler`).
    • Allow Guest: Tick this checkbox. This is essential because the request is coming from Razorpay's server, which is not a logged-in user in your ERPNext system.
    • Script: This is where you'll write the Python code.

Your initial script should focus solely on security: verifying the webhook signature. Without this check, anyone could send fake payment data to your endpoint. The code below demonstrates how to validate the request using the Secret you created in the Razorpay dashboard.


import frappe
import json
import hmac
import hashlib

# Replace this with the actual secret you created in the Razorpay Webhook setup
WEBHOOK_SECRET = 'your_webhook_secret_here'

@frappe.whitelist(allow_guest=True)
def wovlab_razorpay_handler():
    # 1. Get the raw request body and the signature from the headers
    webhook_body = frappe.request.data
    webhook_signature = frappe.request.headers.get('X-Razorpay-Signature')

    if webhook_body and webhook_signature:
        try:
            # 2. Verify the signature
            expected_signature = hmac.new(
                key=WEBHOOK_SECRET.encode('utf-8'),
                msg=webhook_body,
                digestmod=hashlib.sha256
            ).hexdigest()

            # 3. Securely compare the signatures
            if hmac.compare_digest(expected_signature, webhook_signature):
                # Signature is valid, proceed with processing
                # We will add the logic for this in the next step
                frappe.log_error("Razorpay Signature Verified", "Razorpay Webhook")
                process_razorpay_event(json.loads(webhook_body))
                return {"status": "ok"}
            else:
                # Signature is invalid
                frappe.throw("Invalid Razorpay Signature", frappe.AuthenticationError)

        except Exception as e:
            frappe.log_error(frappe.get_traceback(), "Razorpay Webhook Error")
            frappe.throw("Error processing Razorpay webhook")
    
    frappe.throw("Missing Razorpay payload or signature")

def process_razorpay_event(data):
    # This function will contain the logic from Step 3
    pass

Security First: The `hmac.compare_digest` function is used for a "constant-time" comparison, which prevents timing attacks. Never use a simple `==` comparison for cryptographic signatures.

After saving this script, your endpoint is live and secure. It can now authenticate requests from Razorpay, but it doesn't do anything with the data yet. That's the final piece of the puzzle.

Step 3: To integrate Razorpay with ERPNext, you must map the payment data to fields

This is the final and most crucial step where the automation comes to life. Once the webhook is verified, the `process_razorpay_event` function will take the JSON data from Razorpay and use it to create a Payment Entry document in ERPNext. This involves carefully mapping the fields from the Razorpay payment object to the corresponding fields in the ERPNext Payment Entry doctype. The most common use case is to apply the payment against a specific Sales Invoice.

To achieve this, you need to pass the ERPNext `Sales Invoice` ID to Razorpay when you create the payment link or order. This is typically done using the `notes` field in the Razorpay API. For example, when creating an order, you would include: `"notes": {"sales_invoice_id": "SINV-00123", "customer_id": "CUST-0001"}`. Your webhook script can then retrieve this ID to link the payment correctly.

The following table shows the essential mapping between the Razorpay payload and the ERPNext document:

Razorpay Payload Field (JSON Path) ERPNext Payment Entry Field Notes
`payload.payment.entity.id` `reference_no` The unique Razorpay Payment ID. Used to prevent duplicate entries.
`payload.payment.entity.amount` `paid_amount` Must be divided by 100 (e.g., 50000 -> 500.00).
`payload.payment.entity.notes.sales_invoice_id` `references[0].reference_name` The ERPNext Sales Invoice ID you passed in the notes.
`payload.payment.entity.notes.customer_id` `party` The ERPNext Customer ID.
`payload.payment.entity.created_at` `reference_date` The date of the transaction (needs conversion from UNIX timestamp).

Now, let's implement this logic in our `process_razorpay_event` function within the Server Script.


# This function is called by the main handler after signature verification
def process_razorpay_event(data):
    if data.get('event') == 'payment.captured':
        payment = data['payload']['payment']['entity']
        razorpay_payment_id = payment['id']

        # Idempotency Check: Prevent creating duplicate payment entries
        if frappe.db.exists("Payment Entry", {"reference_no": razorpay_payment_id}):
            frappe.log_error("Duplicate Razorpay payment received", f"Payment Entry for {razorpay_payment_id} already exists.")
            return

        try:
            invoice_id = payment['notes']['sales_invoice_id']
            customer_id = payment['notes']['customer_id']
            amount = float(payment['amount']) / 100

            # Create the new Payment Entry document
            new_payment = frappe.get_doc({
                "doctype": "Payment Entry",
                "payment_type": "Receive",
                "mode_of_payment": "Razorpay", # Ensure this Mode of Payment exists in ERPNext
                "party_type": "Customer",
                "party": customer_id,
                "paid_amount": amount,
                "received_amount": amount,
                "reference_no": razorpay_payment_id,
                "reference_date": frappe.utils.getdate(frappe.utils.now_datetime()),
                "posting_date": frappe.utils.getdate(frappe.utils.now_datetime()),
                "references": [{
                    "reference_doctype": "Sales Invoice",
                    "reference_name": invoice_id,
                    "allocated_amount": amount
                }]
            })
            new_payment.insert(ignore_permissions=True)
            new_payment.submit()
            frappe.db.commit() # Crucial to save the transaction
        
        except Exception as e:
            frappe.log_error(message=frappe.get_traceback(), title="Razorpay Payment Creation Failed")

With this final piece of code, your integration is complete. When a payment is captured, Razorpay sends a signed webhook, your ERPNext script verifies it, extracts the data, and automatically creates and submits a Payment Entry against the correct Sales Invoice. Your accounts are updated in real-time, no human intervention required.

Need an Expert? WovLab Can Build Your Custom ERP and Payment Gateway Integration

This guide provides a powerful blueprint to integrate Razorpay with ERPNext. However, a production-grade system often requires more sophistication. Real-world business operations involve handling complex scenarios like partial payments, excess payments, processing refunds automatically, managing subscription billing cycles, and handling payment failures or disputes. A robust integration must include comprehensive error logging, retry mechanisms for transient network failures, and a dashboard for monitoring the status of automated transactions. Furthermore, your specific business rules might require linking payments to other documents like Sales Orders or Projects, not just Sales Invoices.

This is where expert implementation becomes invaluable. At WovLab, a leading digital and AI agency headquartered in India, we specialize in exactly these types of complex, business-critical integrations. We don't just build software; we engineer financial workflows that are scalable, secure, and perfectly aligned with your operational needs. Our deep expertise in the Frappe framework, coupled with our experience across hundreds of payment gateway and ERP projects, allows us to foresee challenges and build solutions that handle the edge cases from day one.

Whether you need to enhance this basic integration, connect multiple payment gateways, or build a completely bespoke ERP system from the ground up, our team is ready to help. We offer a full suite of services, from cloud infrastructure and custom development to AI-powered process automation and SEO. Don't let manual processes dictate your efficiency. Let WovLab build the hardened, reliable integration that allows your business to scale. Contact us at wovlab.com to discuss how we can put our expertise to work for you.

Ready to Get Started?

Let WovLab handle it for you — zero hassle, expert execution.

💬 Chat on WhatsApp