PHPackages                             gokulsingh/laravel-payhub - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. gokulsingh/laravel-payhub

ActiveLibrary

gokulsingh/laravel-payhub
=========================

Unified payment wrapper for Laravel (Razorpay + Cashfree)

v1.0.3(7mo ago)1201MITPHPPHP ^8.1

Since Sep 4Pushed 7mo agoCompare

[ Source](https://github.com/PreciousGariya/laravel-payhub)[ Packagist](https://packagist.org/packages/gokulsingh/laravel-payhub)[ RSS](/packages/gokulsingh-laravel-payhub/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (4)Dependencies (1)Versions (5)Used By (0)

Laravel PayHub — Step-by-step Guide (Beginner Friendly)
=======================================================

[](#laravel-payhub--step-by-step-guide-beginner-friendly)

[![Image 1](docs/ss-payhub-1.png)](docs/ss-payhub-1.png)

A unified payment wrapper for Laravel supporting **Razorpay** and **Cashfree**. It provides a consistent API: create orders, charge, refund, verify webhooks, store optional logs, and attach custom metadata per order.

---

Table of contents
-----------------

[](#table-of-contents)

1. Getting started (Install)
2. Publish config &amp; migrations
3. Configure `.env`
4. Quick examples (backend)
5. Checkout integration (frontend)

    - Razorpay (Checkout.js)
    - Cashfree (Hosted link or Drop-in)
6. Success callback (route + controller + verify)
7. Webhook integration (route + verify)
8. Metadata (custom data per order)
9. Optional DB logging (disable/enable)
10. Unit tests
11. Troubleshooting &amp; FAQ
12. Extending with a new gateway
13. License

---

1 — Getting started (Install)
-----------------------------

[](#1--getting-started-install)

### Option A — Install from Packagist (recommended when published)

[](#option-a--install-from-packagist-recommended-when-published)

```
composer require gokulsingh/laravel-payhub
```

### Option B — Local development (path repository)

[](#option-b--local-development-path-repository)

If you keep the package in your app under `packages/gokulsingh/laravel-payhub`, add to your app `composer.json`:

```
"repositories": {
  "laravel-payhub": {
    "type": "path",
    "url": "packages/gokulsingh/laravel-payhub"
  }
}
```

Then run:

```
composer require gokulsingh/laravel-payhub:* --dev
```

Laravel supports package auto-discovery — no manual provider registration needed.

---

2 — Publish config &amp; migrations
-----------------------------------

[](#2--publish-config--migrations)

Publish config + migration files into your Laravel app:

```
php artisan vendor:publish --provider="Gokulsingh\LaravelPayhub\PaymentServiceProvider" --tag=config
php artisan vendor:publish --provider="Gokulsingh\LaravelPayhub\PaymentServiceProvider" --tag=migrations
```

If you want DB logging, run:

```
php artisan migrate
```

> Note: If you don’t want the `payment_transactions` table, skip the `migrations` publish and `migrate` step — see "Optional DB logging" below.

---

3 — Configure `.env`
--------------------

[](#3--configure-env)

Add credentials and options to your `.env`:

```
# Default gateway
PAYMENT_GATEWAY=razorpay

# Razorpay
RAZORPAY_KEY=rzp_test_xxx
RAZORPAY_SECRET=rzp_secret_xxx
RAZORPAY_WEBHOOK_SECRET=your_rzp_webhook_secret

# Cashfree
CASHFREE_APP_ID=your_cashfree_app_id
CASHFREE_SECRET=your_cashfree_secret
CASHFREE_MODE=sandbox # or production
CASHFREE_WEBHOOK_SECRET=your_cf_webhook_secret

# Logging (DB)
PAYMENT_LOGGING_ENABLED=true
```

Open `config/payment.php` (published) to confirm settings.

**Important — Amount units**

- When calling `createOrder(...)` on this package **pass amount in the main currency unit** (e.g., rupees — `500` = ₹500).

    - Razorpay internally converts ₹ to paise (multiplies by 100).
    - Cashfree uses the amount value directly as provided (e.g., `1200` = ₹1,200).
- Always check the gateway docs when you change behavior.

---

4 — Quick backend examples
--------------------------

[](#4--quick-backend-examples)

Use the package via the `Payment` facade.

**Create an order using the default gateway**

```
use Gokulsingh\LaravelPayhub\Facades\Payment;

$order = Payment::createOrder([
    'amount'   => 500,             // ₹500 (Razorpay will send 50000 paise to API)
    'currency' => 'INR',
    'metadata' => ['receipt' => 'ORD-1001', 'user_id' => auth()->id()],
]);
```

**Explicit gateway**

```
$orderCF = Payment::gateway('cashfree')->createOrder([
             'order_id' => uniqid('ord_'), //else remove automatic generate
            'amount' => 1500,
            'currency' => 'INR',
            'customer_id' => "3297842",
            'email' => 'v2t9H@example.com',
            'phone' => '9999999999',
            'metadata' => [
                'return_url' => 'https://mysite.domain/return_url', // https url else remove
                'notify_url' => 'https://mysite.domain/notify_url', // https url else remove
                'payment_methods' =>  "cc", "dc", "ccc", "ppc","nb","upi","paypal","app","paylater","cardlessemi","dcemi","ccemi", //check for all available options in cashfree documentation
                "banktransfer"
            ],
            'order_tags' => [
                'note1' => 'note1',
                'note2' => 'note2',
            ]
        ]);
```

**Charge / verify a payment**

```
// Razorpay verification by payment id from JS
$payment = Payment::gateway('razorpay')->charge([
    'payment_id' => 'pay_XXXXXXXX',
]);

// Cashfree check status by order id
$payment = Payment::gateway('cashfree')->charge([
    'order_id' => 'cf_order_XXXX',
]);
```

**Refund**

```
$refund = Payment::gateway('razorpay')->refund('pay_XXXXXXXX', ['amount' => 200]);
$refund = Payment::gateway('cashfree')->refund('cf_order_XXXX', ['amount' => 500, 'note' => 'Partial refund']);
```

---

5 — Checkout integration (frontend)
-----------------------------------

[](#5--checkout-integration-frontend)

After you create an order in backend, integrate frontend to complete payment.

### A — Razorpay (Checkout.js)

[](#a--razorpay-checkoutjs)

**Backend**: create order and return JSON.

```
// Controller
public function createRazorpayOrder()
{
    $order = Payment::gateway('razorpay')->createOrder([
        'amount'   => 500,
        'currency' => 'INR',
        'metadata' => ['receipt' => 'rzp_order_101'],
    ]);
    return response()->json($order);
}
```

**Frontend**:

```

fetch("/orders/razorpay")
  .then(r => r.json())
  .then(order => {
    const options = {
      key: "{{ config('payment.gateways.razorpay.key') }}",
      amount: order.data.amount,     // numeric, matches createOrder value (Razorpay expects paise but package handles)
      currency: order.data.currency,
      name: "My Store",
      description: "Order #" + (order.data.custom?.receipt || ''),
      order_id: order.data.id,       // createOrder([
            'order_id' => uniqid('ord_'), //else remove automatic generate
            'amount' => 1500,
            'currency' => 'INR',
            'customer_id' => "3297842",
            'email' => 'v2t9H@example.com',
            'phone' => '9999999999',
            'metadata' => [
                'return_url' => 'https://mysite.domain/return_url', // https url else remove
                'notify_url' => 'https://mysite.domain/notify_url', // https url else remove
                'payment_methods' =>  "cc", "dc", "ccc", "ppc","nb","upi","paypal","app","paylater","cardlessemi","dcemi","ccemi", //check for all available options in cashfree documentation
                "banktransfer"
            ],
            'order_tags' => [
                'note1' => 'note1',
                'note2' => 'note2',
            ]
        ]);
    return response()->json($order);
}
```

**Option 1 — Redirect to hosted payment link**If `createOrder()` returns a `payment_link` (or in `raw`), simply redirect:

```
return redirect($order['data']['custom']['payment_link'] ?? $order['data']['raw']['payment_link']);
```

**Option 2 — Cashfree Drop-in**

```

fetch("/orders/cashfree")
.then(r => r.json())
.then(order => {
  const dropin = new Cashfree();
  dropin.initialiseDropin({
    orderToken: order.data.metadata?.order_token ?? order.data.raw?.order_token,
    onSuccess: function(data) {
      fetch("/payment/success", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ gateway: "cashfree", order_id: order.data.id })
      });
    },
    onFailure: function(data) { console.error("Payment failed", data); }
  });
});

```

Notes:

- Cashfree response shape depends on their API and your account; check the `raw` response in `order.data.raw`.
- If using Drop-in, you must supply `order_token` (returned by Cashfree in the raw response).

---

6 — Success callback (server side verification)
-----------------------------------------------

[](#6--success-callback-server-side-verification)

Add a route:

```
// routes/web.php
use App\Http\Controllers\PaymentController;
Route::post('/payment/success', [PaymentController::class, 'success']);
```

Create controller:

```
namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Gokulsingh\LaravelPayhub\Facades\Payment;

class PaymentController extends Controller
{
    public function success(Request $request)
    {
        $gateway = $request->input('gateway');

        if ($gateway === 'razorpay') {
            $result = Payment::gateway('razorpay')->charge([
                'payment_id' => $request->input('payment_id'),
            ]);
        } elseif ($gateway === 'cashfree') {
            $result = Payment::gateway('cashfree')->charge([
                'order_id' => $request->input('order_id'),
            ]);
        } else {
            return response()->json(['message' => 'Unsupported gateway'], 400);
        }

        if ($result['success']) {
            // Payment verified — mark order as paid in your DB
            return response()->json(['message' => 'Payment successful', 'data' => $result]);
        }

        return response()->json(['message' => 'Payment verification failed', 'data' => $result], 400);
    }
}
```

This uses the package `charge()` method which calls the gateway API and returns normalized result.

---

7 — Webhook integration (automatic route + verification)
--------------------------------------------------------

[](#7--webhook-integration-automatic-route--verification)

Publish routes with the package route macro:

```
// In routes/web.php (or anywhere routes are loaded)
Route::paymentWebhooks('payment/webhook'); // by default POST /payment/webhook/{gateway}
```

The package `WebhookController` will:

- Collect the raw payload and headers,
- Call `Payment::useGateway($gateway)->verifyWebhook($payload)`,
- Dispatch events on success/failure.

If you need custom behavior, extend `WebhookController` or listen to the package events:

```
// app/Providers/EventServiceProvider.php
protected $listen = [
    \Gokulsingh\LaravelPayhub\Events\PaymentSucceeded::class => [
        \App\Listeners\HandlePaymentSucceeded::class,
    ],
];
```

**Manual verification example (Razorpay)**:

```
$verified = Payment::gateway('razorpay')->verifyWebhook([
    'payload' => file_get_contents('php://input'),
    'headers' => request()->headers->all(),
]);
```

---

8 — Custom metadata (attach any data you want)
----------------------------------------------

[](#8--custom-metadata-attach-any-data-you-want)

When creating orders, pass `metadata` array — it will be:

- Sent to the gateway (Razorpay `notes`, Cashfree `metadata`) where supported.
- Stored with the normalized response (check `data.metadata` or `data.raw`).

```
$order = Payment::gateway('cashfree')->createOrder([
    'amount' => 1500,
    'currency' => 'INR',
    'metadata' => [
        'user_id' => auth()->id(),
        'cart_id' => 999,
        'custom_flag' => 'gift',
    ],
]);
```

Use metadata to store app-specific IDs, tracking info, coupons, etc.

---

9 — Optional DB logging
-----------------------

[](#9--optional-db-logging)

By default the package logs transactions into `payment_transactions`. You can disable this:

**Disable**:

```
// config/payment.php
'logging' => [
  'enabled' => false,
],
```

If disabled:

- The `LogsTransactions` trait will skip DB writes.
- You can skip publishing the migration or skip running `php artisan migrate`.

If enabled later:

```
php artisan vendor:publish --provider="Gokulsingh\LaravelPayhub\PaymentServiceProvider" --tag=migrations
php artisan migrate
```

**Migration fields** typically include: `gateway`, `type`, `status`, `amount`, `currency`, `transaction_id`, `payload` (json), `created_at`.

---

10 — Unit tests
---------------

[](#10--unit-tests)

The package includes PHPUnit tests (feature tests). Run them from your application:

```
php artisan test
# or
./vendor/bin/phpunit
```

Suggested tests:

- Payment facade resolves
- createOrder returns normalized response
- charge() verifies payments
- refund() returns normalized refund

When testing, mock HTTP client responses to avoid hitting real APIs.

---

11 — Troubleshooting &amp; FAQ
------------------------------

[](#11--troubleshooting--faq)

**Q: `Class not found` after `composer install`?**A: Run `composer dump-autoload` and ensure package `composer.json` `psr-4` namespace matches your `src/` namespaces.

**Q: `No publishable resources` when vendor:publish?**A: Verify you used the correct tag `--tag=config` and `--tag=migrations` (plural). Check the package provider namespace matches installed package.

**Q: Amount mismatches (Razorpay shows ×100)?**A: Pass amount in main currency unit (₹). The package converts for Razorpay internally.

**Q: Webhook signature verification failing?**A: Make sure `RAZORPAY_SECRET` / `CASHFREE_SECRET` are correct, and that your webhook body is the exact raw JSON used to compute the HMAC. When testing locally, use `ngrok` to forward webhooks.

---

12 — Extending (Add a new gateway)
----------------------------------

[](#12--extending-add-a-new-gateway)

1. Implement `Gokulsingh\LaravelPayhub\Contracts\GatewayInterface`.
2. Use `BaseGateway` &amp; `BaseNormalizer` for consistent behavior.
3. Register gateway in your `Payment` manager (or modify `Payment::useGateway` switch).
4. Add config values in `config/payment.php`.

---

13 — Contributing &amp; License
-------------------------------

[](#13--contributing--license)

- Pull requests welcome.
- Follow PSR-12 and write tests for new functionality.
- License: MIT

---

###  Health Score

34

—

LowBetter than 77% of packages

Maintenance64

Regular maintenance activity

Popularity9

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity47

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 94.4% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~9 days

Total

4

Last Release

222d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/3d418099683e1e7d3a4afccf4e1ee0f71619356748e2110916a311bad759f70a?d=identicon)[preciousgariya98](/maintainers/preciousgariya98)

---

Top Contributors

[![gokulRimms](https://avatars.githubusercontent.com/u/167427771?v=4)](https://github.com/gokulRimms "gokulRimms (17 commits)")[![PreciousGariya](https://avatars.githubusercontent.com/u/113532935?v=4)](https://github.com/PreciousGariya "PreciousGariya (1 commits)")

---

Tags

laravellaravel-packagelaravel-payhubpayment-gateway

### Embed Badge

![Health badge](/badges/gokulsingh-laravel-payhub/health.svg)

```
[![Health](https://phpackages.com/badges/gokulsingh-laravel-payhub/health.svg)](https://phpackages.com/packages/gokulsingh-laravel-payhub)
```

###  Alternatives

[fumeapp/modeltyper

Generate TypeScript interfaces from Laravel Models

196277.9k](/packages/fumeapp-modeltyper)[aedart/athenaeum

Athenaeum is a mono repository; a collection of various PHP packages

255.2k](/packages/aedart-athenaeum)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
