PHPackages                             udviklr/laravel-cashier-nets - 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. udviklr/laravel-cashier-nets

ActiveLibrary[Payment Processing](/categories/payments)

udviklr/laravel-cashier-nets
============================

Laravel Cashier-inspired subscription billing for Nets Easy.

v1.0.0(3w ago)05↓50%MITPHPPHP ^8.1CI passing

Since May 17Pushed 3w agoCompare

[ Source](https://github.com/udviklr/laravel-cashier-nets)[ Packagist](https://packagist.org/packages/udviklr/laravel-cashier-nets)[ RSS](/packages/udviklr-laravel-cashier-nets/feed)WikiDiscussions main Synced 1w ago

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

Laravel Cashier Nets
====================

[](#laravel-cashier-nets)

[![Latest Version on Packagist](https://camo.githubusercontent.com/13e4010903a4011049106373526f1c8bcdfb236eb2173f17d3be385fbb1ee05c/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f756476696b6c722f6c61726176656c2d636173686965722d6e6574732e737667)](https://packagist.org/packages/udviklr/laravel-cashier-nets)[![Total Downloads](https://camo.githubusercontent.com/73949e82782e696f30085a96f3965d03ee8d6d21efd85e9899201676c6697438/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f756476696b6c722f6c61726176656c2d636173686965722d6e6574732e737667)](https://packagist.org/packages/udviklr/laravel-cashier-nets)[![License](https://camo.githubusercontent.com/7773d6429e0ec324032dfc6766b0b02392042d11fce1dddde0c69692e6eff80a/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f756476696b6c722f6c61726176656c2d636173686965722d6e6574732e737667)](LICENSE.md)

Laravel Cashier Nets provides a Cashier-inspired interface for Nets Easy / Nexi Checkout subscription billing in Laravel applications.

Important

This package is an unofficial, community-maintained integration. It is not affiliated with, endorsed by, or sponsored by Laravel, Laravel LLC, Nets, or Nexi. Laravel, Laravel Cashier, Nets, and Nexi are trademarks of their respective owners.

The package focuses on reusable subscription plumbing: creating hosted or embedded checkout sessions, storing local subscription state, processing payment webhooks, charging due subscriptions, and faking provider calls in tests.

Note

The `1.x` release line supports normal Nets subscriptions. Unscheduled subscriptions, one-time checkout helpers, and bulk subscription charges are not part of the `1.x` API surface.

Documentation
-------------

[](#documentation)

- [Installation](docs/installation.md)
- [Configuration](docs/configuration.md)
- [Checkouts](docs/checkouts.md)
- [Webhooks](docs/webhooks.md)
- [Subscriptions and Renewals](docs/subscriptions-and-renewals.md)
- [Testing](docs/testing.md)
- [Upgrading](docs/upgrading.md)

Version Support
---------------

[](#version-support)

Laravel Cashier Nets supports PHP `^8.1` and Laravel `10.x`, `11.x`, `12.x`, and `13.x`. The test matrix follows Laravel's own PHP requirements, so Laravel 10 is tested on PHP 8.1-8.3, Laravel 11 on PHP 8.2-8.4, Laravel 12 on PHP 8.2-8.5, and Laravel 13 on PHP 8.3-8.5.

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

[](#installation)

Install the package with Composer:

```
composer require udviklr/laravel-cashier-nets
```

Publish the configuration and migrations:

```
php artisan vendor:publish --tag="cashier-nets-config"
php artisan vendor:publish --tag="cashier-nets-migrations"
php artisan migrate
```

Add your Nets credentials and environment settings to `.env`:

```
NETS_SECRET_KEY=your-secret-api-key
NETS_CHECKOUT_KEY=your-checkout-key
NETS_SANDBOX=true
NETS_WEBHOOK_SECRET=your-random-webhook-secret
```

The secret key is used for server-to-server Payment API calls and must never be exposed to browsers. The checkout key is used by embedded checkout frontend code and may be exposed client-side.

Billable Model
--------------

[](#billable-model)

Add the `Billable` trait to the Eloquent model that owns subscriptions:

```
use Illuminate\Foundation\Auth\User as Authenticatable;
use Udviklr\CashierNets\Billable;

class User extends Authenticatable
{
    use Billable;
}
```

Hosted Checkout
---------------

[](#hosted-checkout)

Hosted checkout redirects the customer to a Nexi-hosted page:

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

Route::get('/subscribe', function (Request $request) {
    $checkout = $request->user()->newNetsSubscription('default')
        ->amount(9900)
        ->currency('DKK')
        ->intervalDays(30)
        ->description('Pro plan')
        ->reference('pro-plan')
        ->myReference('INV-2026-000123')
        ->returnUrl(route('billing.return'))
        ->termsUrl(route('terms'))
        ->endDate(now()->addYear())
        ->hostedCheckout();

    return $checkout->redirect();
});
```

The shorter `checkout()` method is an alias for `hostedCheckout()`.

Embedded Checkout
-----------------

[](#embedded-checkout)

Embedded checkout creates the payment object and returns a `paymentId` your frontend can pass to Nexi Checkout JS:

```
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use Udviklr\CashierNets\CashierNets;

Route::get('/billing/checkout-session', function (Request $request) {
    $checkout = $request->user()->newNetsSubscription('default')
        ->amount(9900)
        ->currency('DKK')
        ->intervalDays(30)
        ->description('Pro plan')
        ->merchantHandlesConsumerData()
        ->checkoutUrl(route('billing.checkout'))
        ->termsUrl(route('terms'))
        ->endDate(now()->addYear())
        ->embeddedCheckout();

    return response()->json([
        'paymentId' => $checkout->paymentId(),
        'checkoutKey' => CashierNets::checkoutKey(),
        'checkoutJsUrl' => CashierNets::checkoutJsUrl(),
    ]);
});
```

Your application is responsible for rendering the embedded checkout page with Nexi's Checkout JS SDK. This keeps the package frontend-agnostic for Blade, Livewire, Inertia, Vue, React, or other stacks.

Nets requires an `endDate` when creating a subscription. The package exposes this through `endDate()`, which accepts a `CarbonInterface`, `DateTimeInterface`, or date string.

Nets subscriptions use day-based intervals. For example, `intervalDays(30)` is a 30-day billing interval, not a calendar month. If your application stores its own local billing or access period, calculate it from the same interval days value you pass to Cashier Nets so it stays aligned with `nets_subscriptions.next_charge_at`.

Use `merchantHandlesConsumerData()` when your SaaS app collects billing identity itself, such as billing name, VAT, CVR, or invoice details. Nets may hide invoice or installment payment methods if full consumer data is not supplied to checkout.

Subscription State
------------------

[](#subscription-state)

After checkout is created, a pending local subscription is stored. Webhooks should move it to active and persist provider identifiers.

```
if ($user->subscribed()) {
    // The user has a valid subscription.
}

$subscription = $user->netsSubscription('default');

if ($subscription?->pastDue()) {
    // Ask the user to update payment details or retry later.
}
```

The package stores amounts in minor currency units. For example, `9900` is `99.00 DKK`.

See [Subscriptions and Renewals](docs/subscriptions-and-renewals.md) for state helpers, middleware examples, transactions, retry behavior, and scheduled renewal charging.

Webhooks
--------

[](#webhooks)

By default, the package registers a webhook endpoint at:

```
/nets/webhook

```

When creating Nets payments and subscription charges, the package includes configured webhook notifications. Nexi sends the configured `NETS_WEBHOOK_SECRET` value as the incoming `Authorization` header, and the package compares it exactly.

The v1 webhook handler processes:

- `payment.created`
- `payment.checkout.completed`
- `payment.charge.created.v2`
- `payment.charge.failed.v2`
- `payment.reservation.failed`

For local development, expose your Laravel app with a secure HTTPS tunnel such as Ngrok, Expose, or Laravel Herd share, because Nexi requires HTTPS webhook endpoints.

Important

Exclude the webhook route from Laravel CSRF protection, for example `nets/*` when using the default route prefix. See [Webhooks](docs/webhooks.md) for production setup, package events, idempotency, and troubleshooting.

Hosted checkout return routes are application-owned. Nets may return the payment identifier as lowercase `paymentid`, so accept both `paymentid` and `paymentId` before calling `syncNetsSubscriptionFromPayment()`. For session-authenticated callbacks from hosted checkout, prefer `SESSION_SAME_SITE=lax`.

Renewals
--------

[](#renewals)

The package owns local renewal scheduling through `nets_subscriptions.next_charge_at`. Nets subscriptions use day-based intervals, so align any local billing or access period with the same interval days value you sent through `intervalDays()`.

Charge due subscriptions with:

```
php artisan cashier-nets:charge-due
```

Schedule it in your Laravel app:

```
use Illuminate\Support\Facades\Schedule;

Schedule::command('cashier-nets:charge-due')->everyTenMinutes();
```

You may also charge a subscription manually:

```
$transaction = $user->netsSubscription('default')->charge([
    'reference' => 'pro-plan-renewal',
    'my_reference' => 'INV-2026-000124',
]);
```

Failed charge attempts are stored in `nets_transactions`. Retry behavior follows Nets' published retry guidance through the `cashier-nets.retry_policy` config values.

Testing
-------

[](#testing)

Use `CashierNets::fake()` to fake Nets API responses and package webhook events:

```
use Udviklr\CashierNets\CashierNets;

CashierNets::fake([
    'v1/payments' => [
        'paymentId' => 'pay_123',
        'hostedPaymentPageUrl' => 'https://test.checkout.dibspayment.eu/hostedpaymentpage/?checkoutKey=abc',
    ],
]);
```

Webhook events may be asserted with:

```
CashierNets::assertWebhookReceived();
CashierNets::assertWebhookHandled();
```

Production Checklist
--------------------

[](#production-checklist)

Before enabling live billing:

- Set live `NETS_SECRET_KEY` and `NETS_CHECKOUT_KEY`.
- Set `NETS_SANDBOX=false`.
- Set a high-entropy `NETS_WEBHOOK_SECRET` value.
- Ensure your public `APP_URL` is HTTPS and resolves to the application.
- Exclude the package webhook route from Laravel CSRF protection.
- Confirm Nexi can reach `/nets/webhook`, or your configured webhook path.
- Schedule `cashier-nets:charge-due` if the app should charge renewals.
- Run a sandbox checkout and webhook test before switching credentials.

Local Development
-----------------

[](#local-development)

Run the package test suite:

```
composer test
composer analyse
```

Sandbox integration tests are available when you want to exercise the package against Nets directly. They are not part of the default test suite and require real Nets sandbox credentials:

```
NETS_INTEGRATION=true \
NETS_SECRET_KEY=your-sandbox-secret-key \
NETS_CHECKOUT_KEY=your-sandbox-checkout-key \
composer test:integration
```

The default integration suite retrieves created payments from Nets and verifies that order references and `myReference` merchant references were persisted.

Renewal charge coverage is available as an explicit opt-in because it creates real sandbox charge attempts against an existing active Nets subscription:

```
NETS_INTEGRATION=true \
NETS_SECRET_KEY=your-sandbox-secret-key \
NETS_TEST_SUBSCRIPTION_ID=active-sandbox-subscription-id \
composer test:integration:charges
```

The charge integration test verifies the renewal charge reference, `myReference`, and any returned `invoiceNumber` metadata.

See [Testing](docs/testing.md) for fake helpers, webhook assertions, and integration test overrides.

License
-------

[](#license)

Laravel Cashier Nets is open-sourced software licensed under the [MIT license](LICENSE.md).

###  Health Score

39

—

LowBetter than 84% of packages

Maintenance95

Actively maintained with recent releases

Popularity5

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity44

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

Unknown

Total

1

Last Release

23d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/8a3a215b5d0438fc3b691faf171722b3451ad9c7dbae257799d5e4caede6a3fe?d=identicon)[MFlor](/maintainers/MFlor)

---

Top Contributors

[![MFlor](https://avatars.githubusercontent.com/u/3704257?v=4)](https://github.com/MFlor "MFlor (11 commits)")

---

Tags

laravelbillingsubscriptionscashiernetsnexi

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Type Coverage Yes

### Embed Badge

![Health badge](/badges/udviklr-laravel-cashier-nets/health.svg)

```
[![Health](https://phpackages.com/badges/udviklr-laravel-cashier-nets/health.svg)](https://phpackages.com/packages/udviklr-laravel-cashier-nets)
```

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

3325.1M337](/packages/psalm-plugin-laravel)[laravel/cashier

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

2.5k28.4M134](/packages/laravel-cashier)[laravel/cashier-paddle

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

268880.7k3](/packages/laravel-cashier-paddle)[laravel/pulse

Laravel Pulse is a real-time application performance monitoring tool and dashboard for your Laravel application.

1.7k14.1M120](/packages/laravel-pulse)[api-platform/laravel

API Platform support for Laravel

59156.3k10](/packages/api-platform-laravel)[fleetbase/core-api

Core Framework and Resources for Fleetbase API

1232.2k16](/packages/fleetbase-core-api)

PHPackages © 2026

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