Billing Engine for Laravel
Meter multiple dimensions
Meter multiple dimensions
One request can consume several metered dimensions at once — a base operation plus per-result appends plus a separately weighted operation. Reserve them as a set so each bucket is evaluated independently (see ADR-0005).
Reserve a bucket set
use Cbox\Billing\Metering\Contracts\Enforcement;
use Cbox\Billing\Metering\ValueObjects\BucketRequest;
$set = $enforcement->reserveBuckets($org, [
new BucketRequest('search.query', estimate: 1),
new BucketRequest('search.results', estimate: 20),
new BucketRequest('rerank.ops', estimate: 20),
]);
// … do the work …
$enforcement->commitBuckets($set, actuals: [
'search.query' => 1,
'search.results' => 18,
'rerank.ops' => 18,
]);
Each (org, meter) bucket carries its own MeterPolicy:
its enabled? entitlement is checked first (a disabled dimension is refused
before any allowance/cost math), its allowance is isolated (never funded from
another meter's pool), and its multiplier weights the cost. Total cost is the sum
of the per-bucket weighted usage — buckets are never collapsed into one number.
Outcome form
$outcome = $enforcement->reserveBucketsOutcome($org, $requests);
if ($outcome->refused()) {
abort(429);
}
$enforcement->commitBuckets($outcome->reservationSet(), $actuals);
Defining a policy
Policies come from the entitlement resolver, but the value object shows the shape:
use Cbox\Billing\Metering\ValueObjects\MeterPolicy;
use Cbox\Billing\Metering\Enums\OverageBehaviour;
MeterPolicy::metered(allowance: 10_000, multiplier: 1.0, overage: OverageBehaviour::Bill);
MeterPolicy::unlimited(); // cost explicitly zero — no phantom 1.0 multiplier
MeterPolicy::disabled(); // refused before cost