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

  1. Create account at razorpay.com
  2. Complete KYC verification
  3. Get API keys from dashboard
  4. 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
    
    


    

Payment Details

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.