cboxdk/laravel-billing-client
| Install | |
|---|---|
composer require cboxdk/laravel-billing-client |
|
| Latest Version: | v0.4.13 |
| PHP: | ^8.4 |
| Laravel: | 12 · 13 |
| License: | MIT |
| Last Updated: | Nov 6, 2026 |
| Links: | GitHub · Packagist |
Cbox Billing Client
cboxdk/laravel-billing-client — the app-local enforcement SDK a product app
embeds to bill against a remote Cbox Billing service. It enforces usage limits
locally, on the hot path — no network round-trip per request — while billing stays
the eventual authority.
Install
composer require cboxdk/laravel-billing-client
# .env
BILLING_CLIENT_BASE_URL=https://billing.internal
BILLING_CLIENT_API_TOKEN=your-service-token
BILLING_CLIENT_LEASE_SIZE=100
BILLING_CLIENT_FAIL=last_known
With a base URL and token set, the provider binds the HTTP transport and the
BillingClient automatically.
Use
use Cbox\Billing\Client\BillingClient;
use Cbox\Billing\Client\Exceptions\QuotaExceeded;
public function handle(BillingClient $billing): mixed
{
try {
$reservation = $billing->reserve('org_123', 'api.calls', 1);
} catch (QuotaExceeded) {
abort(429, 'Usage limit reached.');
}
try {
$result = $this->doTheWork();
$billing->commit($reservation, actual: 1);
return $result;
} catch (\Throwable $e) {
$billing->release($reservation);
throw $e;
}
}
Reserve several meters atomically by passing a [meter => estimate] map — all-or-nothing
across dimensions, each taken from its own local lease:
$set = $billing->reserve('org_123', ['api.calls' => 1, 'compute.ms' => 250]);
$billing->commit($set, ['api.calls' => 1, 'compute.ms' => 210]);
Schedule the background usage flush and the abandoned-reservation sweep:
Schedule::command('billing:report-usage')->everyMinute();
Schedule::command('billing:sweep-reservations')->everyFiveMinutes();
Self-service management
A typed BillingManagement client (and BillingManager facade) lets a product app's
users manage their own billing over the management API:
use Cbox\Billing\Client\Facades\BillingManager;
$plans = BillingManager::plans();
$preview = BillingManager::previewChange('org_123', 'pro');
$result = BillingManager::subscribe('org_123', 'pro'); // + payment intent if due
$usage = BillingManager::usage('org_123');
$back = BillingManager::reactivate('org_123'); // undo a cancel or pause
$changes = BillingManager::subscriptions(updatedSince: $lastSync); // sync every subscriber
Collect payment either way — redirect to a billing-hosted checkout/portal session, or drive
an embedded, gateway-agnostic element in your own UI. The SDK returns
{gateway, publishableKey, clientSecret}; the gateway JavaScript stays the product's
responsibility and settlement is confirmed by webhook:
// Hosted (redirect):
$session = BillingManager::createCheckoutSession('org_123', 'pro', route('billing.done'));
return redirect()->away($session->url);
// Embedded (in-page element):
$intent = BillingManager::createPaymentIntent('org_123', amountMinor: 4_900, currency: 'usd');
// hand $intent->gateway / publishableKey / clientSecret to the front-end; handle SCA there
How it works
Two tiers:
- Hot path (local, no network). A reservation takes units from a node-local leased slice of the organization's allowance via an atomic decrement-and-compensate.
- Background (remote). When the slice runs short the SDK leases a fresh slice from billing; committed usage is buffered durably and reported back cumulatively.
Leasing is pessimistic — billing reserves the granted units centrally — so an
organization can never exceed its allowance beyond a bounded overshoot of roughly
lease_size × nodes. Usage reporting is cumulative and self-correcting: a dropped
report is backfilled by the next flush, which carries the running total.
Failure policy
Failure handling splits by cause:
- An exhausted allowance (billing granted zero) is a semantic hard limit —
QuotaExceeded, always fail closed. - An unreachable billing service is an infrastructure fault, resolved by the
failpolicy.last_known(the default) admits up to the allowance the client last knew and refuses past it on a hard-limit meter;allowadmits everything;denyrefuses once the local lease is spent. Usage is buffered and reconciled later under every policy.
More enforcement hardening
- Reservation TTL recovery. A held reservation a crashed request never settles is
swept back to the local slice (
billing:sweep-reservations), not leaked. - Single-flight refills. A burst that empties a lease is coalesced behind a per-(org, meter) cache lock into one round-trip.
- Durable buffer options. Cache-backed by default, or a crash-safe
databasebuffer (buffer => 'database'; publish the migration) that survives eviction and restart. - Observability signals.
BillingSignals(allowed / denied / refill / report) so a host can meter the meter; no-op by default,LoggingBillingSignalsor your own metrics optional.
Design
- One network seam per surface.
Contracts\BillingTransport(enforcement) andContracts\ManagementTransport(self-service) are the only things that touch the network — realHttp\*implementations (bearer token, deny-by-default about responses) in production,Testing\Fake*Transportin tests. - Contracts-first, deny-by-default. Depend on interfaces; unknown meters/plans are not entitled; malformed or non-2xx responses raise rather than being trusted.
- Dogfooded testing.
Testing\InteractsWithBillingClientdrives the whole two-tier flow and the management flow offline; the package's own suite uses it.
Requirements
PHP ^8.4; Laravel ^12 || ^13. A cache store with atomic increment / decrement
(any Laravel driver) backs the local counters, the reservation registry, and the cache
usage ledger; the database buffer additionally uses illuminate/database.
Documentation
See docs/ — overview, quickstart, core concepts (two-tier leasing,
multi-meter enforcement, reservation recovery, cumulative reporting, the failure policy,
the management client, and the architecture), and the self-service cookbook.
License
MIT.
Related Packages
Laravel/PHP consumer SDK for Cbox ID — turnkey OIDC login, hosted profile-manage...
Cbox Billing — the billing engine for Laravel — a gateway-agnostic library: cata...
LinkedIn API client. Handles OAuth, CSRF protection. Easy to implement and exten...
LinkedIn API client. Handles OAuth, CSRF protection. Easy to implement and exten...
Version History
| Version | Released | PHP | Laravel | License |
|---|---|---|---|---|
| v0.4.13 | ^8.4 | ^12.0 || | MIT | |
| v0.4.12 | ^8.4 | ^12.0 || | MIT | |
| v0.4.11 | ^8.4 | ^12.0 || | MIT | |
| v0.4.10 | ^8.4 | ^12.0 || | MIT | |
| v0.4.9 | ^8.4 | ^12.0 || | MIT | |
| v0.4.8 | ^8.4 | ^12.0 || | MIT | |
| v0.4.7 | ^8.4 | ^12.0 || | MIT | |
| v0.4.6 | ^8.4 | ^12.0 || | MIT | |
| v0.4.5 | ^8.4 | ^12.0 || | MIT | |
| v0.4.4 | ^8.4 | ^12.0 || | MIT | |
| v0.4.3 | ^8.4 | ^12.0 || | MIT | |
| v0.4.2 | ^8.4 | ^12.0 || | MIT | |
| v0.4.1 | ^8.4 | ^12.0 || | MIT | |
| v0.4.0 | ^8.4 | ^12.0 || | MIT | |
| v0.3.2 | ^8.4 | ^12.0 || | MIT | |
| v0.3.1 | ^8.4 | ^12.0 || | MIT | |
| v0.3.0 | ^8.4 | ^12.0 || | MIT | |
| v0.2.0 | ^8.4 | ^12.0 || | MIT | |
| v0.1.0 | ^8.4 | ^12.0 || | MIT |