PHPackages                             wizcodepl/lunar-tpay - 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. wizcodepl/lunar-tpay

ActiveLibrary[Payment Processing](/categories/payments)

wizcodepl/lunar-tpay
====================

Tpay (OpenAPI) payment driver for Lunar PHP — authorize, redirect, webhook-driven capture.

1.0.2(1mo ago)052↓100%MITPHPPHP ^8.2CI passing

Since May 5Pushed 1mo agoCompare

[ Source](https://github.com/wizcodepl/lunar-tpay)[ Packagist](https://packagist.org/packages/wizcodepl/lunar-tpay)[ Docs](https://github.com/wizcodepl/lunar-tpay)[ RSS](/packages/wizcodepl-lunar-tpay/feed)WikiDiscussions main Synced 1w ago

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

 [![Lunar Tpay](art/logo.svg)](art/logo.svg)

lunar-tpay
==========

[](#lunar-tpay)

[![tests](https://github.com/wizcodepl/lunar-tpay/actions/workflows/tests.yml/badge.svg)](https://github.com/wizcodepl/lunar-tpay/actions/workflows/tests.yml)[![pint](https://github.com/wizcodepl/lunar-tpay/actions/workflows/pint.yml/badge.svg)](https://github.com/wizcodepl/lunar-tpay/actions/workflows/pint.yml)[![phpstan](https://github.com/wizcodepl/lunar-tpay/actions/workflows/phpstan.yml/badge.svg)](https://github.com/wizcodepl/lunar-tpay/actions/workflows/phpstan.yml)[![packagist](https://camo.githubusercontent.com/f328fe303c0d797781b5f7c24e005f71b6e4c4c6e35a79c84c778b589534db68/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f77697a636f6465706c2f6c756e61722d747061792e737667)](https://packagist.org/packages/wizcodepl/lunar-tpay)[![license](https://camo.githubusercontent.com/e1dfe9a8bd33183df0acc982079cc101a1c29d38733793f6cd565deb1001005b/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f77697a636f6465706c2f6c756e61722d747061792e737667)](LICENSE)

[Tpay](https://tpay.com/) (OpenAPI) payment driver for [Lunar PHP](https://lunarphp.com/).

Authorize → redirect customer to tpay → JWS-verified webhook updates the order.

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

[](#installation)

```
composer require wizcodepl/lunar-tpay
php artisan vendor:publish --tag=lunar-tpay-config
```

```
TPAY_CLIENT_ID=...
TPAY_CLIENT_SECRET=...

# Base URLs — omit on production (defaults to https://openapi.tpay.com / https://secure.tpay.com).
# For sandbox / staging:
TPAY_API_BASE_URL=https://openapi.sandbox.tpay.com
TPAY_CERT_BASE_URL=https://secure.sandbox.tpay.com

TPAY_RETURN_URL_SUCCESS=https://your-shop.com/order/ok
TPAY_RETURN_URL_ERROR=https://your-shop.com/order/error
```

Get sandbox credentials at [register.sandbox.tpay.com](https://register.sandbox.tpay.com/) and generate Open API keys in **Merchant Panel → Integration → API**.

In your Lunar `config/lunar.php`, register the driver:

```
'payments' => [
    'types' => [
        'tpay' => ['driver' => 'tpay'],
    ],
],
```

The webhook route `POST /tpay/notify` is registered automatically. Set this URL in your tpay merchant panel.

Usage
-----

[](#usage)

```
$result = Payments::driver('tpay')
    ->cart($cart)
    ->authorize();

if ($result->success) {
    return redirect()->away($result->message);  // tpay redirect URL
}
```

The `PaymentAuthorize.message` field carries the redirect URL — that's a Lunar API quirk (the DTO doesn't have a dedicated `redirectUrl` field).

You can preselect a payment method (BLIK, card, specific bank) via `withData()`:

```
Payments::driver('tpay')
    ->cart($cart)
    ->withData(['pay' => ['groupId' => 150]])  // 150 = BLIK
    ->authorize();
```

When omitted, tpay shows its own payment-method picker on the redirect page.

Webhook authentication — JWS x509
---------------------------------

[](#webhook-authentication--jws-x509)

Tpay signs every notification with its private key (RFC 7515 detached JWS, RS256). We verify against the publicly-fetched Tpay signing certificate, chained up to the Tpay root CA. Both certificates live at:

ProductionSandboxSigning cert`https://secure.tpay.com/x509/notifications-jws.pem``https://secure.sandbox.tpay.com/x509/notifications-jws.pem`Root CA`https://secure.tpay.com/x509/tpay-jws-root.pem``https://secure.sandbox.tpay.com/x509/tpay-jws-root.pem`Certs are fetched once and cached for 24h. Notifications without a valid `X-JWS-Signature` header are rejected with `403 SIGNATURE_INVALID`. Legacy md5sum verification is intentionally not supported — JWS is the modern, asymmetric path with no shared secret to leak.

Testing
-------

[](#testing)

This package uses **real sandbox tests** rather than mocks. The philosophy mirrors how Stripe, PayPal, and AWS PHP SDKs do it: real OAuth, real `POST /transactions`, real `GET /transactions/{id}` against the sandbox.

### Run locally

[](#run-locally)

```
cd packages/lunar-tpay
composer install

export TPAY_CLIENT_ID="your-sandbox-client-id"
export TPAY_CLIENT_SECRET="your-sandbox-secret"

composer test         # unit + sandbox e2e
composer format       # Pint auto-fix
composer format:check # Pint check (CI mode)
composer analyse      # PHPStan level 5
```

Without these env vars the e2e sandbox tests skip cleanly with a clear message — CI without secrets stays green.

### What's covered

[](#whats-covered)

TestTests`TpayClientTest`sandbox OAuth + create/get transaction round-trip + error handling`TpayPaymentDriverTest`driver registration in Lunar PaymentManager + sandbox-backed `authorize()` flow + meta persistence`TpayJwsVerifierTest`JWS verifier negative paths (empty/malformed/wrong-alg/SSRF guard)`TpayWebhookControllerTest`controller logic (status mapping, order lookup, response codes) — verifier swapped with a deterministic stub via the container so we don't need a real tpay signature for controller-level testsThe full positive-path JWS verification needs a real tpay-signed payload, which only happens after a real sandbox transaction fires its webhook against a publicly-reachable URL. Validate that scenario manually after deploying to a staging URL.

### Why no `MockClient` / VCR cassettes

[](#why-no-mockclient--vcr-cassettes)

For payment flows the temptation is to record API responses (à la [VCR](https://github.com/vcr-php/vcr)) and replay them. We chose against this because:

- Sandbox is **free and reliable**. tpay's OpenAPI sandbox is stable.
- Recorded fixtures **drift silently** when the API changes — and payment schemas change more often than people expect.
- Real sandbox calls catch credential / cert / DNS issues that mocks can't.

The downside is that running tests requires creds — solved by skip-on-empty.

What's intentionally not in v1.0
--------------------------------

[](#whats-intentionally-not-in-v10)

- **Refunds** — `refund()` returns `PaymentRefund(false, …)`. Use the tpay merchant panel for now.
- **Retry queue** — single attempt; failure is logged and dispatched as a Lunar `PaymentAttemptEvent`. Wrap with your own retry policy if needed.
- **Filament admin UI** — `Order.meta.tpay` is the source of truth; surface it in your panel however you prefer.

License
-------

[](#license)

MIT — see [LICENSE](LICENSE).

###  Health Score

42

—

FairBetter than 88% of packages

Maintenance93

Actively maintained with recent releases

Popularity12

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity49

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

4

Last Release

35d ago

Major Versions

0.1.0 → 1.0.02026-05-05

### Community

Maintainers

![](https://www.gravatar.com/avatar/855ef6fbfb4716caf57215f39f769dafd5924fa27b83ebea1ed699b946a8c349?d=identicon)[wizku9](/maintainers/wizku9)

---

Top Contributors

[![wizku9](https://avatars.githubusercontent.com/u/136367424?v=4)](https://github.com/wizku9 "wizku9 (9 commits)")

---

Tags

laravelpaymentsecommercelunarpolishlunarphptpay

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/wizcodepl-lunar-tpay/health.svg)

```
[![Health](https://phpackages.com/badges/wizcodepl-lunar-tpay/health.svg)](https://phpackages.com/packages/wizcodepl-lunar-tpay)
```

###  Alternatives

[lunarphp/stripe

Stripe payment driver for Lunar.

2064.7k4](/packages/lunarphp-stripe)[musahmusah/laravel-multipayment-gateways

A Laravel Package that makes implementation of multiple payment Gateways endpoints and webhooks seamless

882.2k1](/packages/musahmusah-laravel-multipayment-gateways)[threesquared/laravel-paymill

Laravel wrapper for the Paymill API

121.3k](/packages/threesquared-laravel-paymill)

PHPackages © 2026

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