# How to Integrate eSewa Payment Gateway (V2) in Laravel & Vue 3

By bswatantra
Published: 2025-05-04
Updated: 2025-05-05
Canonical: https://laranepal.com/blog/how-to-integrate-esewa-payment-gateway-v2-in-laravel-vue-3

# How to Integrate eSewa Payment Gateway (V2) in Laravel & Vue 3

## Prerequisites

Before you begin, ensure the following tools and configurations are set up:

- **PHP 8.3+**
- **Composer**
- **Laravel 11 or 12**
- **Vue 3**
- **Postman** (for API testing)
- A modern **code editor** (e.g., VS Code)

## eSewa Documentation

- [eSewa Developer Portal](https://developer.esewa.com.np/)
- [eSewa Epay Checkout Docs](https://developer.esewa.com.np/pages/Epay#transactionflow)

---

## Step 1: Set Up Payment Initialization (Backend - Laravel)

### 1. Create API Routes

```php
// routes/api.php

use App\Http\Controllers\PaymentController;

Route::prefix('esewa')->controller(PaymentController::class)->group(function () {
    Route::post('/initiate-payment', 'initiatePayment');
    Route::get('/verify-payment', 'verifyPayment');
});
```

### 2. Create `initiatePayment` Method

```php
// app/Http/Controllers/PaymentController.php

use Illuminate\Support\Facades\Http;
use Illuminate\Http\Request;

public function initiatePayment(Request $request)
{
    $taxAmount = 0;
    $totalAmount = $request->amount;
    $transactionUuid = str()->uuid();
    $productCode = config('payment.esewa.product_code');
    $successUrl = url("/api/esewa/verify-payment");
    $failureUrl = config('payment.esewa.redirect') . 'payment/failure';

    $message = "total_amount={$totalAmount},transaction_uuid={$transactionUuid},product_code={$productCode}";
    $signature = base64_encode(hash_hmac('sha256', $message, config('payment.esewa.secret_key'), true));

    $paymentData = [
        'amount' => $totalAmount,
        'tax_amount' => $taxAmount,
        'total_amount' => $totalAmount,
        'transaction_uuid' => $transactionUuid,
        'product_code' => $productCode,
        'product_service_charge' => 0,
        'product_delivery_charge' => 0,
        'success_url' => $successUrl,
        'failure_url' => $failureUrl,
        'signed_field_names' => 'total_amount,transaction_uuid,product_code',
        'signature' => $signature,
        'api_endpoint' => config('payment.esewa.base_url') . '/api/epay/main/v2/form',
    ];

    return response()->json(['data' => $paymentData]);
}
```

### 3. Create Configuration File

```php
// config/payment.php

return [
    'esewa' => [
        'redirect' => env('ESEWA_REDIRECT_URL'),
        'base_url' => env('ESEWA_BASE_URL'),
        'secret_key' => env('ESEWA_SECRET_KEY'),
        'product_code' => env('ESEWA_MERCHANT_CODE'),
    ],
];
```

### 4. Add Environment Variables

```env
// .env

ESEWA_BASE_URL=https://rc-epay.esewa.com.np
ESEWA_SECRET_KEY=your_secret_key_here
ESEWA_MERCHANT_CODE=EPAYTEST
ESEWA_REDIRECT_URL=http://localhost:9000/
```

> 💡 Run `php artisan config:cache` after updating the `.env` file.

---

## Step 2: Payment Verification (Backend - Laravel)

### Create `verifyPayment` Method

```php
// app/Http/Controllers/PaymentController.php

public function verifyPayment(Request $request)
{
    $result = json_decode(base64_decode($request->data), true);

    $params = [
        "product_code" => $result['product_code'],
        "total_amount" => str_replace(',', '', $result['total_amount']),
        "transaction_uuid" => $result['transaction_uuid']
    ];

    $response = Http::get(config('payment.esewa.base_url') . '/api/epay/transaction/status/', $params);

    if ($response->successful()) {
        $data = $response->json();
        if ($data['status'] === 'COMPLETE') {
            return redirect(config('payment.esewa.redirect') . "payment/success");
        }
    }

    return redirect(config('payment.esewa.redirect') . "payment/failed");
}
```

---

## Step 3: Frontend Integration (Vue 3)

### 1. Define Route

```js
// router/index.js or similar

{
    path: "/payment/esewa",
    name: "EsewaPayment",
    component: () => import("src/pages/payment/Esewa.vue"),
}
```

### 2. Create `Esewa.vue` Component

```vue
<!-- src/pages/payment/Esewa.vue -->

<script setup>
import axios from 'axios';

const initiatePayment = () => {
    axios.post('http://localhost:8000/api/esewa/initiate-payment', {
        amount: 100 // replace with dynamic value if needed
    })
    .then((response) => {
        const result = response.data.data;
        const form = document.createElement("form");
        form.method = "POST";
        form.action = result.api_endpoint;

        for (const key in result) {
            const input = document.createElement("input");
            input.type = "hidden";
            input.name = key;
            input.value = result[key];
            form.appendChild(input);
        }

        document.body.appendChild(form);
        form.submit();
    })
    .catch((error) => {
        console.error("Payment initiation failed:", error.response?.data?.message || error.message);
    });
};
</script>

<template>
  <div>
    <h1>eSewa Payment Integration</h1>
    <button @click="initiatePayment">Pay with eSewa</button>
  </div>
</template>
```

---

## Final Notes

- Always use secure HTTPS in production.
- Log payment data for security audits.
- Follow eSewa documentation for any new changes.
- Never expose secret keys to the frontend.

Happy coding! 💻💸
