This guide explains how to integrate Cashfree payment gateway with the Laravel Payments package.
Cashfree is a leading Indian payment gateway that supports multiple payment methods including:
Since Cashfree SDK is already included in the package dependencies, you just need to ensure you have the Laravel Payments package installed and configured.
Add your Cashfree credentials to your .env file:
CASHFREE_APP_ID=your_app_id_here
CASHFREE_SECRET_KEY=your_secret_key_here
CASHFREE_TEST_MODE=true
CASHFREE_COUNTRY=IN
CASHFREE_WEBHOOK_SECRET=your_webhook_secret_here
CASHFREE_RETURN_URL=https://yoursite.com/payment/success
CASHFREE_WEBHOOK_URL=https://yoursite.com/cashfree/webhook
You can obtain these credentials from your Cashfree merchant dashboard.
For development/testing:
CASHFREE_TEST_MODE=true
CASHFREE_APP_ID=TEST123456789
CASHFREE_SECRET_KEY=TEST-secret-key
For production:
CASHFREE_TEST_MODE=false
CASHFREE_APP_ID=PROD123456789
CASHFREE_SECRET_KEY=PROD-secret-key
You also need to add the configuration to your config/services.php:
'cashfree' => [
'app_id' => env('CASHFREE_APP_ID'),
'secret_key' => env('CASHFREE_SECRET_KEY'),
'test_mode' => env('CASHFREE_TEST_MODE', true),
'country' => env('CASHFREE_COUNTRY', 'IN'),
'webhook_secret' => env('CASHFREE_WEBHOOK_SECRET'),
'return_url' => env('CASHFREE_RETURN_URL'),
'webhook_url' => env('CASHFREE_WEBHOOK_URL'),
],
use Mdiqbal\LaravelPayments\Facades\Payment;
$paymentRequest = [
'amount' => 1000.00,
'currency' => 'INR',
'email' => 'customer@example.com',
'transaction_id' => 'TXN' . time(),
'redirect_url' => 'https://yoursite.com/payment/callback',
'customer' => [
'name' => 'Rahul Sharma',
'phone' => '9876543210',
'address' => '123 Main St',
'city' => 'Mumbai',
'country' => 'IN',
'postal_code' => '400001'
],
'metadata' => [
'order_id' => 'ORD123456',
'user_id' => 789
]
];
$payment = Payment::gateway('cashfree')->pay($paymentRequest);
This will return a payment URL that you need to redirect the user to:
if ($payment['success']) {
// Store order_id for later verification
session(['cashfree_order_id' => $payment['order_id']]);
// Redirect to Cashfree payment page
return redirect($payment['payment_url']);
}
// routes/web.php
Route::get('/payment/success', [PaymentController::class, 'success']);
Route::post('/cashfree/webhook', [CashfreeController::class, 'webhook']);
// app/Http/Controllers/CashfreeController.php
use Mdiqbal\LaravelPayments\Facades\Payment;
class CashfreeController extends Controller
{
public function webhook(Request $request)
{
// Parse webhook data
$gateway = Payment::gateway('cashfree');
$webhookData = $gateway->parseCallback($request);
// Process the webhook
$result = $gateway->verify($webhookData);
if ($result['success']) {
$transactionId = $result['transaction_id'];
$status = $result['status'];
if ($status === 'completed') {
// Update order status
$order = Order::where('transaction_id', $transactionId)->first();
if ($order) {
$order->status = 'paid';
$order->paid_at = now();
$order->payment_method = $result['payment_method'];
$order->cashfree_order_id = $result['order_id'];
$order->save();
}
}
}
return response()->json(['status' => 'received']);
}
public function success(Request $request)
{
// Handle successful return from payment page
// Note: Always rely on webhook for final status confirmation
return view('payment.success');
}
}
// First, get the order ID (stored during initialization)
$orderId = session('cashfree_order_id');
$verification = Payment::gateway('cashfree')->verify($orderId);
if ($verification['success']) {
$status = $verification['status'];
if ($status === 'completed') {
// Payment was successful
$orderId = $verification['order_id'];
$amount = $verification['amount'];
$currency = $verification['currency'];
$paymentMethod = $verification['payment_method'];
}
}
$refundData = [
'order_id' => 'CASHFREE_ORDER_ID',
'amount' => 500.00, // Optional - omit for full refund
'reason' => 'Customer requested refund',
'refund_id' => 'REF-' . time() // Optional unique refund ID
];
$refund = Payment::gateway('cashfree')->refund($refundData);
$orderId = 'CF_ORDER_ID';
$status = Payment::gateway('cashfree')->getTransactionStatus($orderId);
// Search with filters
$results = Payment::gateway('cashfree')->searchTransactions([
'order_status' => 'PAID',
'order_date_from' => '2024-01-01',
'order_date_to' => '2024-12-31',
'limit' => 20
]);
$paymentRequest = [
'amount' => 1000.00,
'currency' => 'INR',
'email' => 'customer@example.com',
'transaction_id' => 'TXN' . time(),
'customer' => [
'name' => 'Priya Singh',
'phone' => '9876543210',
'address' => '123 Main Street',
'city' => 'Bangalore',
'state' => 'Karnataka',
'country' => 'IN',
'postal_code' => '560001'
],
'redirect_url' => 'https://yoursite.com/payment/callback'
];
$payment = Payment::gateway('cashfree')->pay($paymentRequest);
$paymentRequest = [
// ... other fields
'metadata' => [
'payment_methods' => ['cc', 'dc', 'upi', 'nb', 'wallet'], // Allowed payment methods
'payment_options' => [
'cc' => ['min_amount' => 100], // Card minimum amount
'emi' => ['max_emis' => 12], // Maximum EMI months
'wallet' => ['allowed_wallets' => ['paytm', 'phonepe', 'amazonpay']]
]
]
];
Cashfree uses webhooks to notify your application about payment status changes.
Configure your webhook URL in the Cashfree merchant dashboard
Create a route to handle webhooks:
// routes/web.php
Route::post('/cashfree/webhook', [CashfreeWebhookController::class, 'handleWebhook']);
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Mdiqbal\LaravelPayments\Facades\Payment;
class CashfreeWebhookController extends Controller
{
public function handleWebhook(Request $request)
{
$gateway = Payment::gateway('cashfree');
$webhookData = $gateway->parseCallback($request);
// Process the webhook
$result = $gateway->verify($webhookData);
if ($result['success']) {
$eventType = $result['event_type'];
$transactionId = $result['transaction_id'];
$orderId = $result['order_id'];
switch ($eventType) {
case 'payment.completed':
case 'payment.captured':
$this->handleSuccessfulPayment($result);
break;
case 'payment.pending':
$this->handlePendingPayment($result);
break;
case 'payment.failed':
$this->handleFailedPayment($result);
break;
default:
$this->logInfo('Unknown webhook event: ' . $eventType, $result);
}
}
// Always return 200 OK to acknowledge receipt
return response()->json(['status' => 'received']);
}
protected function handleSuccessfulPayment($data)
{
// Update order status
$order = Order::where('transaction_id', $data['transaction_id'])->first();
if ($order) {
$order->status = 'paid';
$order->paid_at = now();
$order->payment_method = $data['payment_method'];
$order->cashfree_order_id = $data['order_id'];
$order->customer_details = array_merge($order->customer_details ?? [], $data['customer_details']);
$order->merchant_info = array_merge($order->merchant_info ?? [], $data['merchant_info']);
$order->save();
// Send confirmation email
Mail::to($order->customer_email)->send(new PaymentConfirmation($order));
}
}
protected function handlePendingPayment($data)
{
// Payment is being processed
$order = Order::where('transaction_id', $data['transaction_id'])->first();
if ($order) {
$order->status = 'processing';
$order->save();
}
}
protected function handleFailedPayment($data)
{
// Log failed payment
Log::warning('Cashfree payment failed', [
'transaction_id' => $data['transaction_id'],
'order_id' => $data['order_id']
]);
// Update order status
$order = Order::where('transaction_id', $data['transaction_id'])->first();
if ($order) {
$order->status = 'failed';
$order->save();
}
}
protected function logInfo($message, $data)
{
Log::info($message, $data);
}
}
pay() to create an order and get checkout URLverify() to confirm payment statusCashfree uses HMAC SHA256 signatures for webhook security:
webhook_secret is configuredX-Cashfree-Signature: The HMAC signatureX-Webhook-Timestamp: The timestamp when webhook was generatedThe Cashfree gateway provides detailed error messages:
$payment = Payment::gateway('cashfree')->pay($paymentRequest);
if (!$payment['success']) {
$error = $payment['error'];
$message = $error['message'];
$code = $error['code'];
// Handle error based on type
if ($code === 'PAYMENT_FAILED') {
// Payment initialization failed
}
}
PAYMENT_FAILED - Payment initialization failedVERIFICATION_FAILED - Transaction verification failedREFUND_FAILED - Refund processing failedWEBHOOK_FAILED - Webhook processing failedINVALID_CURRENCY - Unsupported currencyINVALID_REQUEST - Invalid request parametersORDER_NOT_FOUND - Order not foundREFUND_NOT_ELIGIBLE - Order is not eligible for refundUse test credentials for development:
CASHFREE_TEST_MODE=true
Use these test card details for testing:
Cashfree automatically determines appropriate payment methods based on:
Cashfree processes payments in multiple currencies:
Cashfree primarily serves India with international payment support:
Cashfree implements rate limits to prevent abuse:
pay() - Initialize a payment and create orderverify($payload) - Verify webhook payloadverify($orderId) - Verify a transaction statusrefund() - Process a refund (full or partial)getTransactionStatus() - Get transaction statussearchTransactions() - Search transactions with filtersparseCallback() - Parse webhook parameters from requestgetSupportedCurrencies() - Get supported currenciesgetGatewayConfig() - Get gateway configurationgetPaymentMethodsForCountry() - Get payment methods for a country// Create order with custom expiry time
$paymentRequest = [
'amount' => 1000.00,
'currency' => 'INR',
'email' => 'customer@example.com',
'transaction_id' => 'TXN' . time(),
'metadata' => [
'order_expiry' => date('Y-m-d H:i:s', strtotime('+30 minutes')),
'auto_retry' => false,
'send_sms' => true,
'send_email' => true
],
'redirect_url' => 'https://yoursite.com/payment/callback'
];
$payment = Payment::gateway('cashfree')->pay($paymentRequest);
// Restrict payment methods for specific amounts
$paymentRequest = [
'amount' => 500.00,
'currency' => 'INR',
'email' => 'customer@example.com',
'transaction_id' => 'TXN' . time(),
'metadata' => [
'payment_methods' => ['upi', 'wallet'], // Only UPI and wallets
'restrict_payment_options' => true
],
'redirect_url' => 'https://yoursite.com/payment/callback'
];
// Use your own customer ID instead of transaction ID
$paymentRequest = [
'amount' => 1000.00,
'currency' => 'INR',
'email' => 'customer@example.com',
'transaction_id' => 'TXN' . time(),
'customer' => [
'id' => 'CUST_' . $userId, // Your customer ID
'name' => 'Customer Name',
'phone' => '9876543210'
],
'redirect_url' => 'https://yoursite.com/payment/callback'
];
While Cashfree doesn't have direct subscription API in this SDK, you can implement recurring payments:
class RecurringPaymentController extends Controller
{
public function initiateRecurring($subscription)
{
// Create initial payment
$paymentRequest = [
'amount' => $subscription->amount,
'currency' => 'INR',
'email' => $subscription->customer_email,
'transaction_id' => 'SUB_' . $subscription->id . '_' . date('Ym'),
'description' => 'Subscription payment - ' . $subscription->plan_name,
'metadata' => [
'subscription_id' => $subscription->id,
'is_recurring' => true,
'next_billing_date' => $subscription->next_billing_date
],
'redirect_url' => 'https://yoursite.com/subscription/success'
];
$payment = Payment::gateway('cashfree')->pay($paymentRequest);
if ($payment['success']) {
// Store for future recurring billing
$subscription->last_cashfree_order_id = $payment['order_id'];
$subscription->save();
}
}
}
// Handle international payments
if ($customerCountry !== 'IN') {
$paymentRequest = [
'amount' => $amountInUSD,
'currency' => 'USD',
'email' => $customerEmail,
'transaction_id' => 'INTL_' . time(),
'customer' => [
'name' => $customerName,
'phone' => $customerPhone,
'address' => $customerAddress,
'country' => $customerCountry
],
'metadata' => [
'international_payment' => true,
'customer_country' => $customerCountry
],
'redirect_url' => 'https://yoursite.com/payment/callback'
];
$payment = Payment::gateway('cashfree')->pay($paymentRequest);
}
class PaymentController extends Controller
{
public function initiate(Request $request)
{
$payment = Payment::gateway('cashfree')->pay($request->all());
if ($payment['success']) {
// Store payment information in session
session([
'cashfree_order_id' => $payment['order_id'],
'transaction_id' => $payment['transaction_id'],
'amount' => $payment['amount'],
'initiated_at' => now()
]);
return redirect($payment['payment_url']);
}
return back()->with('error', 'Failed to initialize payment');
}
public function success(Request $request)
{
// User returned from Cashfree after payment
// Wait for webhook confirmation before updating order
return view('payment.processing', [
'order_id' => session('cashfree_order_id')
]);
}
public function checkPaymentStatus(Request $request)
{
$orderId = session('cashfree_order_id');
if ($orderId) {
$status = Payment::gateway('cashfree')->getTransactionStatus($orderId);
if ($status['success'] && in_array($status['status'], ['completed', 'failed'])) {
// Clear session
session()->forget(['cashfree_order_id', 'transaction_id', 'amount', 'initiated_at']);
return response()->json(['status' => $status['status']]);
}
}
return response()->json(['status' => 'processing']);
}
}
For Cashfree-specific support:
For Larav...
How can I help you explore Laravel packages today?