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

Tomato Payments Laravel Package

tomatophp/tomato-payments

tomatophp/tomato-payments is a Laravel package for adding payment management to TomatoPHP apps. It provides gateway integration and transaction tracking so you can accept, record, and manage payments through a consistent, configurable workflow.

View on GitHub
Deep Wiki
Context7

Getting Started

Read composer.json before you run composer require. This package's last release is 2023-08-10, it has one star and zero dependents. The require block tells you immediately whether it will even install on your Laravel/PHP version. If it caps laravel/framework at 9 or 10 and you're on 11+, stop and reconsider — payments is not a place to run --ignore-platform-reqs.

composer require tomatophp/tomato-payments
php artisan about                      # confirm the provider registered
php artisan vendor:publish --list      # see what tags exist before publishing

Publish config and migrations as separate steps, and read the migration files before running them:

php artisan vendor:publish --provider="TomatoPHP\TomatoPayments\TomatoPaymentsServiceProvider" --tag=config
php artisan vendor:publish --provider="TomatoPHP\TomatoPayments\TomatoPaymentsServiceProvider" --tag=migrations

Verify the provider FQN from composer.json → extra.laravel.providers rather than copying it from a README.

Where to look, in this order:

  1. src/TomatoPaymentsServiceProvider.php — bindings, config merge, how drivers get registered.
  2. The published config file — this is the package's API surface: the 11 gateway entries, the default, credential key names, currency/amount-unit settings, sandbox flags.
  3. The driver contract/interface.
  4. One concrete driver you actually plan to use.

First use case: one sandbox charge, outside your app. Pick a single gateway, put sandbox credentials in .env, and drive a charge end to end — create → confirm/redirect → verify → record — in php artisan tinker or a throwaway command. Do not wire the facade into controllers yet. You are testing whether a 2023 driver still speaks a 2025 provider API. That is the whole risk, and it takes about twenty minutes to find out.

Implementation Patterns

Put your own interface in front of it. Non-negotiable here.

interface PaymentGateway
{
    public function charge(Order $order, array $payload): PaymentResult;
    public function verify(string $reference): PaymentResult;
    public function refund(string $reference, ?int $amount = null): PaymentResult;
}

Implement it with a thin class that delegates to the package facade. This is what lets you (a) swap in provider SDKs directly when the package stalls, (b) stub payments in tests, (c) absorb the likely mixed/array returns from an older codebase behind a typed result. Everything in your app depends on PaymentGateway, never on TomatoPayments::.

Resolve the driver per call site, not globally. The whole point of 11 gateways is per-context selection — cards via one provider, wallets via another, a regional method for one market. If the facade only exposes the configured default, look in the source for a driver()/gateway() accessor. If none exists, you need a resolver that rebinds config or the container per request. Ugly, but contain it in one class.

Let the package own its tables; own your join keys. The published migrations create payment/transaction rows — that's fine, let them. But add nullable provider and provider_reference columns to your orders table (or a small payment_attempts pivot of your own). The package's models are not your domain model. When the package is eventually removed, backfilling from your own columns is cheap; reconstructing from a dropped table is not.

Write your own webhook controller. Even if the package ships a callback route, you want: signature verification, raw payload written to a log table first, idempotent order update keyed on the provider's event ID, then optionally call the package's verify. Providers retry — idempotency is not optional, and the package's callback shape is the thing most likely to be stale.

Fake the driver in tests. Either register a null/fake driver in config or bind a stub PaymentGateway in TestCase::setUp(). Never let CI reach a real provider — flaky outbound calls will get the package blamed and removed for the wrong reason.

Use events as the seam. The description claims Laravel-native events. Listen for them to fire emails, invoices, and analytics rather than bolting that into the charge flow. If the event list turns out thin, dispatch your own from your wrapper — keep the seam in your code.

Day-to-day admin work: if you're in the TomatoPHP panel ecosystem, the real productivity win is the panel integration — settings screens for credentials, a transactions resource for lookup and refunds. That's where this package saves hours compared to hand-rolling admin views over Stripe objects.

Gotchas and Tips

  • Amount units will bite you. Some gateways want integer minor units, some decimal strings, some a currency-specific exponent (JPY = 0 decimals). Verify with a sandbox charge of exactly 1.00 and confirm what the provider dashboard shows. A silent ×100 is the most expensive bug in this category.
  • The published migrations become yours forever. Copy the originals somewhere diffable before migrate. Better: edit them before first run to add indexes on the columns you'll query — order ID, provider transaction ID, status. Adding indexes later on a payments table is a maintenance window.
  • Pin the version and write down why. "tomatophp/tomato-payments": "1.0.*" or the exact tag, plus a note in your dependency review: date, version, Laravel/PHP it was verified against. With zero dependents there is no community pressure to fix anything.
  • Check for a pinned provider SDK. If the package requires stripe/stripe-php (or similar) in its own require, that version is dictated by the package. A stale SDK is a security-review finding; overriding it at root level is fragile.
  • Credentials via env() only. The config file gets committed. Confirm every credential in the config reads from env(). If a driver reads a key the config doesn't expose, patch the config — it's your file now.
  • Expect untyped returns. Old packages return arrays or mixed. Assert inside your adapter (if (! $result instanceof PaymentResult) throw ...) so a shape change surfaces in one place instead of in production.
  • Custom drivers are the right escape hatch. Look in the service provider for how drivers are bound — typically a config('payments.drivers') map of name → class. Registering your own driver lets you add or fix a gateway without forking. Prefer this over composer patch.
  • Debugging an opaque failure: log the raw provider response inside the driver method, before normalization. The useful error message is almost always swallowed during the transform, and logging around the facade call won't show it.
  • Set an explicit re-evaluation trigger. Schedule a review for your next Laravel major. The realistic end state for a package in this condition is replacement with provider SDKs behind your own PaymentGateway interface — which is exactly why that interface exists. The package should be a swappable detail from day one, not a foundation.
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.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource