Skip to content
Validation map →

Payout process flows

This translates the settlement discussion into payout language for this codebase. In this system, settlement is internal wallet movement from current to available. Payout is the external money event that moves available to reserved, then executes bank/vendor transfer.

Product policy with vendor fallback payoutNumber at initiation External reference at execution Adjustments at initiation Reversal → adjustment, not wallet money

Anchors in repo

  • Payout initiation: PayoutService.initiate
  • OTP approval: PayoutService.approvePayoutByOtp
  • Execution + PoP: PayoutService.executePayout
  • Mismatch review: PayoutService.reviewCompensation
  • Wallet semantics: WalletBalanceService reserve / consume / release
  • Execution attempts: PayoutExecution rows
Main change: payout initiation should stop accepting the external referenceId. The system should generate a payoutNumber before execution so operators have a stable internal identifier. The external reference should be captured only during execution, then copied back to the payout record as the latest final reference.

Policy decisions locked

Area Decision
Policy scope Product config first, vendor fallback
Adjustment entity Separate durable payout adjustment table/entity
Adjustment timing Apply at payout initiation
Application mode control System admin only
Mismatch semantics Keep root payout status simple, nuance in workflow/queue
Reversal No automatic wallet mutation; always create adjustment unless recovered already

Primary flow

Policy / decision Successful state change Exception / review path

Gray pills on arrows describe the outcome or action for that connector (they sit above the line so the arrow stays readable).

Payout initiation to reconciliation flow
Wallet has available funds
Settlement already moved current → available
Initiate payout
Base amount + selected adjustments
Server computes final payout
Policy auto-apply + manual selections. Generate payoutNumber with JPO prefix.
Reserve funds
available → reserved
OTP approval
Normal payout approval path
Exception approval?
If policy-derived proposal overridden
Execute payout
PoP + actual amount + external reference
Consume reservation
reserved decreases on success
Exact transfer
status = success. workflow = executed.
Mismatch transfer
status = success. queue = awaiting_reconciliation.
Compensation review
Resolve manual reconcile / carry-forward / invoice
Adjustment opened
Future obligation tracked durably
Reverse payout
No wallet mutation. Create recoverable/payable adjustment.
Next
Compute total
Reserve balance
OTP approval
Yes — exception path
Resolved — continue
Execute transfer
Consume on success
Record execution
Open compensation
Track adjustment
Reverse when authorized

Key semantic split: internal payout identity exists at initiation; bank/provider identity arrives only at execution. Reversal never manufactures wallet money.

Proof of payment correction flow

One case from the discussion document was missing from the first draft: the payout amount can be correct while the proof of payment document is wrong. That should be handled with a dedicated proof replacement endpoint, not by reversing a valid payout.

Recommended endpoint

Add an endpoint such as POST /payouts/:id/proof-of-payment/replace.

  • Only finance reconciliation approver or system admin should be allowed to use it.
  • The request should require a replacement file and a reason note.
  • The old proof document should remain in audit history instead of being silently overwritten.
  • The latest execution attempt should point to the replacement document after the update.

Expected flow

  1. An operator finds an executed payout whose amount is correct but whose proof file is wrong.
  2. An authorized user uploads the replacement proof and explains why the original file was wrong.
  3. The system stores the new document, keeps the old document in history, and records who made the change.
  4. Vendor-facing notifications and later reads should use the latest approved proof document.

Adjustment lifecycle

1. Create source fact. Mismatch, gross payout invoice-back arrangement, manual recovery, or reversal creates a payout adjustment record.

2. Resolve policy. Product-level mode applies first. If absent, vendor fallback applies. Modes are admin-controlled only.

3. Surface at initiation. Eligible open adjustments appear when next payout is created. Some auto-apply, some require manual selection, some stay as invoice/manual obligations.

4. Track residual balance. Partial use keeps remaining amount open until resolved.

Reversal flow

  1. Only finance reconciliation approver or system admin may reverse executed payout.
  2. Cancellation remains pre-execution concern; reversal is post-execution concern.
  3. Endpoint requires reason, note, and evidence by reason policy.
  4. Default behavior creates recoverable/payable adjustment unless recovery already happened.
  5. No direct wallet credit or debit occurs during reversal.
Why no automatic wallet move?

External cash already left platform. Crediting wallet immediately would create false liquidity before funds actually return or before future offset happens.