Step-by-Step Guide: How to Integrate Razorpay Payment Gateway in a PHP Website
Prerequisites: Setting Up Your Razorpay Account and PHP Environment
Before you can integrate Razorpay payment gateway in a PHP website, a foundational setup is essential. This initial phase ensures you have all the necessary credentials and a compatible server environment, preventing common roadblocks later in the development process. The first step is to create a Razorpay account. Navigate to the Razorpay dashboard and sign up. You will operate in Test Mode initially, a sandboxed environment that allows you to simulate transactions without any real money involved. This is crucial for development and testing. Once you are ready to accept actual payments, you can complete the activation process to switch to Live Mode. Inside your dashboard, locate the API Keys section (usually under Settings). Here, you will generate your Key ID and Key Secret. Treat these credentials like passwords; they should never be exposed in client-side code or committed to public version control repositories. We recommend storing them as environment variables on your server for maximum security.
On the technical side, your PHP environment must meet specific requirements. Your server should be running PHP version 7.4 or higher to ensure compatibility with modern libraries and security standards. Additionally, two critical PHP extensions must be enabled: cURL, which allows your server to communicate with external APIs like Razorpay, and JSON, which is used for handling the data exchanged with the API. Finally, you must have Composer, the de-facto dependency manager for PHP, installed on your development machine and/or server. Composer simplifies the process of including third-party libraries, like the Razorpay PHP SDK, into your project.
| Component | Requirement | Notes |
|---|---|---|
| Razorpay Account | Active account with API Keys | Start in Test Mode. Keep Key ID and Key Secret secure. |
| PHP Version | 7.4+ | Ensures compatibility and access to modern language features. |
| PHP Extensions | cURL, JSON | Essential for API communication and data handling. |
| Dependency Manager | Composer | Required to install and manage the Razorpay PHP SDK. |
Ensuring these prerequisites are met before you write a single line of integration code will create a smoother, more secure, and more efficient development workflow. It lays the groundwork for a robust payment system that you can rely on.
Step 1: Installing the Razorpay PHP SDK & Creating an Order
With your environment prepared, the first server-side action is to install the official Razorpay PHP SDK. This library acts as a powerful wrapper around the Razorpay API, abstracting away the complexities of raw HTTP requests and providing a clean, object-oriented interface. Using Composer, open your project's terminal and run the following command:
composer require razorpay/razorpay-php
This command downloads the SDK and configures your project's autoloader to include it. Now, you can access its classes from anywhere in your PHP application. The next critical task is to create an "Order" on the server. An order is a server-generated entity that dictates the payment amount and currency. This is a vital security measure. By creating the order on your server, you prevent malicious users from tampering with the payment amount in the browser's frontend code.
Creating the payment order on your server is non-negotiable for security. It establishes an authoritative record of the transaction amount, preventing client-side price manipulation and ensuring you get paid correctly for your goods or services.
Here’s a practical PHP script to create an order. This script would typically be called via AJAX from your checkout page before the payment button is rendered.
<?php
require('vendor/autoload.php');
use Razorpay\Api\Api;
// Replace with your actual Key ID and Key Secret
$keyId = 'YOUR_KEY_ID';
$keySecret = 'YOUR_KEY_SECRET';
$api = new Api($keyId, $keySecret);
// Amount in the smallest currency unit (e.g., paise for INR). 10000 paise = ₹100.00
$amount = 10000;
$currency = 'INR';
// A unique identifier for the order from your system
$receiptId = 'receipt_'.uniqid();
$orderData = [
'receipt' => $receiptId,
'amount' => $amount,
'currency' => $currency,
'payment_capture' => 1 // Auto-capture the payment
];
$razorpayOrder = $api->order->create($orderData);
$razorpayOrderId = $razorpayOrder['id'];
// Store this order_id in your session or database against the user
$_SESSION['razorpay_order_id'] = $razorpayOrderId;
$data = [
"key" => $keyId,
"amount" => $amount,
"name" => "WovLab",
"description" => "Digital Solutions",
"image" => "https://wovlab.com/logo.png",
"prefill" => [
"name" => "John Doe",
"email" => "john.doe@example.com",
"contact" => "9999999999",
],
"notes" => [
"address" => "WovLab Corporate Office",
"merchant_order_id" => $receiptId,
],
"theme" => [
"color" => "#3399cc"
],
"order_id" => $razorpayOrderId,
];
// Return the data as JSON to your frontend
header('Content-Type: application/json');
echo json_encode($data);
?>
In this script, we initialize the API, define the order details (note that amount is in paise), and create the order. The most important piece of data returned is the `order_id`. This ID is the crucial link between your server, the Razorpay system, and your frontend checkout form.
Step 2: Implementing the Frontend Razorpay Checkout Form
Once your server can generate an order ID, the next step is to create the user-facing payment interface. Razorpay's Checkout.js library makes this remarkably simple, providing a sleek, responsive, and secure payment modal that handles everything from displaying payment methods to processing OTPs. This approach significantly simplifies PCI DSS compliance, as sensitive card details are never transmitted through your server. The first task is to include the Checkout.js script in your HTML page, typically just before the closing `</body>` tag.
<!-- A button to trigger the payment -->
<button id="rzp-button1">Pay with Razorpay</button>
<script src="https://checkout.razorpay.com/v1/checkout.js"></script>
Next, you need to write the JavaScript code that initializes the checkout process. This script will typically make an AJAX call to the PHP file we created in Step 1 to fetch the order details, including the crucial `order_id`. On receiving the data, it configures the checkout options and binds the payment process to the button.
<script>
document.getElementById('rzp-button1').onclick = function(e){
// Fetch order details from your server
fetch('/create-order.php', { method: 'POST' })
.then(response => response.json())
.then(data => {
var options = {
"key": data.key,
"amount": data.amount,
"currency": "INR",
"name": data.name,
"description": data.description,
"image": data.image,
"order_id": data.order_id, // This is a crucial parameter
"handler": function (response){
// This function is called after a successful payment.
// You must now verify the payment signature on your server.
console.log("Payment successful. Response:", response);
// Send payment details to server for verification
var formData = new FormData();
formData.append('razorpay_payment_id', response.razorpay_payment_id);
formData.append('razorpay_order_id', response.razorpay_order_id);
formData.append('razorpay_signature', response.razorpay_signature);
fetch('/verify-payment.php', {
method: 'POST',
body: formData
})
.then(verifyResponse => verifyResponse.json())
.then(verifyResult => {
if(verifyResult.status === 'success') {
alert('Payment Verified and Successful!');
window.location.href = '/thank-you.php';
} else {
alert('Payment verification failed!');
window.location.href = '/payment-failed.php';
}
});
},
"prefill": data.prefill,
"notes": data.notes,
"theme": data.theme
};
var rzp1 = new Razorpay(options);
rzp1.on('payment.failed', function (response){
// This function is called if the payment fails
alert("Payment Failed: " + response.error.description);
console.error(response.error);
});
rzp1.open();
});
e.preventDefault();
}
</script>
The `handler` function is the most important part of this script. It executes automatically after the customer completes the payment on the Razorpay modal. The function receives a response object containing the `razorpay_payment_id`, the `razorpay_order_id`, and a cryptographic `razorpay_signature`. Your script's job is to immediately POST these three values back to your server for the final and most critical step: signature verification.
Step 3: Securely Verifying the Payment Signature on Your Server
This server-side verification is the cornerstone of a secure payment integration. It is the only reliable method to confirm that a payment was genuinely successful and that the data received from the client has not been tampered with. The `handler` function in your frontend JavaScript initiates this process by sending the payment IDs and the signature to a dedicated verification script on your server (e.g., `verify-payment.php`). Your PHP script must then use the Razorpay SDK to validate the authenticity of this signature.
Never trust client-side callbacks alone. A malicious user could fake a "successful" payment response and redirect to your success page. Server-side signature verification is the only way to cryptographically confirm that Razorpay has processed a payment for a specific order.
The verification logic involves reconstructing the signature on your server using the `order_id` and `payment_id` and comparing it to the signature sent by Razorpay. The SDK simplifies this into a single utility function. If the signatures don't match, the function throws an exception, allowing you to gracefully handle the fraudulent or failed attempt. Here is the complete `verify-payment.php` script:
<?php
require('vendor/autoload.php');
use Razorpay\Api\Api;
use Razorpay\Api\Errors\SignatureVerificationError;
$success = true;
$error = "Payment Failed";
$paymentStatus = 'failed';
if (empty($_POST['razorpay_payment_id']) === false) {
// Replace with your actual Key ID and Key Secret
$keyId = 'YOUR_KEY_ID';
$keySecret = 'YOUR_KEY_SECRET';
$api = new Api($keyId, $keySecret);
try {
// The attributes array must contain razorpay_order_id, razorpay_payment_id, and razorpay_signature
$attributes = [
'razorpay_order_id' => $_POST['razorpay_order_id'],
'razorpay_payment_id' => $_POST['razorpay_payment_id'],
'razorpay_signature' => $_POST['razorpay_signature']
];
$api->utility->verifyPaymentSignature($attributes);
$success = true;
$paymentStatus = 'success';
} catch(SignatureVerificationError $e) {
$success = false;
$error = 'Razorpay Error : ' . $e->getMessage();
}
}
// In a real application, you would now update your database
if ($success === true) {
// --- Step 4 logic goes here ---
// Update your database with the successful payment details
// Mark order as paid
// Redirect to a success page
header('Content-Type: application/json');
echo json_encode(['status' => 'success']);
} else {
// Payment verification failed
// Log the error
// Redirect to a failure page
header('Content-Type: application/json');
http_response_code(400);
echo json_encode(['status' => 'failed', 'error' => $error]);
}
?>
The `try...catch` block is essential. If the `verifyPaymentSignature` function executes without throwing a `SignatureVerificationError`, you can be 100% certain that the payment is authentic and successful. Only then should you proceed to the final step of updating your database and confirming the order to the customer.
Step 4: Storing Transaction Details in Your Database
Once the payment signature has been successfully verified, the final step is to record the transaction details in your database. This persistent record is your system's source of truth. It's essential for order fulfillment, inventory management, accounting, customer support, and handling potential disputes or refunds. Neglecting this step means that even after a successful payment, your system would have no memory of the transaction. Before you can store the data, you need an appropriate database table. A well-structured table is key to maintaining clean and useful data.
| Column Name | Data Type | Description |
|---|---|---|
| `id` | INT, AUTO_INCREMENT | Primary key for the record. |
| `user_id` | INT / VARCHAR | Foreign key linking to your users table. |
| `order_id` | VARCHAR(255) | The `order_id` generated by Razorpay. |
| `razorpay_payment_id` | VARCHAR(255) | The unique ID for the payment, received after success. |
| `amount` | DECIMAL(10, 2) | The transaction amount (in rupees, not paise). |
| `currency` | VARCHAR(3) | The currency of the transaction (e.g., 'INR'). |
| `status` | VARCHAR(20) | 'pending', 'success', or 'failed'. |
| `created_at` | TIMESTAMP | Timestamp when the record was created. |
With the table in place, you can now modify your `verify-payment.php` script. Inside the `if ($success === true)` block, you will add the database logic. It's common practice to first create a record with a 'pending' status when the order is generated (Step 1), and then update it to 'success' upon verification. Here's an example using PDO for secure database operations:
<?php
// --- Inside the successful verification block ---
if ($success === true) {
// Database connection details
$host = 'localhost';
$dbname = 'your_database';
$username = 'your_username';
$password = 'your_password';
try {
$pdo = new PDO("mysql:host=$host;dbname=$dbname", $username, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// Data from the verified payment
$paymentId = $_POST['razorpay_payment_id'];
$orderId = $_POST['razorpay_order_id'];
$status = 'success';
// Find the original amount from your orders table using $orderId
// For this example, let's assume it was 100.00
$amount = 100.00;
// Update the payment record status and save the payment ID
$sql = "UPDATE payments SET razorpay_payment_id = ?, status = ? WHERE order_id = ?";
$stmt = $pdo->prepare($sql);
$stmt->execute([$paymentId, $status, $orderId]);
// Fulfill the order: grant access, ship product, etc.
// ... your application logic here ...
// Send success response
header('Content-Type: application/json');
echo json_encode(['status' => 'success', 'order_id' => $orderId]);
} catch (PDOException $e) {
// Handle DB error
// Log this error for debugging
header('Content-Type: application/json');
http_response_code(500);
echo json_encode(['status' => 'failed', 'error' => 'Database error: ' . $e->getMessage()]);
}
} else {
// ... failure logic ...
}
?>
By using prepared statements (`?` placeholders), you prevent SQL injection vulnerabilities. Once this database update is complete, the payment process is officially finished. You can now confidently redirect the user to a "Thank You" page, send a confirmation email, and trigger your order fulfillment workflow.
Need Expert Help? WovLab’s Seamless Payment Gateway Integration Services
This guide provides a solid foundation to integrate Razorpay payment gateway in a PHP website. However, real-world e-commerce applications often introduce a layer of complexity that goes beyond this basic setup. You might need to handle subscriptions and recurring payments, implement automated refunds, manage Razorpay Webhooks for server-to-server updates, or design a fully custom checkout experience that matches your brand's unique identity.
At WovLab, a premier digital agency headquartered in India, we specialize in building robust, scalable, and secure payment solutions. Our expertise isn't limited to just payment gateways; we offer a full suite of services including AI Agent development, custom software engineering, strategic SEO and GEO marketing, cloud infrastructure management, and end-to-end ERP solutions. We understand the nuances of the Indian market and have extensive experience deploying payment systems that are optimized for performance and reliability.
Why partner with WovLab for your payment integration needs?
- Security First: We implement industry best practices, including secure key management, robust signature verification, and webhook validation, to protect your transactions and your customers' data.
- Scalability: Our solutions are built to grow with your business, whether you're processing ten transactions a day or thousands per hour.
- Holistic Approach: We don't just write code. We analyze your business processes to ensure the payment workflow integrates seamlessly with your inventory, accounting, and CRM systems.
- Full-Service Agency: Beyond payments, we can help you build AI-driven customer service bots, optimize your website for search engines, or develop a custom ERPNext solution to manage your entire operation.
Don't let technical complexities slow down your business growth. Let the experts at WovLab handle the intricacies of payment gateway integration so you can focus on what you do best: serving your customers.
Contact WovLab today at wovlab.com to build a seamless and secure payment experience that drives conversions and builds trust.
Ready to Get Started?
Let WovLab handle it for you — zero hassle, expert execution.
💬 Chat on WhatsApp