This blog guides you through integrating eSewa v2 into your Laravel application using Livewire. I assume you already have basic knowledge of Livewire, and that Laravel and Livewire are installed and set up.
Step 1: Create the eSewa Configuration File
First, create a config file (e.g. config/esewa.php
) where you can add your eSewa product code, secret key, production URL, and sandbox URL. Make sure to add these values to your .env
file as well.
<?php
declare(strict_types=1);
return [
'product_code' => env('ESEWA_PRODUCT_CODE'),
'secret' => env('ESEWA_SECRET'),
'production_url' => env('ESEWA_PRODUCTION_URL'),
'sandbox_url' => env('ESEWA_SANDBOX_URL'),
];
Step 2: Create Your Checkout Component
Assuming you already have a Livewire Checkout Component, you will handle the fields required for the eSewa checkout page inside it. You can name the method anything you like to process this logic; in my case, I used a method called save()
.
According to eSewa documentation there are a few important fields to keep in mind such as transaction_uuid
and signature
. The transaction_uuid
needs be unique for every transaction.
Step 3: Create the Esewa Helper Class (Optional)
To keep your code clean, I created a helper class Esewa.php
that contains reusable logic like fetching credentails and generating signatures.
<?php
declare(strict_types=1);
namespace App\Helpers;
use App\Models\Client;
class Esewa
{
public static function generateSignature(array $fields): string
{
$signatureMessage = collect($fields)->map(fn ($value, $key): string => "{$key}={$value}")->implode(',');
return base64_encode(hash_hmac('sha256', $signatureMessage, config('esewa.secret'), true));
}
public static function getCredentials(): array
{
$productCode = config('esewa.product_code');
$secret = config('esewa.secret');
return [
'product_code' => $productCode,
'secret' => $secret,
];
}
}
Signature Explanation
According to eSewa's documentation, to generate the signature, you need to includes these fields along with their values: total_amount
, transaction_uuid
, and product_code
.
For example:
use App\Helpers\Esewa;
['product_code' => $productCode,'secret' => $secret] = Esewa::getCredentials();
$signatureFields = [
'total_amount' => $this->cart->total,
'transaction_uuid' => $transactionUuid,
'product_code' => $productCode,
];
$signature = Esewa::generateSignature($signatureFields, $secret);
In the code, I created an array $signatureFields
containing the required fields for the signature along with their values and passed it to the generateSignature
function.
The signature message should look like this:
total_amount=100,transaction_uuid=128481264,product_code=EPAYTEST
After that, you need to hash the string using HMAC-SHA256 and then encode it in base64. This process is implemented in the generateSignature
function.
Step 4: Creating the form fields for Esewa Checkout Page
All the required fields are mentioned in the eSewa documentation. Please refer to the official documentation here.
$data = [
'amount' => $this->cart->sub_total,
'tax_amount' => $this->cart->vat,
'total_amount' => $this->cart->total,
'transaction_uuid' => $transactionUuid,
'product_code' => $productCode,
'product_service_charge' => $this->cart->service_charge,
'product_delivery_charge' => 0,
'success_url' => route('esewa.success'),
'failure_url' => route('esewa.failure'),
'signed_field_names' => 'total_amount,transaction_uuid,product_code',
'signature' => $signature,
];
$this->dispatch('esewa-form-submit', data: $data);
Step 5: Handling the eSewa Form Submission Using JavaScript
eSewa does not support backend checkout directly. Instead, you must create an HTML form with the required fields and submit it to eSewa’s URL. To achieve this, we will use JavaScript to dynamically create and submit the form.
To avoid exposing JS logic directly in your Blade templates, I created a JavaScript module esewa-form.js
in resources/js
:
export default () => ({
formSubmit(data, isProduction = false){
const form = document.createElement('form');
form.method = 'POST';
form.action = isProduction
? 'https://epay.esewa.com.np/api/epay/main/v2/form'
: 'https://rc-epay.esewa.com.np/api/epay/main/v2/form';
Object.entries(data).forEach(([key, value]) => {
const input = document.createElement('input');
input.type = 'hidden';
input.id = key;
input.name = key;
input.value = value;
form.appendChild(input);
});
document.body.appendChild(form);
form.submit();
}
});
Register this JS file in your main app.js
file:
import './bootstrap';
import esewaForm from './esewa-form';
document.addEventListener('alpine:init', () => {
Alpine.data('esewa', esewaForm);
});
Step 6: Listen for the Emit Event in Blade
In your checkout.blade.php
, add a <div>
and use Alpine.js to listen for the Livewire esewa-form-submit
event:
<div x-data="esewa" @esewa-form-submit.window="formSubmit($event.detail.data)">
<!-- Your checkout form goes here -->
</div>
Important: Don't forget to include Livewire’s
@livewireScriptConfig
as explained in the Livewire docs. Without it, it doesn't work.
Step 7: Handling the Payment Success Response
After payment completion, eSewa redirects to your success route with a base64-encoded response string. You need to decode it and verify the signature:
$transactionResponse = json_decode(base64_decode($request->data), true);
A typical response looks like:
{
"transaction_code": "000AWEO",
"status": "COMPLETE",
"total_amount": 1000.0,
"transaction_uuid": "250610-162413",
"product_code": "EPAYTEST",
"signed_field_names": "transaction_code,status,total_amount,transaction_uuid,product_code,signed_field_names",
"signature": "62GcfZTmVkzhtUeh+QJ1AqiJrjoWWGof3U+eTPTZ7fA="
}
According to the eSewa documentation, it is necessary to verify the response signature by generating a new signature from the response data and comparing it with the one provided in the response. To verify the response signature, you generate a signature from the response data excluding the signature
field:
use Illuminate\Support\Arr;
$signatureFields = Arr::except($transactionResponse, ['signature']);
$signature = Esewa::generateSignature($signatureFields, config('esewa.secret'));
if ($signature !== $transactionResponse['signature']) {
// Cancel the transaction due to signature mismatch
return ;
}
Step 8: Check Payment Status Using eSewa API
Once the signature is verified, it is also necessary to confirm the payment status. To do this, we create an service EsewaService.php
file that calls eSewa’s payment status API.
<?php
declare(strict_types=1);
namespace App\Services;
use Illuminate\Support\Facades\Http;
class EsewaService
{
public static function paymentStatusCheck(array $data): array
{
$url = match (app()->environment()) {
'production' => config('esewa.production_url'),
default => config('esewa.sandbox_url')
} . 'transaction/status/?';
$urlWithQueryParams = $url . http_build_query([
'product_code' => $data['product_code'],
'total_amount' => $data['total_amount'],
'transaction_uuid' => $data['transaction_uuid'],
]);
$response = Http::get($urlWithQueryParams)->json();
return $response;
}
}
Call this service after verifying the signature:
$statusResponse = EsewaService::paymentStatusCheck($transactionResponse);
if ($statusResponse['status'] === 'COMPLETE') {
// Payment successful, proceed with creating order
}
Bonus Tip:
If you want to store customer information (like name, email, and contact) when they submit the checkout form, you can use session to store the data and clear it after payment success or failure.
If you are working with a team, consider using Data Transfer Objects (DTOs) to clearly define response fields with their types.
If you have any questions or would like me to share a GitHub repo or full working example, feel free to reach out or leave a comment.
Happy coding! 🚀
Top comments (0)