PHPackages                             veekthoven/laravel-cashier-bachs - 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. veekthoven/laravel-cashier-bachs

ActiveLibrary[Payment Processing](/categories/payments)

veekthoven/laravel-cashier-bachs
================================

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

v0.1.0(1mo ago)11MITPHPPHP ^8.4CI passing

Since Jul 15Pushed 1mo agoCompare

[ Source](https://github.com/veekthoven/laravel-cashier-bachs)[ Packagist](https://packagist.org/packages/veekthoven/laravel-cashier-bachs)[ Docs](https://github.com/veekthoven/laravel-cashier-bachs)[ GitHub Sponsors](https://github.com/veekthoven)[ RSS](/packages/veekthoven-laravel-cashier-bachs/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (1)Dependencies (16)Versions (2)Used By (0)

Laravel Cashier (Bachs)
=======================

[](#laravel-cashier-bachs)

[![Latest Version on Packagist](https://camo.githubusercontent.com/0ed9ec6af65fbd6bd76a7b344994a1db221e16ce8ca2ed7043e9b90125926295/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f7665656b74686f76656e2f6c61726176656c2d636173686965722d62616368732e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/veekthoven/laravel-cashier-bachs)[![GitHub Tests Action Status](https://camo.githubusercontent.com/d0582d664ea1d4f52ad9b7cfb8c549b42de51001ebbd8e0594750e9882933ff4/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f7665656b74686f76656e2f6c61726176656c2d636173686965722d62616368732f72756e2d74657374732e796d6c3f6272616e63683d6d61696e266c6162656c3d7465737473267374796c653d666c61742d737175617265)](https://github.com/veekthoven/laravel-cashier-bachs/actions?query=workflow%3Arun-tests+branch%3Amain)[![GitHub Code Style Action Status](https://camo.githubusercontent.com/6cd05d819d6a798adae9c4d10920a01976d08963972f16b77ce1dc7e231e29cc/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f7665656b74686f76656e2f6c61726176656c2d636173686965722d62616368732f6669782d7068702d636f64652d7374796c652d6973737565732e796d6c3f6272616e63683d6d61696e266c6162656c3d636f64652532307374796c65267374796c653d666c61742d737175617265)](https://github.com/veekthoven/laravel-cashier-bachs/actions?query=workflow%3A%22Fix+PHP+code+style+issues%22+branch%3Amain)[![Total Downloads](https://camo.githubusercontent.com/6fc13e91cec6f566050a59e312934d0ac77a6757ed0c9a4ba5e40f2a56c9ec99/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f7665656b74686f76656e2f6c61726176656c2d636173686965722d62616368732e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/veekthoven/laravel-cashier-bachs)

Laravel Cashier Bachs provides an expressive, fluent interface to [Bachs'](https://bachs.io) subscription billing services — modeled after [Laravel Cashier for Stripe](https://github.com/laravel/cashier-stripe). It handles Bachs customers, hosted checkouts, one-time payments, subscriptions with trials, plan swaps with proration, cancellation grace periods, and webhook-driven state syncing.

Note

In Bachs, subscriptions are always started by the customer completing a **hosted checkout** for a recurring product. This package creates the checkout session and then keeps your local subscription records in sync via webhooks.

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

[](#installation)

Install the package via composer:

```
composer require veekthoven/laravel-cashier-bachs
```

Run Cashier's migrations, which add a `bachs_id` and `trial_ends_at` column to your `users` table and create the `subscriptions` table:

```
php artisan migrate
```

You may publish the migrations to customize them:

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

And optionally the config file:

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

### Configuration

[](#configuration)

Add your Bachs credentials to your `.env` file:

```
BACHS_API_KEY=sk_sandbox_...
BACHS_WEBHOOK_SECRET=whsec_...
```

Keys prefixed with `sk_sandbox_` are automatically routed to the Bachs sandbox API and `sk_live_` keys to production — no extra configuration needed.

### Billable model

[](#billable-model)

Add the `Billable` trait to your model:

```
use Veekthoven\CashierBachs\Billable;

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

If your billable model is not `App\Models\User`, register it in a service provider:

```
use Veekthoven\CashierBachs\Cashier;

Cashier::useCustomerModel(Team::class);
```

Customers
---------

[](#customers)

```
// Create the customer in Bachs (uses the model's email, name and phone)...
$user->createAsBachsCustomer();

// Or with overrides...
$user->createAsBachsCustomer(['name' => 'Jane Doe']);

$user->hasBachsId();
$user->bachsId();

// Retrieve the raw Bachs customer payload...
$customer = $user->asBachsCustomer();

// Push local changes to Bachs...
$user->syncBachsCustomerDetails();
```

The trait reads `email`, `name` and `phone` from your model by default. Override `bachsEmail()`, `bachsName()` or `bachsPhone()` to customize.

Subscriptions
-------------

[](#subscriptions)

### Creating subscriptions

[](#creating-subscriptions)

Subscriptions start with a hosted checkout for a recurring Bachs product:

```
use Illuminate\Http\Request;

Route::get('/subscribe', function (Request $request) {
    return $request->user()
        ->newSubscription('default', 'prod_abc123')
        ->checkout([
            'success_url' => route('billing.success'),
            'cancel_url' => route('billing.cancel'),
        ]);
});
```

The `Checkout` object is responsable — returning it redirects the customer to the Bachs-hosted checkout page. You can also grab the URL yourself with `$checkout->url()`.

Once the customer pays, Bachs sends a `customer.subscription.created` webhook and Cashier creates the local subscription record automatically. The subscription "type" (`default` above) travels through the checkout session's metadata.

### Checking subscription status

[](#checking-subscription-status)

```
$user->subscribed();                          // has a valid "default" subscription
$user->subscribed('default', 'prod_abc123');  // ...to a specific product
$user->subscribedToProduct('prod_abc123');

$subscription = $user->subscription();

$subscription->valid();          // active, trialing, past_due, or on grace period
$subscription->active();
$subscription->onTrial();
$subscription->pastDue();
$subscription->paused();
$subscription->canceled();
$subscription->onGracePeriod();  // canceled but still within the paid period
$subscription->ended();
```

### Trials

[](#trials)

Recurring products configured with a trial in Bachs start subscriptions in the `trialing` state — no extra code needed. You can also manage trials directly:

```
$subscription->extendTrial(now()->addDays(30));
$subscription->endTrial(); // ends the trial and bills immediately
```

For trials **without** requiring a checkout ("generic" trials), set `trial_ends_at` on the billable model when creating it:

```
$user = User::create([
    // ...
    'trial_ends_at' => now()->addDays(14),
]);

$user->onTrial();        // true (generic or subscription trial)
$user->onGenericTrial(); // true (generic trial only)
```

### Swapping plans

[](#swapping-plans)

```
$subscription->swap('prod_premium');                 // prorated, invoiced now (Bachs default)
$subscription->swapWithoutProration('prod_premium'); // no proration
$subscription->swap('prod_premium', [
    'proration_behavior' => 'next_cycle',            // settle the difference next cycle
]);
```

### Cancelling

[](#cancelling)

```
$subscription->cancel();                  // at period end; enters a grace period
$subscription->cancelNow();               // immediately
$subscription->cancel('Too expensive');   // with a reason
```

While on the grace period, `$subscription->valid()` remains `true` until the paid period runs out.

### Payment method

[](#payment-method)

```
$subscription->updatePaymentMethod('pm_abc123');
```

One-time payments
-----------------

[](#one-time-payments)

Sell one-time products through a hosted checkout:

```
// Single product...
return $user->checkout('prod_ebook', [
    'success_url' => route('shop.success'),
]);

// Multiple products with quantities...
return $user->checkout([
    ['product_id' => 'prod_course', 'quantity' => 2],
    'prod_ebook',
]);
```

### Refunds

[](#refunds)

```
$user->refund('chr_1a2b3c4d5e6f');
$user->refund('chr_1a2b3c4d5e6f', ['amount' => '10.00', 'reason' => 'Requested by customer']);
```

Webhooks
--------

[](#webhooks)

Cashier registers a webhook route at `/bachs/webhook` that keeps subscriptions in sync (`customer.subscription.created`, `.updated`, `.deleted`). Create the Bachs webhook endpoint with:

```
php artisan cashier:webhook
```

The command prints the signing secret — add it to your `.env` as `BACHS_WEBHOOK_SECRET`. Incoming webhooks are verified against the `X-Bachs-Signature` header (HMAC-SHA256) and stale deliveries are rejected.

Important

Make sure the webhook route is excluded from CSRF verification. In `bootstrap/app.php`:

```
->withMiddleware(function (Middleware $middleware) {
    $middleware->validateCsrfTokens(except: ['bachs/*']);
})
```

### Handling other events

[](#handling-other-events)

Listen for any Bachs event via the `WebhookReceived` event:

```
use Veekthoven\CashierBachs\Events\WebhookReceived;

Event::listen(function (WebhookReceived $event) {
    if ($event->payload['type'] === 'invoice.payment_failed') {
        // ...
    }
});
```

A `WebhookHandled` event fires after Cashier has processed one of the events it manages itself.

Low-level API access
--------------------

[](#low-level-api-access)

Anything not covered by the fluent interface is available through the API client:

```
use Veekthoven\CashierBachs\Cashier;

$products = Cashier::api()->listProducts();
$payment = Cashier::api()->getPayment('pay_1a2b3c4d5e');
$response = Cashier::api()->get('/accounts/balances');
```

Failed requests throw `Veekthoven\CashierBachs\Exceptions\BachsApiError`, exposing the stable `errorCode`, validation `errors`, and the `requestId` for support.

Customization
-------------

[](#customization)

```
use Veekthoven\CashierBachs\Cashier;

Cashier::ignoreRoutes();      // don't register the webhook route
Cashier::ignoreMigrations();  // don't load the package migrations
Cashier::useSubscriptionModel(CustomSubscription::class);
Cashier::formatCurrencyUsing(fn ($amount, $currency) => /* ... */);
```

Testing
-------

[](#testing)

```
composer test
```

Changelog
---------

[](#changelog)

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

Credits
-------

[](#credits)

- [Victor Abbah Nkoms](https://github.com/veekthoven)
- Inspired by [Laravel Cashier (Stripe)](https://github.com/laravel/cashier-stripe)
- [All Contributors](../../contributors)

License
-------

[](#license)

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

###  Health Score

37

—

LowBetter than 81% of packages

Maintenance90

Actively maintained with recent releases

Popularity3

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity41

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

47d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/1681d2a0bcbcd1edcffa17edb2ca46a0dae8ef6e21546a92ade2b76f59a4a219?d=identicon)[veekthoven](/maintainers/veekthoven)

---

Top Contributors

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

---

Tags

laravelbillingpaymentsubscriptioncashierLaravel Cashierveekthovenlaravel-cashier-bachsbachs

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/veekthoven-laravel-cashier-bachs/health.svg)

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

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

3365.5M359](/packages/psalm-plugin-laravel)[api-platform/laravel

API Platform support for Laravel

58190.1k22](/packages/api-platform-laravel)[laravel/cashier

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

2.5k31.8M166](/packages/laravel-cashier)[laravel/mcp

Rapidly build MCP servers for your Laravel applications.

80732.6M270](/packages/laravel-mcp)[fleetbase/core-api

Core Framework and Resources for Fleetbase API

1346.4k29](/packages/fleetbase-core-api)[laravel/pulse

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

1.7k17.6M165](/packages/laravel-pulse)

PHPackages © 2026

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