NewWe open-sourced 50+ Laravel packages
Custom AI apps, agents and automation — Roundly ConsultingRoundly
All packages
Credits for Laravel

Custom model & translations

Your own ledger model

The Credit model is deliberately not final. Extend it to add relations, accessors or observers:

namespace App\Models;

use RoundlyConsulting\Credits\Models\Credit;

class LedgerEntry extends Credit
{
    protected $table = 'credits';

    // your own relations, accessors, observers ...
}

Then point the config at it — the relation, the balance reads and the scopes all use the configured class:

// config/credits.php
'model' => App\Models\LedgerEntry::class,
  • A key that is not set — absent, null or blank — resolves the packaged Credit.
  • Anything else must be Credit or a subclass of it — the ledger’s scopes and the bucket and amount columns depend on it — or the toolkit’s InvalidConfigurationException is thrown naming the key. A foreign class is never silently replaced.
  • The ledger lives on one connection: your model’s own $connection when it sets one, else the owner’s. Balance and total reads, the owner lock and the transaction around each change all run there, so an owner on a tenant connection keeps its ledger beside it. The migration creates credits and credit_locks together — run it on that connection.

Translations

The exception messages live in the credits::messages translation group and ship in English and Slovak, so with the application locale set to sk they read in Slovak. Publish them with the credits-translations tag and edit lang/vendor/credits/{en,sk}/messages.php — or add a locale folder next to them:

// lang/vendor/credits/en/messages.php
return [
    'insufficient' => 'Insufficient credits: tried to deduct :requested but only :available are available.',
    'insufficient_above_minimum' => 'Insufficient credits: tried to deduct :requested but only :spendable can be spent above the minimum balance of :minimum.',
    'not_denominated' => 'The credits bucket [:bucket] is not denominated in a currency; map it in credits.currencies to use money amounts.',
];

InsufficientCreditsException renders :requested as an absolute amount and, with a floor other than 0, uses insufficient_above_minimum with :spendable and :minimum; BucketNotDenominatedException fills :bucket with the resolved bucket name. A line your published copy lacks is read from the package.

Show your open-source love

This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.

More ways to support, including crypto

By donating, you agree to our donation terms.

Want this built into your product?

We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.