Post a house credit adjustment

Move a balance by hand the only way the platform allows: a new, balanced, append-only entry.

Owned by Admin · 8 steps · about 18 minutes

Why this exists

Sooner or later somebody's balance is wrong and you have to fix it. This workflow is about the fact that "fix" here never means "edit". The ledger is append-only, enforced by database triggers rather than by convention, and there is no admin surface anywhere — not the data suite, not raw SQL through the console — that can update or delete a posted entry. The only way to change a balance is to post a new balanced transaction that says what you changed and why. Undoing one whole transaction has a control of its ownReverse this transaction, on any transaction's page — which posts the exact mirror with a reason code and links the pair both ways. Compose an adjustment by hand when you are correcting something in part; reverse when the whole posting was wrong.

That sounds bureaucratic until the first time somebody asks what happened to their money. Because nothing is ever rewritten, the statement is a complete and ordered story: the mistake is there, the correction is there, and the reason is attached to both. An editable ledger cannot make that promise no matter how careful its admins are.

Adjustments are ordinary double-entry postings, so the ordinary rules apply. At least two entries. Every entry is on exactly one side. Debits must equal credits to the cent. Per-user accounts require a user id — member house credit, seller earned balance and VIP tab used are all per-user, and the database refuses an entry on them without one. And no posting may drive a user's sub-balance negative: there is no overdraft, no receivable wallet, just a refusal.

Memo discipline matters more here than anywhere else on the platform. The memo you type is the explanation an auditor reads. "Adjustment" is not an explanation.

Before you start

  • An admin session — every ledger admin route is admin-only and a venue manager gets 403.
  • The chart of accounts to hand: the account codes are on the trial balance page.
  • A decided, written reason. Post the memo you would be happy to read aloud.

Practise with

PersonaEmailPasswordNote
adminadmin@club.test admin123the only persona that can post an adjustment
memberalice.credit@demo.club alice-pass-123seeded with $150 prepaid house credit — a safe balance to practise on

Steps 1–4 — Admin

their manual →
  1. 1
    Open the user's credit page. This is the adjustment composer as well as the readout: balances, recent movements, and the chart of accounts to pick from.
    /admin/credit/users/{user_id} ledger
    Expected result Prepaid, earned and tab figures for that user, plus their recent transactions.
    Watch out for Read the three balances as three different things. Prepaid is money they paid in, earned is money they made from resale, tab is money they owe. Correcting the wrong one is a bigger mess than the original error.
  2. 2
    Pull the raw blob for the same user when you want the underlying numbers rather than the page's presentation of them.
    /api/admin/ledger/users/{user_id} ledger
    Expected result Balances, earning lots, tab state and KYC status.
    Watch out for Earning lots matter for cash-out timing, not for spending. A user can spend earned credit immediately and still not be able to withdraw it yet.
  3. 3
    Post the correction: a memo that explains it, and the entries. Give every entry an account code, a direction and an amount, and put the user id on any per-user account.
    Expected result 201 with the new transaction id. The transaction is recorded with kind adjustment.
    Watch out for An empty memo is 422 MEMO_REQUIRED. Unbalanced entries are 422 UNBALANCED_ENTRIES and nothing is written. A per-user account without a user id is 422 USER_REQUIRED. A posting that would take a sub-balance below zero is 409 WOULD_GO_NEGATIVE. Every one of those refusals leaves the ledger exactly as it was.
  4. 4
    Open the transaction you just posted and check it reads the way you meant: debits on the left, credits on the right, equal totals, your memo on top. If it is wrong, use the Reverse this transaction card on this page — pick a reason code, say why in a sentence, confirm.
    /admin/ledger/transactions/{txn_id} ledger
    Expected result The entries with the user attribution on the per-user lines, and a Reverse card above them on any transaction that is not itself a reversal.
    Watch out for Reverse posts the exact mirror of every entry and links the two both ways, so the pair reads as one story. Do not hand-compose the mirror in the composer: it is the same money and about eleven presses instead of four, and the result is an unlinked transaction with no reason code — nothing joins it to the mistake it corrects. One reversal per transaction, ever, and a reversal cannot itself be reversed (409 CANNOT_REVERSE_REVERSAL — re-post the original instead). There is still no edit button anywhere, which is the point: two honest rows beat one tidy one.

Steps 5 — Member

their manual →

It is their balance that moves, and the correction lands on their statement in full view.

  1. 5
    Look at the correction from the member's side, on their statement.
    Expected result Your adjustment appears in the running story with its memo, between the ordinary top-ups and purchases.
    Watch out for The member sees the memo. Write it for them, not for you.

Steps 6–8 — Admin

their manual →
  1. 6
    Understand the neighbouring control that is not an adjustment: setting or freezing a VIP's tab limit.
    /api/admin/credit/users/{user_id}/tab PUT ledger
    Expected result The tab row with its new limit or status.
    Watch out for A tab limit is permission to owe, not a balance. Raising it gives nobody any money, and freezing it stops further spending without cancelling a penny of what is already owed.
  2. 7
    Prove the append-only claim to yourself rather than believing this page: run the mutation attempt probe.
    Expected result A report showing every attempted update and delete against the ledger being rejected by the database.
    Watch out for If any attempt ever succeeds, this endpoint fails loudly with a 500. That is intentional — a silently mutable ledger is worse than a broken endpoint.
  3. 8
    Finish with the integrity report so you know your correction did not break something else.
    Expected result Balanced transactions, lots reconciling to the earned account, no negative sub-balances, payout clearing matching live payouts, and a balanced trial balance.
    Watch out for Fix a red check before you move on. Ledger errors compound: the next report you run is built on the mess you left.