PHPackages                             goodoneuz/pay-uz - 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. goodoneuz/pay-uz

ActiveLibrary[Payment Processing](/categories/payments)

goodoneuz/pay-uz
================

Payment: Click, Payme, Uzcard, Visa

4.0.0(1w ago)855.0k↓25%42MITPHPPHP ^7.1|^8.0CI failing

Since Apr 3Pushed 1w ago13 watchersCompare

[ Source](https://github.com/shaxzodbek-uzb/pay-uz)[ Packagist](https://packagist.org/packages/goodoneuz/pay-uz)[ Docs](https://github.com/shaxzodbek-uzb/pay-uz)[ RSS](/packages/goodoneuz-pay-uz/feed)WikiDiscussions master Synced yesterday

READMEChangelog (10)Dependencies (8)Versions (53)Used By (0)Security (1)

Для национальных платежных систем в Узбекистане
===============================================

[](#для-национальных-платежных-систем-в-узбекистане)

[Видео документация ![](https://camo.githubusercontent.com/e2f9c29e4430f1db44fe1f2884f0f6498e34df70b2a2b1d896d2374c56e3402c/68747470733a2f2f75706c6f61642e77696b696d656469612e6f72672f77696b6970656469612f636f6d6d6f6e732f7468756d622f302f30392f596f75547562655f66756c6c2d636f6c6f725f69636f6e5f253238323031372532392e7376672f3132303070782d596f75547562655f66756c6c2d636f6c6f725f69636f6e5f253238323031372532392e7376672e706e67)](https://www.youtube.com/playlist?list=PLIU-yN_rFScVbbglNYmucY3TKzrxypEaP)

[![Buy Me A Coffee](https://camo.githubusercontent.com/9f44ce2dc3b3eecdd02598900866ffc518801df1932849703dae1e5ce5031070/68747470733a2f2f7777772e6275796d6561636f666665652e636f6d2f6173736574732f696d672f637573746f6d5f696d616765732f6f72616e67655f696d672e706e67)](https://tirikchilik.uz/shaxzodbek-uzb)

[![Latest Version on Packagist](https://camo.githubusercontent.com/ba4e95ef9cce705957ed29f926cd05f324a48b6cc1d80f3f542e7f7417fada74/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f676f6f646f6e65757a2f7061792d757a2e7376673f7374796c653d666c6174)](https://packagist.org/packages/goodoneuz/pay-uz)[![Build Status](https://camo.githubusercontent.com/84396a6e7f7e62affbb406e72789ab50482b2f0ad2fe7c2b217e9ddfbf6e7b41/68747470733a2f2f696d672e736869656c64732e696f2f7472617669732f736861787a6f6462656b2d757a622f7061792d757a2f6d61737465722e7376673f7374796c653d666c61742d737175617265)](https://travis-ci.org/shaxzodbek-uzb/pay-uz)[![Quality Score](https://camo.githubusercontent.com/a3c37f965418e019faf88d1edcab3d4101e9a22ac93c4284fb61896f1eee859a/68747470733a2f2f696d672e736869656c64732e696f2f7363727574696e697a65722f672f736861787a6f6462656b2d757a622f7061792d757a2e7376673f7374796c653d666c61742d737175617265)](https://scrutinizer-ci.com/g/shaxzodbek-uzb/pay-uz)

**Featured**
------------

[](#featured)

- [Payme](http://payme.uz) - Merchant
- [Click](http://click.uz) - Merchant
- [Oson](http://click.uz) - Merchant
- [Uzcard](http://uzcard.uz) - Merchant
- [Paynet](http://paynet.uz) - Merchant
- [Uzum Bank](https://uzumbank.uz) - Merchant
- [Stripe](https://stripe.com/) - Merchant(Subscribe)
- OFD fiscalization (онлайн-ККМ / virtual kassa) - pluggable drivers (IKPU/MXIK, VAT, fiscal sign/QR)
- Recurring charges / card tokenization - [Payme Subscribe](https://developer.help.paycom.uz) &amp; [ATMOS](https://atmos.uz) (save card, OTP, charge)
- Card-acquiring aggregators - [Octo](https://octo.uz) &amp; [Multicard](https://multicard.uz) / [Rahmat Pay](https://rhmt.uz) (Uzcard+Humo+Visa+MC, hosted checkout, saved-card, capture/refund/webhook)
- BNPL / installments - [Uzum Nasiya](https://uzum.uz/nasiya) (eligibility, tariffs, contract create/confirm/cancel/status)
- E-invoicing / ЭСФ - [Didox](https://didox.uz) (e-documents, E-IMZO signer seam, create/sign/accept/reject/cancel/status)

*По умолчанию для оплаты установлен "накопительный режим". Чтобы производить оплату в "Одноразовом режиме", вам необходимо изменить параметр в config/payuz.php `'multi_transaction' => false`*

**Planned**
-----------

[](#planned)

- Upay
- Visa

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

[](#installation)

You can install the package via composer:

```
composer require goodoneuz/pay-uz
```

Publishing required files of package:

```
php artisan vendor:publish --provider="Goodoneuz\PayUz\PayUzServiceProvider"
```

Migrate tables:

```
php artisan migrate
```

Seed settings:

```
php artisan db:seed --class="Goodoneuz\PayUz\database\seeds\PayUzSeeder"
```

Usage
-----

[](#usage)

---

Placing routes for service in web.php

```
//handle requests from payment system
Route::any('/handle/{paysys}',function($paysys){
    (new Goodoneuz\PayUz\PayUz)->driver($paysys)->handle();
});

//redirect to payment system or payment form
Route::any('/pay/{paysys}/{key}/{amount}',function($paysys, $key, $amount){
	$model = Goodoneuz\PayUz\Services\PaymentService::convertKeyToModel($key);
    $url = request('redirect_url','/'); // redirect url after payment completed
    $pay_uz = new Goodoneuz\PayUz\PayUz;
    $pay_uz
    	->driver($paysys)
    	->redirect($model, $amount, 860, $url);
});
```

### Payment hooks (resolver &amp; events)

[](#payment-hooks-resolver--events)

The gateways bridge to your application in two ways. **Neither writes or executes runtime PHP files** — the old editable `app/Http/Controllers/Payments/*.php` hooks (and the in-dashboard code "editor") have been removed.

**1. A resolver** for the operations that must return a value — mapping your model to/from the payment key, validating callback amounts, and optionally post-processing a gateway's response. Implement `Goodoneuz\PayUz\Payments\Contracts\PaymentResolver` and point `config/payuz.php` at it:

```
// config/payuz.php
'payments' => [
    'resolver' => \App\Payments\AppPaymentResolver::class,
],
```

```
namespace App\Payments;

use App\Models\Order;
use Goodoneuz\PayUz\Payments\Contracts\PaymentResolver;

class AppPaymentResolver implements PaymentResolver
{
    public function convertModelToKey($model)        { return $model->id; }
    public function convertKeyToModel($key)          { return Order::find($key); }
    public function isProperModelAndAmount($m, $amt) { return $m && (int) $m->amount === (int) $amt; }
    public function beforeResponse($context, $request, array $response) { return $response; }
}
```

The shipped `DefaultPaymentResolver` reproduces the old default hooks (`$model->id`, `App\Models\User::find($key)`, accept-all, pass-through), so an install that never customised them keeps working.

**2. Lifecycle events** for fire-and-forget side effects. Subscribe to them from your `EventServiceProvider`:

event (`Goodoneuz\PayUz\Payments\Events\…`)old hookwhen`PaymentBeforePay``before_pay.php`model resolved, before a tx is created`PaymentProcessing``paying.php`transaction created, payment underway`PaymentPaid``after_pay.php`payment completed`PaymentCancelled``cancel_pay.php`payment cancelled / reversed```
// app/Providers/EventServiceProvider.php
protected $listen = [
    \Goodoneuz\PayUz\Payments\Events\PaymentPaid::class => [
        \App\Listeners\FulfilOrder::class,
    ],
];
```

Each event exposes `$event->model` and `$event->transaction` (for `PaymentBeforePay`, `$event->transaction` is the requested amount).

### Uzum Bank (Merchant API)

[](#uzum-bank-merchant-api)

Uzum Bank uses the server-to-server "Merchant API" model: Uzum's processing centre calls **your** endpoints for five operations — `check`, `create`, `confirm`, `reverse`, `status`. Expose them on a single `{operation}` route:

```
Route::post('/handle/uzum/{operation}', function () {
    return (new Goodoneuz\PayUz\PayUz)->driver('uzum')->handle();
})->where('operation', 'check|create|confirm|reverse|status');
```

Configure the credentials Uzum issues for your terminal in the control panel (payment system `uzum`):

parammeaning`login`HTTP Basic auth login`password`HTTP Basic auth password`service_id`your Uzum `serviceId` (also validated against the request body)`key`which `params` field identifies the order/model (default `id`)Authentication is HTTP Basic (`login:password`) plus a `serviceId` match. Amounts on the wire are in **tiyin** (1 som = 100 tiyin); transactions are stored in som, like the Payme driver.

### OFD fiscalization (онлайн-ККМ)

[](#ofd-fiscalization-онлайн-ккм)

Under PKM No. 943 (23.11.2019) every settlement with the public must be registered with a Fiscal Data Operator (OFD). The fiscalization layer turns an order into a fiscal receipt — with IKPU/MXIK product codes, VAT and a fiscal sign/QR — independently of which payment gateway took the money.

It is intentionally decoupled from the payment webhooks: you fiscalize after a payment completes (e.g. in your own "transaction completed" handler) and attach the result to the transaction. Nothing is written to executable hook files.

**Configure** the driver in `config/payuz.php` (`fiscalization` block). The shipped default is `null` — a no-op that validates the receipt and returns a synthetic sign — so a fresh install never blocks on credentials it lacks. Switch to the `ofd` driver and point it at your OFD/virtual-kassa gateway in production:

```
'fiscalization' => [
    'default'     => env('PAYUZ_FISCAL_DRIVER', 'null'), // 'null' | 'ofd'
    'vat_percent' => env('PAYUZ_FISCAL_VAT', 12),
    'drivers' => [
        'ofd' => [
            'endpoint'    => env('OFD_ENDPOINT'),    // your register-receipt URL
            'token'       => env('OFD_TOKEN'),       // bearer token
            'terminal_id' => env('OFD_TERMINAL_ID'),
        ],
        'null' => ['log' => env('PAYUZ_FISCAL_LOG', false)],
    ],
],
```

The `ofd` driver builds the standard **soliq fiscal-receipt** body (`Name`, `SPIC` = MXIK, `PackageCode`, `GoodPrice`, `Price`, `Amount`, `VAT`, `VATPercent`, `IsRefund`, `ReceivedCash`/`ReceivedCard`) and parses the `FiscalSign` / `QRCodeURL` / `TerminalId` out of the response.

**Build a receipt and fiscalize it.** Amounts are in **tiyin** (1 som = 100 tiyin) and prices are VAT-inclusive; the VAT amount is extracted for you.

```
use Goodoneuz\PayUz\Fiscalization\Receipt;
use Goodoneuz\PayUz\Fiscalization\ReceiptItem;
use Fiscalizer; // facade alias

$receipt = Receipt::sale($transaction->id, [
    new ReceiptItem(
        'Pro plan — 1 month',  // title (printed on the receipt)
        '10305001001000000',   // MXIK / IKPU (17 digits, from tasnif.soliq.uz)
        12_000_000,            // unit price in tiyin (120 000 so'm, VAT incl.)
        1,                     // quantity
        12,                    // VAT percent (12 standard, 0 exempt)
        '1495762'              // package code (optional)
    ),
])->payByCard();

$result = Fiscalizer::fiscalize($receipt); // uses the default driver

if ($result->isSuccessful()) {
    $transaction->attachFiscalReceipt($result); // stores sign/QR in detail['fiscal']
    // $result->fiscalSign(), $result->qr(), $result->receiptUrl()
}
```

Items can also be built from arrays (snake\_case or common aliases):

```
$receipt = Receipt::sale($order->id, [
    ['title' => 'Coffee', 'mxik' => '...', 'price' => 2_500_000, 'count' => 2, 'vat_percent' => 12],
]);
```

Use `Receipt::refund(...)` for returns and `withPayment($cashTiyin, $cardTiyin)`for a mixed cash/card split (it must balance the total).

**Events.** `Fiscalizer::fiscalize()` emits `Goodoneuz\PayUz\Fiscalization\Events\ReceiptFiscalized` on success and `...\Events\FiscalizationFailed` otherwise — listen for these to persist, notify or queue a retry.

**Custom OFD provider.** Implement `Fiscalization\Contracts\FiscalDriver` and register it without touching the package:

```
Fiscalizer::extend('my-ofd', function (array $config, $http) {
    return new \App\Fiscal\MyOfdDriver($config, $http);
});
```

> **Notes.** Direct submission to `ofd.uz` additionally requires PKCS#7 signing of the receipt with the taxpayer certificate — use a gateway that signs on its side, or add a signing driver via `extend()`. **Multikassa (multibank)** is a *local* cashier agent (`http://localhost:8080`), not a server-side API, so it is intentionally not shipped as a driver; add it via `extend()` if you run it on the same host. Confirm exact endpoints/fields against your provider's docs.

### Recurring charges / card tokenization (Payme Subscribe)

[](#recurring-charges--card-tokenization-payme-subscribe)

Save a customer's card once, then charge it again and again — for subscriptions and one-click payments. The `Subscribe` facade is gateway-agnostic (Payme Subscribe is the first driver). Amounts are in **tiyin**; the shipped default is the `null` driver (simulates the happy path) so a fresh install works offline.

**Configure** `subscribe` in `config/payuz.php` and switch to `payme` in production:

```
'subscribe' => [
    'default' => env('PAYUZ_SUBSCRIBE_DRIVER', 'null'), // 'null' | 'payme'
    'drivers' => [
        'payme' => [
            'merchant_id' => env('PAYME_SUBSCRIBE_MERCHANT_ID'),
            'key'         => env('PAYME_SUBSCRIBE_KEY'), // secret X-Auth key — server only!
            'test'        => env('PAYME_SUBSCRIBE_TEST', false),
        ],
    ],
],
```

**Tokenize a card (with OTP), then charge it:**

```
use Subscribe; // facade alias

// 1. Mint a token from the card (this call is browser-safe — id-only auth)
$card = Subscribe::driver('payme')->createCard($pan, $expire /* "MMYY" */, true);

// 2. Send + confirm the SMS code
Subscribe::driver('payme')->sendVerifyCode($card->token());
$card = Subscribe::verify($card->token(), $smsCode);   // fires CardVerified

// 3. Persist ONLY $card->token() (never the PAN), then charge any time:
$charge = Subscribe::charge($card->token(), 1_200_000, ['order_id' => $order->id]);
if ($charge->isPaid()) {                                // fires ChargePaid
    // $charge->id(), $charge->state(), $charge->cardNumber() (masked)
}
```

**Two-stage (hold / capture):**

```
$held = Subscribe::authorize($card->token(), 2_500_000, ['order_id' => $order->id]); // state 5
Subscribe::capture($held->id());   // captures (state 4)  — fires HoldConfirmed
// or Subscribe::release($held->id());  // voids           — fires ChargeCancelled
```

**Security &amp; rules enforced by the driver:** the `X-Auth` header is the cashbox id **alone** for the browser-safe token-minting calls and `id:key` (secret key) for every server-side call (`cards.check`/`remove`, all `receipts.*`); only the **token** is ever persistable — never the PAN; all amounts are tiyin integers. Gateway errors raise typed exceptions (`AuthorizationException`, `InvalidAmountException`, `ReceiptNotFoundException`, `AccountException`, …); unmapped/decline codes surface as `SubscribeException` carrying the raw code.

**ATMOS** is a second `Subscribe` driver (`subscribe.default = 'atmos'`). It speaks the same contract — `createCard` → `verifyCard` → `createReceipt`/`payReceipt` — over ATMOS's OAuth2 card-vault API. Notable differences the driver handles for you: amounts are already **tiyin** (no conversion); auth is an OAuth `client_credentials`token (cached, auto-refreshed); card binding returns a `binding_id` that `verifyCard` swaps for the real `card_token`; and the OTP for saved-token charges is fixed. Configure `consumer_key` / `consumer_secret` / `store_id` / `api_key`under `subscribe.drivers.atmos`. Two ATMOS limits are explicit: `confirmHold()`throws (no verified hold endpoint) and refunds are whole-transaction (`cancelReceipt`). The merchant-cabinet callback is verified with the ATMOS-specific `Subscribe::driver('atmos')->verifyCallback($payload)` / `parseCallback($payload)` (the callback `amount` is unauthenticated — reconcile via `getReceipt()` before granting value).

### Card-acquiring aggregator (Octo)

[](#card-acquiring-aggregator-octo)

One REST integration for Uzcard + Humo + Visa + Mastercard + international cards, with hosted checkout, saved-card charges, two-stage capture, refunds and webhooks. The `Checkout` facade is gateway-agnostic (Octo is the first driver; ATMOS / Multicard follow). **Amounts are tiyin** in your code — the driver converts to Octo's som. Default driver is `null` (simulator).

**Configure** `checkout` in `config/payuz.php` and switch to `octo`:

```
'checkout' => [
    'default' => env('PAYUZ_CHECKOUT_DRIVER', 'null'), // 'null' | 'octo'
    'drivers' => [
        'octo' => [
            'shop_id'    => env('OCTO_SHOP_ID'),
            'secret'     => env('OCTO_SECRET'),
            'unique_key' => env('OCTO_UNIQUE_KEY'), // webhook signature secret
            'test'       => env('OCTO_TEST', false),
            'return_url' => env('OCTO_RETURN_URL'),
            'notify_url' => env('OCTO_NOTIFY_URL'),
        ],
    ],
],
```

**Hosted checkout (redirect):**

```
use Checkout;
use Goodoneuz\PayUz\Checkout\Payment;

$result = Checkout::pay(
    Payment::make(1_200_000, $order->id)        // tiyin
        ->describedAs('Order #'.$order->id)
        ->returnTo(route('checkout.return'))
        ->notifyAt(route('checkout.webhook'))    // Octo will POST the outcome here
);

return redirect($result->payUrl());              // send the customer to Octo
```

**Webhook route** — verifies the signature, normalizes the outcome and emits the event (`PaymentSucceeded` / `PaymentFailed` / `PaymentRefunded`):

```
Route::post('/checkout/webhook', function () {
    $result = Checkout::webhook(request()->all(), request()->headers->all());
    // act on $result, or (recommended) re-confirm via Checkout::status($order->id)
    return response('', 200);
});
```

**Saved-card charge, two-stage and refunds:**

```
$result = Checkout::charge($cardToken, Payment::make(1_200_000, $order->id)); // no redirect
$hold   = Checkout::pay(Payment::make(1_200_000, $order->id)->authorizeOnly());
Checkout::capture($uuid, 1_200_000);  // capture a held payment (Octo needs the amount)
Checkout::refund($uuid, 600_000);     // partial refund
```

> **Octo caveats (documented in the driver):** Octo bills in **som**, so the driver divides your tiyin by 100. HTTP is always 200 — failure is the response `error` field, surfaced as `CheckoutException`. `capture()`/`refund()` take the `octo_payment_UUID`, but `status()` takes your **`shop_transaction_id`** (order id). The **webhook signature recipe is not byte-precisely documented**: the driver checks `sha1(unique_key . uuid . status)` with `hash_equals`, but you should confirm it against a live callback and re-verify via `status()` before mutating an order.

**Multicard** is a second `Checkout` driver (`checkout.default = 'multicard'`) — same `Checkout` API (`pay` / `charge` / `capture` / `refund` / `status` / `webhook`). It speaks Multicard's REST API: a cached bearer token (`POST /auth`), real HTTP verbs (invoice = `POST`, capture = `PUT`, refund = `DELETE`), and the `{success}` envelope. Unlike Octo, **amounts are already tiyin** (no conversion). Configure `application_id` / `secret` / `store_id` / `callback_url` under `checkout.drivers.multicard`; `base_url` selects prod vs sandbox. Two things to confirm with Multicard: which **`callback_scheme`** your store uses (`webhooks` → `sha1(uuid·invoice_id·amount·secret)`, or `success` → `md5(store_id·invoice_id·amount·secret)`), and that `capture`/`refund`/`status` take the payment **uuid**. OFD line items and `split` are passed through via `Payment::with([...])`.

> **Rahmat Pay** is not a separate gateway — it is the Multicard acquiring rail (its hosted checkout renders on `app.rhmt.uz`). Use the `multicard` driver; the `rahmat` alias (`Checkout::driver('rahmat')`) resolves to it with the same `multicard` config for discoverability.

### BNPL / installments (Uzum Nasiya)

[](#bnpl--installments-uzum-nasiya)

Buy-now-pay-later is a **credit-contract lifecycle**, not card acquiring, so it has its own `Bnpl` facade (Uzum Nasiya is the first driver). The flow: check the buyer's eligibility, calculate installment tariffs, create a contract, let the buyer sign it in Uzum's WebView, then confirm. Amounts are **tiyin** at the facade; the driver converts. Default driver is `null` (simulator).

```
use Bnpl;

$elig = Bnpl::checkEligibility($phone);          // e.g. "998901234567"
if ($elig->isBlocked())   { /* stop */ }
if ($elig->mustRegister()) { return redirect($elig->webviewUrl()); }

$plans = Bnpl::calculate($elig->buyerId(), [
    ['product_id' => $p->id, 'price' => 1_200_000, 'amount' => 1], // price in tiyin
]);

$contract = Bnpl::createContract($elig->buyerId(), $plans[0]->tariffId(), [
    ['name' => $p->name, 'price' => 1_200_000, 'amount' => 1, 'category' => 1, 'unit_id' => 1],
], $order->id);                                   // fires ContractCreated

return redirect($contract->webviewPath());        // buyer signs in Uzum's WebView

// after the buyer returns / on a status poll:
Bnpl::confirm($contract->contractId());           // fires ContractConfirmed
// Bnpl::cancel($contract->orderId());             // note: cancel uses orderId(), not contractId()
$status = Bnpl::status($contract->contractId());  // poll-only — Nasiya has no signed webhook
```

Configure `bnpl.drivers.uzum_nasiya` with the partner **Bearer JWT** (issued at onboarding — no self-serve key, no published sandbox). Two integration-time items the driver flags inline: **amounts are decimal som on the wire** (\[INFERRED\] — the driver converts tiyin↔som; confirm against a live payload), and whether activation is **WebView vs partner-driven OTP** (`otp_mode`, default `webview`) is uncertain. Refunds are **full-only** (`cancel`); there is no partial refund.

> **Alif Nasiya** is a planned second BNPL driver — the `Bnpl` layer is ready for it — but Alif's Nasiya API is partner-gated with no public spec, so it is deferred until onboarding rather than guessed.

### E-invoicing / ЭСФ (Didox)

[](#e-invoicing--эсф-didox)

Issue electronic invoices (ЭСФ) and other e-documents through an operator. This is not a payment flow, so it has its own `Einvoice` facade (Didox is the first driver). The package performs **no cryptography**: Uzbek e-documents are signed with E-IMZO (PKCS#7), which the host app supplies through a `Signer` (or a pre-signed blob). Amounts are **tiyin** in your code; the driver emits decimal-som on the wire. Default driver is `null`.

```
use Einvoice;
use Goodoneuz\PayUz\Einvoice\{Document, InvoiceItem, Counterparty};
use Goodoneuz\PayUz\Einvoice\Signers\CallableSigner;

Einvoice::driver('didox')->login(new Counterparty($myTin), $password); // or set user_key

$doc = Document::invoice(
    new Counterparty($myTin, 'My Company'),
    new Counterparty($buyerTin, 'Buyer LLC'),
    [new InvoiceItem('00702001001000001', 'Pro plan', 1_200_000, 1, 12)] // price tiyin, net
)->factura('A-1', '2026-06-20');

$res = Einvoice::createDocument($doc);            // fires DocumentCreated

// Sign with E-IMZO (in your app) and submit. Two ways:
Einvoice::useSigner(new CallableSigner(fn ($b64) => $yourEimzo->signPkcs7($b64)));
Einvoice::signAndSubmit($res->documentId());      // toSign → sign → submit → DocumentSigned
// — or do it yourself: $blob = $eimzo->sign(Einvoice::toSign($id)); Einvoice::submit($id, $blob);
```

Configure `einvoice.drivers.didox` with the partner token (`Partner-Authorization`header — switchable via `partner_header`). State is **poll-only** (`status`/`list`; no webhook). Several wire details (response keys, the exact sign field, the to-sign source path, the `doc_status` map) are best-effort and flagged **UNCERTAIN** in the driver — confirm against the Didox sandbox.

**Exception:**
--------------

[](#exception)

PaymentException

### Changelog

[](#changelog)

Please see [CHANGELOG](CHANGELOG.md) for more information what has changed recently.

Contributing
------------

[](#contributing)

Please see [CONTRIBUTING](CONTRIBUTING.md) for details.

### Security

[](#security)

If you discover any security related issues, please email  instead of using the issue tracker.

> ⚠️ **Upgrade note (code "editor" removed; hooks are now code).**The runtime code "editor" — and the `app/Http/Controllers/Payments/*.php` files it wrote and `PaymentService` `require`d — have been removed. They were a write-PHP-then-execute primitive (the unauthenticated form was CVE-2026-31843; an authenticated-CSRF variant remained afterwards). Move your hooks into versioned code: implement a [`PaymentResolver`](#payment-hooks-resolver--events) and subscribe to the `Payments\Events\*` lifecycle events. The control-panel routes remain behind the `auth` middleware by default (`control_panel.middleware`); the publish tag `pay-uz-editable` is now `pay-uz-config`. See [CHANGELOG](CHANGELOG.md) for details.

Credits
-------

[](#credits)

- [Shaxzodbek](https://github.com/shaxzodbek-uzb)
- [Azizbek](https://github.com/azizbekeshonaliyev)
- [Rustam Mamadaminov](https://github.com/rustamwin)
- [All Contributors](../../contributors)

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

64

—

FairBetter than 99% of packages

Maintenance98

Actively maintained with recent releases

Popularity39

Limited adoption so far

Community25

Small or concentrated contributor base

Maturity79

Established project with proven stability

 Bus Factor1

Top contributor holds 66.9% 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 ~55 days

Recently: every ~187 days

Total

49

Last Release

11d ago

Major Versions

1.7.4 → 2.02020-03-31

2.2.24 → 3.0.02026-06-20

3.0.0 → 4.0.02026-06-22

PHP version history (2 changes)1.0PHP ^7.1

2.1.1PHP ^7.1|^8.0

### Community

Maintainers

![](https://www.gravatar.com/avatar/52601832881370c15b8c88de19f249fa511d46114d02d0a9d1fe2e51e2cb2f16?d=identicon)[Shaxzodbek](/maintainers/Shaxzodbek)

---

Top Contributors

[![shaxzodbek-uzb](https://avatars.githubusercontent.com/u/47610909?v=4)](https://github.com/shaxzodbek-uzb "shaxzodbek-uzb (178 commits)")[![azizbekeshonaliyev](https://avatars.githubusercontent.com/u/38589316?v=4)](https://github.com/azizbekeshonaliyev "azizbekeshonaliyev (67 commits)")[![abdurashid-dev](https://avatars.githubusercontent.com/u/78313030?v=4)](https://github.com/abdurashid-dev "abdurashid-dev (6 commits)")[![MuhammadQuran17](https://avatars.githubusercontent.com/u/59314275?v=4)](https://github.com/MuhammadQuran17 "MuhammadQuran17 (4 commits)")[![Sodiqmirzo](https://avatars.githubusercontent.com/u/65369403?v=4)](https://github.com/Sodiqmirzo "Sodiqmirzo (3 commits)")[![rustamwin](https://avatars.githubusercontent.com/u/16498265?v=4)](https://github.com/rustamwin "rustamwin (2 commits)")[![Khurshidjon](https://avatars.githubusercontent.com/u/38835663?v=4)](https://github.com/Khurshidjon "Khurshidjon (1 commits)")[![laravel-shift](https://avatars.githubusercontent.com/u/15991828?v=4)](https://github.com/laravel-shift "laravel-shift (1 commits)")[![khamdullaevuz](https://avatars.githubusercontent.com/u/81905341?v=4)](https://github.com/khamdullaevuz "khamdullaevuz (1 commits)")[![asia-coder](https://avatars.githubusercontent.com/u/13574524?v=4)](https://github.com/asia-coder "asia-coder (1 commits)")[![asadbek-fayzulloev](https://avatars.githubusercontent.com/u/61094370?v=4)](https://github.com/asadbek-fayzulloev "asadbek-fayzulloev (1 commits)")[![bekaproger](https://avatars.githubusercontent.com/u/31145167?v=4)](https://github.com/bekaproger "bekaproger (1 commits)")

---

Tags

billingclickuzlaravelpayment-gatewaypaymeuzpaynet-uzuzbekistanblazepay-uz

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/goodoneuz-pay-uz/health.svg)

```
[![Health](https://phpackages.com/badges/goodoneuz-pay-uz/health.svg)](https://phpackages.com/packages/goodoneuz-pay-uz)
```

###  Alternatives

[laravel/cashier

Laravel Cashier provides an expressive, fluent interface to Stripe's subscription billing services.

2.6k29.9M146](/packages/laravel-cashier)[duncanmcclean/statamic-cargo

Comprehensive e-commerce addon for Statamic. Build bespoke e-commerce sites without the complexity.

3416.9k](/packages/duncanmcclean-statamic-cargo)[linkxtr/laravel-qrcode

A clean, modern, and easy-to-use QR code generator for Laravel

3720.4k](/packages/linkxtr-laravel-qrcode)

PHPackages © 2026

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