ACAKM ClearingPayment processor
Processor · port 4200

Where a payment becomes an accounting fact.

Owns the payment state machine, a double-entry ledger kept independently of the acquirer’s, the saga that compensates for unknown outcomes, a transactional outbox, and reconciliation.

Authorisation is a hold and posts nothing. Capture is the money. Conflating the two is the most common modelling error in payments software.

Transactions

6

every lifecycle state

Captured

3

money actually moved

Ledger postings

3

9 signed entries

Ledger balance

balanced

every posting sums to zero

Chart of accounts

Positive is a debit, negative a credit. One signed column makes “does this balance” a single SUM.

  • REVENUE:PROCESSING_FEES$-6.26
  • ASSETS:ACQUIRER_RECEIVABLE$375.16
  • ASSETS:PSP_RECEIVABLE$86.12
  • LIABILITIES:MERCHANT_PAYABLE$-455.02
  • Sum$0.00

Endpoints

  • POST/api/v1/paymentsRecords PENDING before contacting the acquirer, so a crash cannot orphan a hold.
  • POST/api/v1/payments/:id/captureThe financial event. Both ledgers post here.
  • POST/api/v1/payments/:id/refundA new mirrored transaction, never an edit.
  • POST/api/v1/external-captureStripe-rail captures land here, booked to PSP_RECEIVABLE.
  • POST/api/v1/reconcilePer line, scoped to one counterparty.
  • GET/api/v1/trace/:traceIdThis service’s account of one payment.

The patterns, and what breaks without them

0 reconciliation runs recorded.

Transactional outbox

Commit-then-publish loses events on a crash; publish-then-commit emits events for things that never happened. Writing the intent in the same transaction turns an impossible atomicity problem into ordinary at-least-once delivery.

Saga with compensation

A timeout is not a failure. It is an unknown outcome. Retrying could place a second hold, so the processor sends a reversal instead, which is safe whether or not a hold exists.

Reversal is a new entry

Never a delete. Deleting a posting destroys the audit trail; the correct record is “this happened, then it was undone”.

Reconciliation per counterparty

Rail A lines are compared against AKM Bank, rail B against Stripe. Pointing one file at the other’s captures reports every one as a break.