Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Pay Pocket Laravel Package

toneflix-code/laravel-pay-pocket

Laravel Pay Pocket is a lightweight Laravel package for adding wallet and payment functionality to your application. It provides simple APIs for managing balances, transactions, and payment flows, making it easy to integrate secure pay-ins and payouts.

View on GitHub
Deep Wiki
Context7

Getting Started

Check your upgrade eligibility first. 4.0.0 is a hard bump: PHP ^8.3|^8.4 and Illuminate ^12.0|^13.0. If you are still on Laravel 10/11 or PHP 8.2, pin to the 3.x line — there is no compatibility shim.

Upgrade from 3.x (breaking rename). The vendor and namespace both moved, so a plain composer update will not work cleanly:

composer remove toneflix-code/laravel-pay-pocket
composer require toneflix/laravel-pay-pocket:^4.0

Then do a project-wide replace of ToneflixCode\LaravelPayPocket → Toneflix\LaravelPayPocket. This hits more than your use statements: published config files, any extended/overridden package classes, cached config in bootstrap/cache, and custom exception handlers that reference the package's exception classes. Run php artisan config:clear (and optimize:clear on deployed environments) before smoke-testing.

Where to look first. Open the published config (config/pay-pocket.php after vendor:publish) before writing any code. The pocket/wallet names, the balance columns on your model, and the transaction table shape are all driven from there — everything else in the package is downstream of that config.

First use case — the 15-minute path:

  1. Publish config and migrations, then php artisan migrate.
  2. Add the wallet trait to your User model (confirm the exact trait FQCN in the v4 README, since the namespace changed).
  3. $user->deposit(5000, 'wallet', 'Initial top-up')
  4. $user->getWalletBalance('wallet') (or equivalent accessor — check the README for the v4 method name)
  5. $user->withdraw(2000, 'wallet', 'Payout')
  6. Inspect the transaction history method to see the ledger rows this produced.

That loop — deposit, read balance, withdraw, read ledger — is the whole mental model. Everything else is variants.

Implementation Patterns

Model the pockets before you model the money. The package's value is that one Eloquent model can hold several segregated balances (main wallet, bonus, referral credit, subscription allowance). Decide your pocket taxonomy up front and put it in config; retrofitting a new pocket later means a config change plus a column/migration if the package stores one column per pocket. Treat the pocket list as a schema decision, not a runtime toggle.

Wrap every write in a domain action, not a controller. Controllers should not call deposit/withdraw directly. Create App\Actions\CreditWallet / DebitWallet classes that own the DB transaction, the reference/idempotency key, and the exception translation. This is the single highest-leverage pattern with this package: it keeps package-specific calls out of your HTTP layer, so the inevitable namespace/API churn in a future major lands in one directory.

DB::transaction(function () use ($user, $amount, $ref) {
    // guard against replay using your own idempotency table keyed on $ref
    $user->deposit($amount, 'wallet', $description);
});

Treat the ledger as the source of truth, the balance column as a cache. The package maintains both. Your reporting, refunds, and reconciliation queries should aggregate transaction rows grouped by pocket; the balance accessor is for display and fast guards. This distinction saves you the first time a balance drifts.

Webhook/payment integration. Give every gateway callback a deterministic reference (charge ID, order UUID) and store it alongside the transaction via your own table or the description field. Gateways retry; without idempotency you will double-credit. Check the package's transaction model for a reference/metadata column before inventing one.

Authorization belongs in a policy, not the package. canWithdraw-style checks should live in WalletPolicy / Gate::define so that admin-initiated debits and scheduled jobs can bypass them via Gate::forUser(). Do not encode "only the owner can withdraw" inside your action class.

API surface. Expose balances via an API Resource that returns integers in minor units plus a currency code from config, and paginate transaction history — a busy account's ledger grows without bound and eager-loading it into a profile endpoint will eventually time out.

Testing. Use RefreshDatabase, factories, and assert on ledger rows rather than only on the returned balance, since balance is derived state. Add one test that asserts insufficient-funds behaviour throws the package exception and that your action converts it to a 422. If you are contributing to the package itself, note that 4.0 moved dev tooling to Testbench ^10.11|^11.1 and Pest ^4 — your local test suite conventions will differ from the package's.

Multi-tenant / multi-guard. If your users are polymorphic or you run several authenticatable models, verify the package's migration uses a morph-style owner key. If it uses a plain user_id, you will need a custom migration or a walletable pivot of your own — check the published migration before migrating in a multi-model app.

Gotchas and Tips

The 4.0 rename is the big one. A partially-completed upgrade is the most likely failure mode: composer remove succeeds, composer require succeeds, but a stale ToneflixCode\... import in a queued job or an event listener surfaces only at runtime — often days later in a worker. Grep the whole repo including config/, database/, app/Providers/, and any custom exception handler registrations. Also clear the config cache: a cached config referencing the old namespace produces confusing Class not found errors that look like a corrupt autoloader.

Do not composer require the new name before removing the old. With both packages installed you get two sets of classes with identical short names and a genuine risk of the wrong one being autoloaded.

Published config is now stale in a subtle way. The rename instructions say to replace the namespace in the published config, but if 4.0 also changed any config keys or defaults, your 3.x-published file will silently miss them. Diff your config/pay-pocket.php against the package's config/pay-pocket.php. This is worth doing for every major.

Pocket names are validated against config. Deposit/withdraw to a pocket string that is not in config throws — and because these calls often live behind form input, an unvalidated pocket field becomes a 500 instead of a 422. Add Rule::in(array_keys(config('pay-pocket....'))) to your Form Request.

Config changes require a cache clear and possibly a migration. In production with config:cache, adding a pocket to an array looks like it does nothing. And because balances are per-pocket columns in the shipped migration, a new pocket may need a new column — never edit an already-run published migration; publish a fresh one that adds the column.

Concurrency and negative balances. Two simultaneous withdrawals on the same user can both pass a pre-check and both write, depending on how the package guards. Always run wallet mutations inside DB::transaction with a lockForUpdate on the owner row, and rely on an exception on insufficient funds rather than a if (balance > x) check before the call.

Money representation. Check the migration's column type before assuming decimals are safe. If balances are decimal/float, do arithmetic in integer minor units in your own code and convert at the boundary; float accumulation over thousands of transactions produces visible cent-level drift that users will report.

Debugging a wrong balance. The fastest diagnostic is always the same query: sum the ledger for that owner and pocket, grouped by pocket, and compare to the cached balance. A mismatch means something wrote outside the package (a mass update, a seeder, an admin script), which is by far the most common cause.

Laravel 13 support is forward-looking, not a reason to upgrade. The headline feature here is the version matrix, not new capability. Only move to 12/13 and this package's 4.0 together if you actually need that Laravel version; otherwise the rename buys you nothing but a find-and-replace and a worker restart.

Extension points to prefer over patching. If you need custom behaviour (custom transaction model, extra columns, events), publish and extend rather than editing vendor/. Bind your subclass in a service provider and, if the package resolves models from config, point the config key at your class. Anything you patch into vendor/ disappears on the next composer update — and given this package has already done one vendor move, another is plausible.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect
youbar/easy-crud
c-point-labs/laravel-hostyourai
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo