Introduction: Payment Integration Made Simple
Integrating payment gateways is essential for any e-commerce or subscription-based application. Razorpay is India's most popular payment gateway, offering seamless integration with Laravel applications. This comprehensive guide will walk you through the complete integration process.
Why Choose Razorpay?
Advantages for Indian Developers
- Local Support: India-based company with local customer support
- Multiple Payment Options: UPI, cards, wallets, net banking
- Quick Setup: Easy registration and approval process
- Competitive Rates: Low transaction fees
- Developer-Friendly: Excellent documentation and SDKs
Supported Payment Methods
- Credit and Debit Cards
- UPI (PhonePe, Google Pay, Paytm)
- Net Banking (all major banks)
- Digital Wallets
- EMI options
Prerequisites and Setup
Before You Start
- Laravel 8+ project setup
- Composer installed
- Basic knowledge of Laravel controllers and routes
- Razorpay account (sign up at razorpay.com)
Razorpay Account Setup
- Create account at razorpay.com
- Complete KYC verification
- Get API keys from dashboard
- Note down Key ID and Key Secret
Step 1: Install Razorpay Package
Using Composer
composer require razorpay/razorpay
Environment Configuration
Add Razorpay credentials to your .env
file:
RAZORPAY_KEY_ID=your_key_id_here
RAZORPAY_KEY_SECRET=your_key_secret_here
Config File Setup
Create config/razorpay.php
:
env('RAZORPAY_KEY_ID'),
'key_secret' => env('RAZORPAY_KEY_SECRET'),
];
Step 2: Create Database Migration
Orders Table Migration
php artisan make:migration create_orders_table
Migration Code
public function up()
{
Schema::create('orders', function (Blueprint $table) {
$table->id();
$table->string('razorpay_order_id');
$table->string('razorpay_payment_id')->nullable();
$table->decimal('amount', 10, 2);
$table->string('currency', 3)->default('INR');
$table->string('status')->default('pending');
$table->json('customer_details');
$table->timestamps();
});
}
Step 3: Create Models and Controllers
Order Model
php artisan make:model Order
Order.php model:
class Order extends Model
{
protected $fillable = [
'razorpay_order_id',
'razorpay_payment_id',
'amount',
'currency',
'status',
'customer_details'
];
protected $casts = [
'customer_details' => 'array'
];
}
Payment Controller
php artisan make:controller PaymentController
Step 4: Implement Payment Logic
PaymentController Implementation
razorpay = new Api(
config('razorpay.key_id'),
config('razorpay.key_secret')
);
}
public function createOrder(Request $request)
{
$amount = $request->amount * 100; // Convert to paise
$orderData = [
'receipt' => 'order_' . time(),
'amount' => $amount,
'currency' => 'INR',
'payment_capture' => 1
];
$razorpayOrder = $this->razorpay->order->create($orderData);
// Save order to database
$order = Order::create([
'razorpay_order_id' => $razorpayOrder['id'],
'amount' => $request->amount,
'customer_details' => [
'name' => $request->name,
'email' => $request->email,
'phone' => $request->phone
]
]);
return response()->json([
'order_id' => $razorpayOrder['id'],
'amount' => $amount,
'key_id' => config('razorpay.key_id'),
'customer' => $order->customer_details
]);
}
public function verifyPayment(Request $request)
{
$razorpayPaymentId = $request->razorpay_payment_id;
$razorpayOrderId = $request->razorpay_order_id;
$razorpaySignature = $request->razorpay_signature;
// Verify signature
$attributes = [
'razorpay_order_id' => $razorpayOrderId,
'razorpay_payment_id' => $razorpayPaymentId,
'razorpay_signature' => $razorpaySignature
];
try {
$this->razorpay->utility->verifyPaymentSignature($attributes);
// Update order status
$order = Order::where('razorpay_order_id', $razorpayOrderId)->first();
$order->update([
'razorpay_payment_id' => $razorpayPaymentId,
'status' => 'paid'
]);
return response()->json(['success' => true]);
} catch (\Exception $e) {
return response()->json(['success' => false]);
}
}
}
Step 5: Create Frontend Integration
Payment Form (Blade Template)
Payment Gateway
Step 6: Define Routes
Web Routes
// routes/web.php
Route::get('/payment', function () {
return view('payment');
});
Route::post('/create-order', [PaymentController::class, 'createOrder']);
Route::post('/verify-payment', [PaymentController::class, 'verifyPayment']);
Step 7: Handle Webhooks (Optional but Recommended)
Webhook Controller
public function handleWebhook(Request $request)
{
$webhookSecret = 'your_webhook_secret';
$webhookSignature = $request->header('X-Razorpay-Signature');
$payload = $request->getContent();
if (!$this->verifyWebhookSignature($payload, $webhookSignature, $webhookSecret)) {
return response('Unauthorized', 401);
}
$event = json_decode($payload, true);
if ($event['event'] === 'payment.captured') {
$paymentId = $event['payload']['payment']['entity']['id'];
// Update order status in database
$order = Order::where('razorpay_payment_id', $paymentId)->first();
if ($order) {
$order->status = 'captured';
$order->save();
}
}
return response('OK', 200);
}
Error Handling and Best Practices
Common Errors and Solutions
- Invalid API Keys: Check environment variables
- Signature Verification Failed: Ensure correct webhook secret
- Amount Mismatch: Convert rupees to paise (multiply by 100)
- CORS Issues: Configure proper headers
Security Best Practices
- Always verify payment signatures
- Use HTTPS in production
- Store API keys securely
- Validate all input data
- Implement proper error logging
Testing Payment Integration
Test Mode Setup
- Use test API keys for development
- Razorpay provides test card numbers
- No real money is charged in test mode
- All payment methods work in test mode
Test Card Details
Card Number: 4111 1111 1111 1111
CVV: Any 3 digits
Expiry: Any future date
Name: Any name
Advanced Features
Subscription Payments
- Create subscription plans
- Handle recurring payments
- Manage subscription lifecycle
- Handle failed payments
Refund Implementation
public function refundPayment($paymentId, $amount = null)
{
try {
$refund = $this->razorpay->payment
->fetch($paymentId)
->refund(['amount' => $amount]);
return $refund;
} catch (\Exception $e) {
// Handle refund error
}
}
Production Deployment
Go Live Checklist
- Complete KYC verification
- Replace test keys with live keys
- Set up webhook endpoints
- Configure SSL certificate
- Test with small amounts
Monitoring and Analytics
- Track payment success rates
- Monitor failed payments
- Set up alerts for errors
- Regular reconciliation
Troubleshooting Common Issues
Payment Failures
- Insufficient Funds: User account issue
- Card Declined: Bank security settings
- Network Issues: Retry mechanism
- Validation Errors: Check input format
Integration Issues
- Verify API credentials
- Check request/response format
- Validate webhook signatures
- Monitor error logs
Conclusion
Integrating Razorpay with Laravel provides a robust payment solution for your applications. The combination of Razorpay's comprehensive payment options and Laravel's elegant framework creates a seamless payment experience for users.
Remember to test thoroughly in development, implement proper error handling, and follow security best practices. With this integration, you can handle payments for e-commerce sites, subscription services, or any application requiring online transactions.
Need help with implementation? Check out complete Razorpay integration examples in Laravel projects at SkillBolt.dev.