Accounting
Every financial state change produces balanced double-entry journal entries—worked through Harbor's disbursement and first payment—and posted lines are never edited, only adjusted or reversed.
A ledger earns its keep by still being true a year later, when nobody remembers the argument. That is why posted lines are never edited: every financial state change produces balanced double-entry journal entries, and a correction is an explicit adjustment or reversal that leaves the original where it was. An edited line would leave the books showing the tidied answer with no evidence that anything had ever been wrong—and the first person to ask why a balance moved would have nothing to read. This guide works the entries for Harbor’s disbursement and first payment line by line.
Loan balances are projections over those posted transactions and balanced journal entries: they do not change because a provider accepted a request, an operator wrote a note, or a workflow reached approval.
Debits equal credits, in one currency
For every posted transaction:
sum(debit lines) = sum(credit lines)
Journal entries are read entry-per-line: each row is a single DEBIT or CREDIT line against one ledger account, and the lines of a balanced transaction share a transactionId. Every line carries an effective transaction date, a submission date, the source entity type and id, and its currency, so the accounting is explainable from a payment, funding, charge, accrual, refund, or servicing command.
Harbor is advanced $8,400 and receives $8,148
A $252.00 prepaid finance charge is withheld from proceeds. Both figures are true at once: the receivable is what Maya owes, the cash is what left the building, and the withheld charge is the difference the ledger names rather than absorbs.
Harbor's disbursement, line by line
Receivable = cash released + charge withheld
- Loan principal receivabledebit — amount contractually advanced
- $8,400.00
- Funding clearing / cashcredit — net funds released to Maya
- $8,148.00
- Origination-fee clearing / incomecredit — withheld charge, per product policy
- $252.00
- Debits = credits
- $8,400.00
Harbor’s first payment posts three lines
Harbor's first installment, line by line
Cash received = principal retired + interest earned
- Cash / payment clearingdebit — the money that arrived
- $517.14
- Loan principal receivablecredit — principal retired
- $424.39
- Interest receivable or incomecredit — per accrual policy
- $92.75
- Debits = credits
- $517.14
Query the entries by their source transaction—the postedTransactionRef from the payment read, prefixed as a loan transaction:
curl "$BASE/v1/journalentries?transactionId=L30411&loanId=7204" \
-H "Authorization: Bearer $TOKEN" \
-H "LendEasy-Tenant: demo-lender"
{
"totalFilteredRecords": 3,
"pageItems": [
{
"id": 90211,
"officeId": 1,
"glAccountId": 14,
"glAccountName": "Interest income",
"glAccountCode": "4100",
"glAccountType": { "id": 4, "value": "INCOME" },
"transactionDate": [2026, 9, 12],
"entryType": { "id": 2, "value": "CREDIT" },
"amount": 92.75,
"transactionId": "L30411",
"entityType": { "id": 1, "value": "LOAN" },
"entityId": 7204,
"currency": { "code": "USD" },
"submittedOnDate": [2026, 9, 15]
}
]
}
The list uses the standard list shape—totalFilteredRecords plus pageItems—with glAccountId, loanId, transactionId, entityType, manualEntriesOnly, and fromDate/toDate filters, and response dates serialize as [year, month, day] arrays.
Effective date versus posting time
transactionDate answers when the financial event belongs in loan calculations. submittedOnDate answers when it was recorded. Harbor’s ACH payment settles and posts on September 15 but is effective September 12, so allocation and delinquency are recomputed from September 12. Collapse the two dates into one and Maya pays three days of interest for time the ACH network spent, and stands three days closer to a delinquency she did not cause.
Backdating is controlled, not arbitrary:
- validate the business date and open accounting period;
- prevent conflict with completed statements or terminal states unless correction policy allows it;
- reprocess dependent allocation and accrual deterministically;
- create explicit adjustment or reversal entries—never edit posted lines;
- regenerate affected read models and reconciliation state.
Nine event families, each with its own entry
A recovery is not a late installment, and a waiver is not a payment. Each family posts its own shape, which is what keeps a portfolio’s income readable after the fact instead of arriving as one undifferentiated stream of cash:
| Event | Accounting behavior |
|---|---|
| Funding posted | Establishes receivable and cash/clearing movement. |
| Interest accrual | Recognizes receivable and income under product policy. |
| Payment posted | Clears cash and reduces components in allocation order. |
| Payment returned | Reverses the original economic effect with explicit linkage. |
| Charge assessed | Establishes charge receivable and configured income/liability. |
| Charge waived | Reduces eligible receivable and income/contra account. |
| Refund posted | Creates outbound money movement and one linked balance effect. |
| Charge-off | Reclassifies or recognizes loss under configured accounting policy. |
| Recovery payment | Records post-charge-off recovery without pretending it is a normal installment. |
The entries above name roles, not codes
GET /v1/glaccounts returns the chart of accounts—each account’s glCode, type (ASSET, LIABILITY, EQUITY, INCOME, EXPENSE), usage, whether manual entries are allowed, and activation. GET /v1/glaccounts/{id} returns one account. Product accounting rules map loan events onto these accounts, and the chart is yours: two lenders can post Harbor’s disbursement to differently numbered accounts without either one’s economics changing.
A manual entry is never a side effect
POST /v1/journalentries posts a balanced manual entry—matching debits and credits arrays, an office, a transaction date with dateFormat and locale, and a comment. The route is restricted to accounting administrators, and loan-servicing money movement never uses it. That separation is what lets a controller read every manual entry as somebody’s deliberate decision, instead of having to work out which ones the platform wrote on its own.
The journal is the export surface
Posted activity reaches an external accounting system through the accounting export, which consolidates each business date into one balanced journal entry per account and pushes it into QuickBooks Online under an operator-owned mapping.
There is no trial-balance resource, and that absence is deliberate. A point-in-time trial balance is derived operator-side from the immutable journal detail: export entries by transaction-date range, aggregate by account, and reconcile totals and source counts to your ERP. A second “finance balance” computed from API snapshots—or from SQL run against production—is a second set of books, and the two disagree the first time a backdated correction lands, with no way to tell which one moved. The journal-entry list with its date and account filters is the surface every derived figure should come from.
Repair posts; it never edits
If a provider settlement has no ledger entry, reconciliation opens a classified exception. Repair posts the missing authorized entry or records why the external state is wrong. It never edits journal lines or resubmits money blindly, because a repair that rewrote history would destroy the only evidence that the drift existed—and a repair that blindly resubmitted would debit a borrower twice for a payment that had already arrived. See Reconciliation & drift.