PHPackages                             climactic/laravel-credits - 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. climactic/laravel-credits

ActiveLibrary

climactic/laravel-credits
=========================

A ledger-based Laravel package for managing credit-based systems in your application.

v1.4.2(1mo ago)29925.4k—8.1%19MITPHPPHP ^8.4CI passing

Since Nov 20Pushed 1mo ago1 watchersCompare

[ Source](https://github.com/Climactic/laravel-credits)[ Packagist](https://packagist.org/packages/climactic/laravel-credits)[ Docs](https://github.com/climactic/laravel-credits)[ GitHub Sponsors](https://github.com/sponsors/climactic)[ Fund](https://ko-fi.com/climacticco)[ RSS](/packages/climactic-laravel-credits/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (10)Dependencies (24)Versions (16)Used By (0)

[![Laravel Credits](.github/assets/laravelcredits.webp)](.github/assets/laravelcredits.webp)Laravel Credits
===============

[](#laravel-credits)

A ledger-based Laravel package for managing credit-based systems in your application. Perfect for virtual currencies, reward points, or any credit-based feature.

[![Discord](https://camo.githubusercontent.com/a2d0c0993adc0d0f466338c3991d1d318ab74795b52e1d5e4a2e41efc27acfb1/68747470733a2f2f696d672e736869656c64732e696f2f646973636f72642f3330333139353332323531343031343231303f7374796c653d666f722d7468652d6261646765)](https://discord.gg/kedWdzwwR5)[![Latest Version on Packagist](https://camo.githubusercontent.com/58d7f182f57b4c6eef7c38df8f76eb2a9f724b375a64dc356758c93b4a7a8c1d/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f636c696d61637469632f6c61726176656c2d637265646974732e7376673f7374796c653d666f722d7468652d6261646765)](https://packagist.org/packages/climactic/laravel-credits)[![GitHub Tests Action Status](https://camo.githubusercontent.com/4166297db574295f36535259fd7007d39832d15f8b9c5a57658fab633ce5a951/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f636c696d61637469632f6c61726176656c2d637265646974732f72756e2d74657374732e796d6c3f6272616e63683d6d61696e266c6162656c3d7465737473267374796c653d666f722d7468652d6261646765)](https://github.com/climactic/laravel-credits/actions?query=workflow%3Arun-tests+branch%3Amain)[![GitHub Code Style Action Status](https://camo.githubusercontent.com/8b9740eab8a5af7b60f61d2c0504cc4b1865104a8fd8e1d880ebc43f5523bb72/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f636c696d61637469632f6c61726176656c2d637265646974732f6669782d7068702d636f64652d7374796c652d6973737565732e796d6c3f6272616e63683d6d61696e266c6162656c3d636f64652532307374796c65267374796c653d666f722d7468652d6261646765)](https://github.com/climactic/laravel-credits/actions?query=workflow%3A%22Fix+PHP+code+style+issues%22+branch%3Amain)[![Total Downloads](https://camo.githubusercontent.com/f837f0702b8772aac685fdbd2a45a5b8408f5d497afc5a8f708d0366c1f64136/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f636c696d61637469632f6c61726176656c2d637265646974732e7376673f7374796c653d666f722d7468652d6261646765)](https://packagist.org/packages/climactic/laravel-credits)[![Depfu](https://camo.githubusercontent.com/cf639c3cfc6d937551e38934a14aa4861ac0dc78e90a7e779e859b51ceff2cca/68747470733a2f2f696d672e736869656c64732e696f2f64657066752f646570656e64656e636965732f6769746875622f436c696d61637469632532466c61726176656c2d637265646974733f7374796c653d666f722d7468652d6261646765)](https://camo.githubusercontent.com/cf639c3cfc6d937551e38934a14aa4861ac0dc78e90a7e779e859b51ceff2cca/68747470733a2f2f696d672e736869656c64732e696f2f64657066752f646570656e64656e636965732f6769746875622f436c696d61637469632532466c61726176656c2d637265646974733f7374796c653d666f722d7468652d6261646765)[![Sponsor on GitHub](https://camo.githubusercontent.com/b3163f75bf5ed93d5cdab93ef38cdf453559a26611bab9abe917d7dee974979a/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f53706f6e736f722d4769744875622d6561346161613f7374796c653d666f722d7468652d6261646765266c6f676f3d676974687562)](https://github.com/sponsors/climactic)[![Support on Ko-fi](https://camo.githubusercontent.com/b5dfdef80a44c8875071357e6b7e2ef1f3c595e89a0b947682d5b12a58722d9e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f537570706f72742d4b6f2d2d66692d4646354535423f7374796c653d666f722d7468652d6261646765266c6f676f3d6b6f2d6669266c6f676f436f6c6f723d7768697465)](https://ko-fi.com/ClimacticCo)

📖 Table of Contents
-------------------

[](#-table-of-contents)

- [Laravel Credits](#laravel-credits)
    - 📖 [Table of Contents](#-table-of-contents)
    - [Features](#features)
    - 📦 [Installation](#-installation)
    - ⚙️ [Configuration](#%EF%B8%8F-configuration)
        - 🗄️ [Database Recommendations](#%EF%B8%8F-database-recommendations)
    - 🚀 [Usage](#-usage)
        - 🔧 [Setup Your Model](#-setup-your-model)
        - 💳 [Basic Usage](#-basic-usage)
        - 💸 [Transfers](#-transfers)
        - 📊 [Transaction History](#-transaction-history)
        - 🕐 [Historical Balance](#-historical-balance)
        - 📝 [Metadata](#-metadata)
        - 🔎 [Querying by Metadata](#-querying-by-metadata)
            - [Metadata Key Format](#metadata-key-format)
            - [Basic Metadata Queries](#basic-metadata-queries)
            - [Advanced Metadata Queries](#advanced-metadata-queries)
            - [Chaining Multiple Metadata Conditions](#chaining-multiple-metadata-conditions)
            - [Convenience Methods](#convenience-methods)
            - ⚡ [Performance Optimization](#-performance-optimization)
                - [When to Optimize](#when-to-optimize)
                - [MySQL/MariaDB: Virtual Columns with Indexes](#mysqlmariadb-virtual-columns-with-indexes)
                - [PostgreSQL: GIN Indexes on JSONB](#postgresql-gin-indexes-on-jsonb)
                - [SQLite: Limited Support](#sqlite-limited-support)
                - [Choosing What to Index](#choosing-what-to-index)
                - [Best Practices](#best-practices)
        - 📢 [Events](#-events)
    - 📚 [API Reference](#-api-reference)
        - 🔧 [Available Methods](#-available-methods)
        - 🔍 [Query Scopes](#-query-scopes)
        - ⚠️ [Deprecated Methods](#%EF%B8%8F-deprecated-methods)
    - 🧪 [Testing](#-testing)
    - 📋 [Changelog](#-changelog)
    - 🤝 [Contributing](#-contributing)
    - 🔒 [Security Vulnerabilities](#-security-vulnerabilities)
    - 💖 [Support This Project](#-support-this-project)
        - 🌟 [Sponsors](#-sponsors)
    - ⭐ [Star History](#-star-history)
    - 📦 [Other Packages](#-other-packages)
    - 📄 [License](#-license)
    - ⚖️ [Disclaimer](#%EF%B8%8F-disclaimer)

Features
--------

[](#features)

- 🔄 Credit transactions
- 💸 Credit transfers
- 📢 Events for adding, deducting, and transferring credits
- 💰 Balance tracking with running balance
- 📊 Transaction history
- 🔍 Point-in-time balance lookup
- 📝 Transaction metadata support
- 🔎 Powerful metadata querying with filters and scopes
- ⚡ Efficient queries using running balance and indexes
- 🚀 Performance optimization guide for high-volume applications

📦 Installation
--------------

[](#-installation)

You can install the package via composer:

```
composer require climactic/laravel-credits
```

Publish and run the migrations:

```
php artisan vendor:publish --tag="credits-migrations"
php artisan migrate
```

Optionally publish the config file:

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

⚙️ Configuration
----------------

[](#️-configuration)

```
return [
    // Allow negative balances
    'allow_negative_balance' => false,

    // Table name for credit transactions (change if you've updated the migration table name)
    'table_name' => 'credits',
];
```

### 🗄️ Database Recommendations

[](#️-database-recommendations)

**Concurrency &amp; Locking**: This package uses row-level locking (`SELECT FOR UPDATE`) to prevent race conditions during concurrent credit operations. This requires a database engine that supports proper transaction isolation and row-level locking:

- ✅ **MySQL/MariaDB**: Requires InnoDB engine (default in modern versions)
- ✅ **PostgreSQL**: Full support for row-level locking
- ⚠️ **SQLite**: Row-level locking is ignored; concurrent operations may produce incorrect results in high-concurrency scenarios

For production environments with concurrent users, we recommend using MySQL/MariaDB (InnoDB) or PostgreSQL.

🚀 Usage
-------

[](#-usage)

### 🔧 Setup Your Model

[](#-setup-your-model)

Add the `HasCredits` trait to any model that should handle credits:

```
use Climactic\Credits\Traits\HasCredits;

class User extends Model
{
    use HasCredits;
}
```

### 💳 Basic Usage

[](#-basic-usage)

```
// Add credits
$user->creditAdd(100.00, 'Subscription Activated');

// Deduct credits
$user->creditDeduct(50.00, 'Purchase Made');

// Get current balance
$balance = $user->creditBalance();

// Check if user has enough credits
if ($user->hasCredits(30.00)) {
    // Proceed with transaction
}
```

### 💸 Transfers

[](#-transfers)

Transfer credits between two models:

```
$sender->creditTransfer($recipient, 100.00, 'Paying to user for their service');
```

### 📊 Transaction History

[](#-transaction-history)

```
// Get last 10 transactions
$history = $user->creditHistory();

// Get last 20 transactions in ascending order
$history = $user->creditHistory(20, 'asc');
```

### 🕐 Historical Balance

[](#-historical-balance)

Get balance as of a specific date:

```
$date = new DateTime('2023-01-01');
$balanceAsOf = $user->creditBalanceAt($date);
```

### 📝 Metadata

[](#-metadata)

Add additional information to transactions:

```
$metadata = [
    'order_id' => 123,
    'product' => 'Premium Subscription',
    'user_id' => 456,
    'tags' => ['premium', 'featured']
];

$user->creditAdd(100.00, 'Purchase', $metadata);
```

### 🔎 Querying by Metadata

[](#-querying-by-metadata)

The package provides powerful query scopes to filter transactions by metadata with built-in input validation for security.

#### Metadata Key Format

[](#metadata-key-format)

Metadata keys must follow these rules:

- Use **dot notation** for nested keys (e.g., `'user.id'`, not `'user->id'`)
- Cannot be empty or contain only whitespace
- Cannot contain quotes (`"` or `'`)
- Whitespace is automatically trimmed

```
// ✅ Valid
$user->credits()->whereMetadata('source', 'purchase')->get();
$user->credits()->whereMetadata('user.id', 123)->get();
$user->credits()->whereMetadata('  source  ', 'test')->get(); // Trimmed automatically (not recommended)

// ❌ Invalid - will throw InvalidArgumentException
$user->credits()->whereMetadata('', 'value')->get();              // Empty key
$user->credits()->whereMetadata('data->key', 'value')->get();     // Arrow operator
$user->credits()->whereMetadata('data"key', 'value')->get();      // Contains quotes
```

#### Basic Metadata Queries

[](#basic-metadata-queries)

```
// Query by simple metadata value
$purchases = $user->credits()
    ->whereMetadata('source', 'purchase')
    ->get();

// Query with comparison operators
$highValue = $user->credits()
    ->whereMetadata('order_value', '>', 100)
    ->get();

// Query by nested metadata (using dot notation)
$specificUser = $user->credits()
    ->whereMetadata('user.id', 123)
    ->get();

// Deeply nested keys (use raw where for very deep nesting)
$results = $user->credits()
    ->where('metadata->data->level1->level2->value', 'found')
    ->get();
```

#### Advanced Metadata Queries

[](#advanced-metadata-queries)

```
// Check if metadata array contains a value
$premium = $user->credits()
    ->whereMetadataContains('tags', 'premium')
    ->get();

// Check if metadata key exists
$withOrderId = $user->credits()
    ->whereMetadataHas('order_id')
    ->get();

// Check if metadata key is null or doesn't exist
$withoutTags = $user->credits()
    ->whereMetadataNull('tags')
    ->get();

// Query by metadata array length
$multipleTags = $user->credits()
    ->whereMetadataLength('tags', '>', 1)
    ->get();
```

#### Chaining Multiple Metadata Conditions

[](#chaining-multiple-metadata-conditions)

```
$filtered = $user->credits()
    ->whereMetadata('source', 'purchase')
    ->whereMetadata('category', 'electronics')
    ->whereMetadataContains('tags', 'featured')
    ->where('amount', '>', 50)
    ->get();
```

#### Convenience Methods

[](#convenience-methods)

```
// Get credits filtered by metadata (with limit and ordering)
$purchases = $user->creditsByMetadata('source', 'purchase', limit: 20, order: 'desc');

// With comparison operators
$highValue = $user->creditsByMetadata('order_value', '>=', 100, limit: 10);

// Multiple metadata filters
$filtered = $user->creditHistoryWithMetadata([
    ['key' => 'source', 'value' => 'purchase'],
    ['key' => 'category', 'value' => 'electronics'],
    ['key' => 'tags', 'value' => 'premium', 'method' => 'contains'],
    ['key' => 'order_value', 'operator' => '>', 'value' => 50],
], limit: 25);

// Query with null values (explicitly include 'value' key)
$nullChecks = $user->creditHistoryWithMetadata([
    ['key' => 'refund_id', 'operator' => '=', 'value' => null],  // Check for null
    ['key' => 'status', 'value' => 'pending'],                   // Simple equality
], limit: 10);
```

**Note:** When using `creditHistoryWithMetadata()`, the filter array distinguishes between "two-parameter syntax" and "three-parameter syntax" by checking if the `'value'` key exists:

- If `'value'` key exists: uses three-parameter form `whereMetadata($key, $operator, $value)`
- If `'value'` key missing: uses two-parameter form `whereMetadata($key, $operator)` where operator becomes the value

This allows proper handling of null values while maintaining shorthand syntax convenience.

#### ⚡ Performance Optimization

[](#-performance-optimization)

For high-volume applications querying metadata frequently, consider adding database indexes. Without indexes, metadata queries perform full table scans. With proper indexes, queries become nearly instant even with millions of records.

##### When to Optimize

[](#when-to-optimize)

- **Small datasets (&lt; 10k transactions)**: No optimization needed
- **Medium datasets (10k - 100k)**: Consider optimization for frequently queried keys
- **Large datasets (&gt; 100k)**: Highly recommended for any metadata queries

##### MySQL/MariaDB: Virtual Columns with Indexes

[](#mysqlmariadb-virtual-columns-with-indexes)

Virtual generated columns extract JSON values into indexed columns for fast queries:

```
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;

return new class extends Migration
{
    public function up()
    {
        $tableName = config('credits.table_name', 'credits');

        // Add virtual columns for frequently queried metadata keys
        DB::statement("
            ALTER TABLE {$tableName}
            ADD COLUMN metadata_source VARCHAR(255)
            GENERATED ALWAYS AS (JSON_UNQUOTE(JSON_EXTRACT(metadata, '$.source'))) VIRTUAL
        ");

        DB::statement("
            ALTER TABLE {$tableName}
            ADD COLUMN metadata_order_id BIGINT
            GENERATED ALWAYS AS (JSON_EXTRACT(metadata, '$.order_id')) VIRTUAL
        ");

        // Add indexes on virtual columns
        Schema::table($tableName, function (Blueprint $table) {
            $table->index('metadata_source');
            $table->index('metadata_order_id');
        });

        // Optional: Composite indexes for common query combinations
        Schema::table($tableName, function (Blueprint $table) {
            $table->index(['metadata_source', 'created_at']);
            $table->index(['creditable_id', 'creditable_type', 'metadata_order_id']);
        });
    }

    public function down()
    {
        $tableName = config('credits.table_name', 'credits');

        Schema::table($tableName, function (Blueprint $table) {
            $table->dropIndex(['metadata_source', 'created_at']);
            $table->dropIndex(['creditable_id', 'creditable_type', 'metadata_order_id']);
            $table->dropIndex(['metadata_source']);
            $table->dropIndex(['metadata_order_id']);
        });

        DB::statement("ALTER TABLE {$tableName} DROP COLUMN metadata_source");
        DB::statement("ALTER TABLE {$tableName} DROP COLUMN metadata_order_id");
    }
};
```

**Performance impact**: Queries go from scanning millions of rows to using index lookups (1000x+ faster).

##### PostgreSQL: GIN Indexes on JSONB

[](#postgresql-gin-indexes-on-jsonb)

PostgreSQL's GIN (Generalized Inverted Index) provides efficient querying for all JSON operations:

```
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;

return new class extends Migration
{
    public function up()
    {
        $tableName = config('credits.table_name', 'credits');

        // GIN index supports all JSON operators (@>, ?, ?&, ?|, etc.)
        DB::statement("
            CREATE INDEX {$tableName}_metadata_gin_idx
            ON {$tableName} USING GIN (metadata)
        ");

        // Optional: Add specific path indexes for even faster queries
        DB::statement("
            CREATE INDEX {$tableName}_metadata_source_idx
            ON {$tableName} ((metadata->>'source'))
        ");

        DB::statement("
            CREATE INDEX {$tableName}_metadata_order_id_idx
            ON {$tableName} ((metadata->'order_id'))
        ");
    }

    public function down()
    {
        $tableName = config('credits.table_name', 'credits');

        DB::statement("DROP INDEX IF EXISTS {$tableName}_metadata_gin_idx");
        DB::statement("DROP INDEX IF EXISTS {$tableName}_metadata_source_idx");
        DB::statement("DROP INDEX IF EXISTS {$tableName}_metadata_order_id_idx");
    }
};
```

**Note**: The GIN index alone enables fast queries for all metadata keys. Path-specific indexes provide marginal additional performance.

##### SQLite: Limited Support

[](#sqlite-limited-support)

SQLite has limited JSON indexing capabilities. For SQLite:

- Metadata queries work but will be slower on large datasets
- Consider using a different database for production if metadata querying is critical
- JSON1 extension must be enabled (available in SQLite 3.38+)

##### Choosing What to Index

[](#choosing-what-to-index)

Index metadata keys that you query frequently:

```
// If you often query by source
$user->credits()->whereMetadata('source', 'purchase')->get();
// → Index: metadata_source

// If you filter by order_id
$user->credits()->whereMetadata('order_id', 12345)->get();
// → Index: metadata_order_id

// If you query by tags array
$user->credits()->whereMetadataContains('tags', 'premium')->get();
// → MySQL: Index on virtual column for tags
// → PostgreSQL: GIN index handles this automatically
```

##### Best Practices

[](#best-practices)

1. **Analyze your queries first**: Use `EXPLAIN` to identify slow queries
2. **Index selectively**: Only index frequently queried keys (each index adds storage overhead)
3. **Use composite indexes**: For queries combining metadata with other columns
4. **Test with production data**: Benchmark before and after indexing
5. **Monitor index usage**: Remove unused indexes to save storage

### 📢 Events

[](#-events)

Events are fired for each credit transaction, transfer, and balance update.

The events are:

- `CreditsAdded`
- `CreditsDeducted`
- `CreditsTransferred`

📚 API Reference
---------------

[](#-api-reference)

### 🔧 Available Methods

[](#-available-methods)

MethodDescription`creditAdd(float $amount, ?string $description = null, array $metadata = [])`Add credits to the model`creditDeduct(float $amount, ?string $description = null, array $metadata = [])`Deduct credits from the model`creditBalance()`Get the current balance`creditTransfer(Model $recipient, float $amount, ?string $description = null, array $metadata = [])`Transfer credits to another model`creditHistory(int $limit = 10, string $order = 'desc')`Get transaction history`hasCredits(float $amount)`Check if model has enough credits`creditBalanceAt(Carbon|DateTimeInterface|int $dateTime)`Get balance at a specific time`credits()`Eloquent relationship to credit transactions`creditsByMetadata(string $key, $operator, $value = null, int $limit = 10, string $order = 'desc')`Get credits filtered by metadata key/value`creditHistoryWithMetadata(array $filters, int $limit = 10, string $order = 'desc')`Get credits filtered by multiple metadata### 🔍 Query Scopes

[](#-query-scopes)

These scopes can be used on the `credits()` relationship:

ScopeDescription`whereMetadata(string $key, $operator, $value = null)`Filter by metadata key/value`whereMetadataContains(string $key, $value)`Filter where metadata array contains value`whereMetadataHas(string $key)`Filter where metadata key exists`whereMetadataNull(string $key)`Filter where metadata key is null/doesn't exist`whereMetadataLength(string $key, $operator, $value)`Filter by metadata array length### ⚠️ Deprecated Methods

[](#️-deprecated-methods)

The following methods are deprecated and will be removed in v2.0. They still work but will trigger deprecation warnings:

Deprecated MethodUse Instead`addCredits()``creditAdd()``deductCredits()``creditDeduct()``getCurrentBalance()``creditBalance()``transferCredits()``creditTransfer()``getTransactionHistory()``creditHistory()``hasEnoughCredits()``hasCredits()``getBalanceAsOf()``creditBalanceAt()``creditTransactions()``credits()`🧪 Testing
---------

[](#-testing)

```
composer test
```

📋 Changelog
-----------

[](#-changelog)

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

🤝 Contributing
--------------

[](#-contributing)

Please see [CONTRIBUTING](CONTRIBUTING.md) for details. You can also join our Discord server to discuss ideas and get help: [Discord Invite](https://discord.gg/kedWdzwwR5).

🔒 Security Vulnerabilities
--------------------------

[](#-security-vulnerabilities)

Please report security vulnerabilities to .

💖 Support This Project
----------------------

[](#-support-this-project)

Laravel Credits is free and open source, built and maintained with care. If this package has saved you development time or helped power your application, please consider supporting its continued development.

[ ![Sponsor on GitHub](https://camo.githubusercontent.com/b54bfcc9644ed7bcc05286df7b65016fc35a3ef50ead57e5942733d1b7663048/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f53706f6e736f722532306f6e2d4769744875622d6561346161613f7374796c653d666f722d7468652d6261646765266c6f676f3d676974687562)](https://github.com/sponsors/climactic) [ ![Support on Ko-fi](https://camo.githubusercontent.com/f29eb9e7ac04ba39e8f164bd49b7170f8d5263e726c135bfbebf865998f3b146/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f537570706f72742532306f6e2d4b6f2d2d66692d4646354535423f7374796c653d666f722d7468652d6261646765266c6f676f3d6b6f2d6669266c6f676f436f6c6f723d7768697465)](https://ko-fi.com/ClimacticCo)### 🌟 Sponsors

[](#-sponsors)

*Your logo here* — Become a sponsor and get your logo featured in this README and on our website.

**Interested in title sponsorship?** Contact us at  for premium placement and recognition.

⭐ Star History
--------------

[](#-star-history)

[![Star History Chart](https://camo.githubusercontent.com/d79000af73c9cad79fccc02bd25646aa4761e7e8f5635c25a4510d8de66bc3e7/68747470733a2f2f6170692e737461722d686973746f72792e636f6d2f7376673f7265706f733d636c696d61637469632f6c61726176656c2d6372656469747326747970653d64617465266c6567656e643d746f702d6c656674)](https://www.star-history.com/#climactic/laravel-credits&type=date&legend=top-left)

📦 Other Packages
----------------

[](#-other-packages)

Check out our other Laravel packages:

PackageDescription🏢 [laravel-workspaces](https://github.com/climactic/laravel-workspaces)Multi-tenancy package for adding workspace (team) functionality with member management, role-based permissions, and invitation system📄 License
---------

[](#-license)

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

⚖️ Disclaimer
-------------

[](#️-disclaimer)

This package is not affiliated with Laravel. It's for Laravel but is not by Laravel. Laravel is a trademark of Taylor Otwell.

###  Health Score

59

—

FairBetter than 99% of packages

Maintenance89

Actively maintained with recent releases

Popularity49

Moderate usage in the ecosystem

Community17

Small or concentrated contributor base

Maturity64

Established project with proven stability

 Bus Factor1

Top contributor holds 83.9% 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

Every ~40 days

Total

13

Last Release

53d ago

PHP version history (2 changes)v1.0.0PHP ^8.2

v1.2.1PHP ^8.4

### Community

Maintainers

![](https://www.gravatar.com/avatar/04e8fd6548e1113d35fb74e60ba71ce472fcf61503f8bd0c5b2f0928910860d4?d=identicon)[climactic](/maintainers/climactic)

---

Top Contributors

[![adiologydev](https://avatars.githubusercontent.com/u/9266227?v=4)](https://github.com/adiologydev "adiologydev (52 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (4 commits)")[![github-actions[bot]](https://avatars.githubusercontent.com/in/15368?v=4)](https://github.com/github-actions[bot] "github-actions[bot] (4 commits)")[![Abeni001](https://avatars.githubusercontent.com/u/103540341?v=4)](https://github.com/Abeni001 "Abeni001 (1 commits)")[![ludioao](https://avatars.githubusercontent.com/u/7070404?v=4)](https://github.com/ludioao "ludioao (1 commits)")

---

Tags

credit-management-systemhacktoberfestlaravellaravel-creditslaravel-packagelaraveltransactionsledgerbalancelaravel-credits

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/climactic-laravel-credits/health.svg)

```
[![Health](https://phpackages.com/badges/climactic-laravel-credits/health.svg)](https://phpackages.com/packages/climactic-laravel-credits)
```

###  Alternatives

[vormkracht10/laravel-mails

Laravel Mails can collect everything you might want to track about the mails that has been sent by your Laravel app.

24149.7k](/packages/vormkracht10-laravel-mails)[spatie/laravel-prometheus

Export Laravel metrics to Prometheus

2651.3M6](/packages/spatie-laravel-prometheus)[021/laravel-wallet

Reliable and flexible wallet system for Laravel

2785.2k](/packages/021-laravel-wallet)[hydrat/filament-table-layout-toggle

Filament plugin adding a toggle button to tables, allowing user to switch between Grid and Table layouts.

6292.3k1](/packages/hydrat-filament-table-layout-toggle)[scalar/laravel

Render your OpenAPI-based API reference

6183.9k2](/packages/scalar-laravel)[ralphjsmit/laravel-helpers

A package containing handy helpers for your Laravel-application.

13704.6k2](/packages/ralphjsmit-laravel-helpers)

PHPackages © 2026

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