Search by

Financial reconciliation for Laravel: compare internal payments with provider data and detect missing, duplicate and mismatched transactions.

v0.1.0 2026-09-29 21:44 UTC

This package is auto-updated.

Last update: 2026-09-29 21:52:55 UTC


README

Financial reconciliation for Laravel.

Compare internal payments with a provider's records, automatically match the valid transactions, and detect missing payments, duplicates, wrong amounts and settlement problems. Every run is stored as an immutable audit trail. Money is handled as exact decimals, never floats. Matching is deterministic: no AI, no guessing.

Source records: 10,000     Target records: 9,997
Matched: 9,972             Discrepancies: 28
Source total: USD 824,192.00   Target total: USD 823,742.00   Difference: USD 450.00

Why ReconcileKit?

Payment systems rarely have one source of truth.

Your application can say:

$824,192 received

while your provider says:

$823,742 settled

ReconcileKit helps answer:

  • Which transactions match?
  • Which payments are missing?
  • Are there duplicates?
  • Which amounts differ?
  • How much money is unexplained?

Use cases

  • Stripe/payment provider reconciliation
  • Marketplace payouts
  • Wallet balances
  • Crypto exchange transactions
  • Bank exports
  • Refund reconciliation
  • Internal ledger verification

Install

composer require reconcilekit/core
php artisan vendor:publish --tag=reconcilekit-config
php artisan migrate

Requires PHP 8.3+ and Laravel 13.

Example

final class StripePaymentsReconciliation extends ReconciliationDefinition
{
    public function source(): Source
    {
        return DatabaseSource::make('internal-payments')
            ->query(fn () => Payment::query())
            ->id('id')->amount('amount')->currency('currency')
            ->reference('stripe_payment_intent')->occurredAt('created_at');
    }

    public function target(): Source
    {
        return CsvSource::make('stripe-csv')->path(storage_path('app/stripe.csv'))
            ->id('id')->amount('amount')->currency('currency')
            ->reference('payment_intent')->occurredAt('created')->timezone('UTC');
    }

    public function rules(): array
    {
        return [ExactReferenceRule::make(), CurrencyRule::make(), AmountRule::make(), DateWindowRule::withinHours(72)];
    }
}

Register it under profiles in config/reconcilekit.php, then:

php artisan reconcile:run stripe-payments --from=2026-09-01 --to=2026-10-01
php artisan reconcile:run stripe-payments --queue      # or from the scheduler
php artisan reconcile:show <run>
$result = Reconcile::make('stripe-payments')->from('2026-09-01')->to('2026-10-01')->run();
$result->matchedCount(); $result->discrepancyCount(); $result->difference();

What is in Core

Database and CSV sources, a decimal-safe money type, deterministic matching rules, discrepancy classification, immutable run history with record snapshots, manual resolution API, events, structured logs, Artisan commands (reconcile:list|run|show|retry|prune), queued runs and Laravel scheduler support.

Documentation

Start with the documentation index: installation, quick start, concepts, sources, matching rules, custom sources and rules, queues, scheduling, events, the audit trail, the command line, configuration, testing, performance and troubleshooting.

Development

composer install
vendor/bin/pest
vendor/bin/phpstan analyse --memory-limit=1G
vendor/bin/pint --test
composer bench      # opt-in 100,000-record benchmark

License

MIT. See LICENSE.