PHPackages                             phpcorelab/upi-gateway - 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. [Payment Processing](/categories/payments)
4. /
5. phpcorelab/upi-gateway

ActiveLibrary[Payment Processing](/categories/payments)

phpcorelab/upi-gateway
======================

Provider-agnostic PHP library for UPI QR code generation and payment status polling

1.0.1(1mo ago)02MITPHPPHP ^8.1CI passing

Since Mar 15Pushed 1mo agoCompare

[ Source](https://github.com/PHPCoreLab/upi-gateway)[ Packagist](https://packagist.org/packages/phpcorelab/upi-gateway)[ RSS](/packages/phpcorelab-upi-gateway/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (1)Dependencies (6)Versions (3)Used By (0)

upi-gateway
===========

[](#upi-gateway)

> Provider-agnostic PHP library for UPI QR code generation and payment status polling. Switch payment gateways — and environments — with a single config change.

[![Latest Version](https://camo.githubusercontent.com/94c10ba60321b9ecc19d6f6557d51b676e938cf69a8d7695371b40bb57d9b1e6/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f706870636f72656c61622f7570692d67617465776179)](https://packagist.org/packages/PHPCoreLab/upi-gateway)[![PHP Version](https://camo.githubusercontent.com/7281f8393600358dac778427c08a7c475e8ae490da788568aa9b5d004f94263c/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f706870636f72656c61622f7570692d67617465776179)](https://packagist.org/packages/PHPCoreLab/upi-gateway)[![License](https://camo.githubusercontent.com/c07b40f02028b3a2e7faf3744c932042191ae404aad1b8e537cfd08c203587fb/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f706870636f72656c61622f7570692d67617465776179)](LICENSE)

Installation
------------

[](#installation)

```
composer require phpcorelab/upi-gateway
```

Requires PHP 8.1+.

Supported Providers
-------------------

[](#supported-providers)

ProviderSandbox URLLive URLQRPollRefundWebhookRazorpayapi.razorpay.com (test keys)api.razorpay.com (live keys)✅✅✅✅PhonePeapi-preprod.phonepe.comapi.phonepe.com✅✅✅✅Paytmpguat.paytm.iosecuregw.paytm.in🚧🚧🚧🚧> **Razorpay note:** Razorpay uses the same base URL for both environments. Sandbox mode is activated by using test-mode API keys (`rzp_test_*`). Live mode uses production keys (`rzp_live_*`).

Configuration
-------------

[](#configuration)

Provide **both** sandbox and live credentials upfront. The active environment determines which set is used at runtime — no code changes needed when going live.

```
use PHPCoreLab\UpiGateway\UpiGateway;
use PHPCoreLab\UpiGateway\Core\GatewayConfig;

$gateway = new UpiGateway(
    GatewayConfig::fromArray([
        'active_provider' => 'razorpay',  // change from admin panel to switch provider
        'environment'     => 'sandbox',   // 'sandbox' | 'live'  ← change to go live
        'providers' => [
            'razorpay' => [
                'sandbox_key_id'     => $_ENV['RAZORPAY_SANDBOX_KEY_ID'],
                'sandbox_key_secret' => $_ENV['RAZORPAY_SANDBOX_KEY_SECRET'],
                'live_key_id'        => $_ENV['RAZORPAY_LIVE_KEY_ID'],
                'live_key_secret'    => $_ENV['RAZORPAY_LIVE_KEY_SECRET'],
            ],
            'phonepe' => [
                'sandbox_merchant_id' => $_ENV['PHONEPE_SANDBOX_MERCHANT_ID'],
                'sandbox_salt_key'    => $_ENV['PHONEPE_SANDBOX_SALT_KEY'],
                'sandbox_salt_index'  => $_ENV['PHONEPE_SANDBOX_SALT_INDEX'] ?? 1,
                'live_merchant_id'    => $_ENV['PHONEPE_LIVE_MERCHANT_ID'],
                'live_salt_key'       => $_ENV['PHONEPE_LIVE_SALT_KEY'],
                'live_salt_index'     => $_ENV['PHONEPE_LIVE_SALT_INDEX'] ?? 1,
            ],
            'paytm' => [
                'sandbox_mid'          => $_ENV['PAYTM_SANDBOX_MID'],
                'sandbox_merchant_key' => $_ENV['PAYTM_SANDBOX_MERCHANT_KEY'],
                'live_mid'             => $_ENV['PAYTM_LIVE_MID'],
                'live_merchant_key'    => $_ENV['PAYTM_LIVE_MERCHANT_KEY'],
            ],
        ],
    ])
);
```

### Shorthand (single key pair)

[](#shorthand-single-key-pair)

If you only have one set of credentials (e.g. during initial development), you can use the plain `key_id` / `key_secret` keys and the adapter will fall back to them:

```
'razorpay' => [
    'key_id'     => $_ENV['RAZORPAY_KEY_ID'],
    'key_secret' => $_ENV['RAZORPAY_KEY_SECRET'],
],
```

Usage
-----

[](#usage)

### 1. Generate a UPI QR code

[](#1-generate-a-upi-qr-code)

```
use PHPCoreLab\UpiGateway\DTOs\OrderPayload;

$order = new OrderPayload(
    orderId:       'ORD-2024-001',
    amountPaisa:   49900,           // INR 499.00 — always in paise
    customerName:  'Rahul Sharma',
    customerPhone: '9876543210',
);

$qr = $gateway->createQr($order);
echo $qr->transactionId;  // store this for polling
echo $qr->qrString;       // render as QR image
```

### 2. Poll for payment status

[](#2-poll-for-payment-status)

**Synchronous:**

```
use PHPCoreLab\UpiGateway\DTOs\PaymentState;

$status = $gateway->pollUntilDone(
    transactionId: $qr->transactionId,
    intervalMs:    3000,
    maxAttempts:   20,
    backoff:       'exponential',
    onTick: fn($s, $i) => logger()->debug("Poll #{$i}: {$s->state->value}"),
);

if ($status->state === PaymentState::Success) {
    // fulfil order
}
```

**Async / queue-based (recommended for production):**

```
// In your background job:
$status = $gateway->checkStatus($transactionId);
if ($status->isTerminal()) {
    // handle success / failure
}
// Otherwise re-queue with a delay.
```

### 3. Handle webhooks

[](#3-handle-webhooks)

```
$status = $gateway->handleWebhook(
    rawBody: file_get_contents('php://input'),
    headers: getallheaders(),
);
// WebhookVerificationException thrown on bad signature.
```

### 4. Switch provider or environment at runtime

[](#4-switch-provider-or-environment-at-runtime)

```
// Change provider (e.g. from admin panel):
$gateway->switchProvider('phonepe');

// Check current environment:
echo $gateway->getEnvironment()->value; // 'sandbox' or 'live'
```

> **Important:** Never switch to `live` environment at runtime in a test or staging context. The environment should be set via config and treated as deployment-level configuration.

Adding a Custom Provider
------------------------

[](#adding-a-custom-provider)

```
use PHPCoreLab\UpiGateway\Contracts\UpiProviderInterface;
use PHPCoreLab\UpiGateway\Enums\Environment;

class CashfreeAdapter implements UpiProviderInterface
{
    public function __construct(array $config, Environment $environment) { ... }
    // implement generateQr, checkStatus, refund, parseWebhook, getName
}

$gateway->registerProvider('cashfree', new CashfreeAdapter($config, $gateway->getEnvironment()));
$gateway->switchProvider('cashfree');
```

DTOs
----

[](#dtos)

ClassKey Properties`OrderPayload``orderId`, `amountPaisa`, `currency`, `customerName`, `customerPhone``QrResult``transactionId`, `qrString`, `qrImageUrl`, `expiresAt`, `raw``PaymentStatus``transactionId`, `state` (enum), `amountPaisa`, `providerRef`, `failureReason``RefundResult``refundId`, `success`, `message`, `raw``PaymentState` enum: `Pending · Success · Failed · Expired · Refunded`

`Environment` enum: `Sandbox · Live`

Exceptions
----------

[](#exceptions)

ExceptionWhen thrown`ProviderException`HTTP / API call to provider fails`WebhookVerificationException`Signature or checksum mismatch`ProviderNotFoundException`Provider name not registeredAll extend `UpiGatewayException extends RuntimeException`.

Running Tests
-------------

[](#running-tests)

```
composer install
composer test
composer analyse   # PHPStan level 8
```

License
-------

[](#license)

MIT

###  Health Score

37

—

LowBetter than 83% of packages

Maintenance89

Actively maintained with recent releases

Popularity3

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity43

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% 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 ~0 days

Total

2

Last Release

55d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/59a56eba5b07cd0fb82f0c2c24f98b03804d94afe88f11249bde7f3e8187fa3c?d=identicon)[PHPCoreLab](/maintainers/PHPCoreLab)

---

Top Contributors

[![PHPCoreLab](https://avatars.githubusercontent.com/u/268302355?v=4)](https://github.com/PHPCoreLab "PHPCoreLab (15 commits)")

---

Tags

qrpaymentgatewayindiarazorpaypaytmupiPhonePe

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP\_CodeSniffer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/phpcorelab-upi-gateway/health.svg)

```
[![Health](https://phpackages.com/badges/phpcorelab-upi-gateway/health.svg)](https://phpackages.com/packages/phpcorelab-upi-gateway)
```

###  Alternatives

[shetabit/multipay

PHP Payment Gateway Integration Package

291348.2k3](/packages/shetabit-multipay)[bitpay/sdk

Complete version of the PHP library for the new cryptographically secure BitPay API

42337.5k4](/packages/bitpay-sdk)[sebdesign/laravel-viva-payments

A Laravel package for integrating the Viva Payments gateway

4845.9k](/packages/sebdesign-laravel-viva-payments)

PHPackages © 2026

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