Skip to main content

General Ledger

The general ledger (GL) is the accounting backbone of the platform. It provides a hierarchical chart of accounts, double-entry journal posting with approval workflows, and standing instructions for recurring entries.

Chart of Accounts

Account Categories

CategoryNormal BalanceExamples
assetDebitCash, receivables, loans, fixed assets
liabilityCreditCustomer deposits, payables
equityCreditShare capital, reserves
revenueCreditInterest income, fee income
expenseDebitInterest expense, operating expenses

Pre-seeded Account Types

CodeNameCategoryNormal Balance
CASHCash and Cash Equivalentsassetdebit
RECVReceivablesassetdebit
LOAN_ASSETLoans and Advancesassetdebit
FIXED_ASSETFixed Assetsassetdebit
DEPOSITCustomer Depositsliabilitycredit
PAYABLEPayablesliabilitycredit
CAPITALShare Capitalequitycredit
RESERVESReservesequitycredit
INT_INCOMEInterest Incomerevenuecredit
FEE_INCOMEFee Incomerevenuecredit
INT_EXPENSEInterest Expenseexpensedebit
OP_EXPENSEOperating Expensesexpensedebit

Account Hierarchy

GL accounts form a tree. Header accounts (non-posting) organize the tree; leaf accounts allow direct posting.

1000 Assets (header)
├── 1100 Cash and Bank (header)
│ ├── 1101 Cash on Hand (posting)
│ └── 1102 Bank Balances (posting)
├── 1200 Loans and Advances (header)
│ ├── 1201 Personal Loans (posting)
│ └── 1202 Business Loans (posting)
2000 Liabilities (header)
├── 2100 Customer Deposits (header)
│ ├── 2101 Savings Deposits (posting)
│ └── 2102 Current Deposits (posting)

Create a GL Account

POST /api/v1/accounts
{
"account_number": "1103",
"name": "Money Market Instruments",
"description": "Short-term money market holdings",
"account_type_id": "cash-type-uuid",
"parent_id": "1100-header-uuid",
"currency_code": "NGN",
"is_header_account": false,
"is_control_account": false,
"allow_direct_posting": true,
"tags": ["treasury"],
"metadata": {}
}

Requires officer role.

List GL Accounts

GET /api/v1/accounts?currency=NGN&active=true

Get Account Balance and Ledger

GET /api/v1/accounts/:id/balance
GET /api/v1/accounts/:id/ledger

Journals

A journal is a group of balanced debit and credit entries. Every financial event in the system is recorded as a journal.

Journal Lifecycle

PENDING ──▶ APPROVED ──▶ POSTED
│ │ │
▼ ▼ ▼
REJECTED REJECTED REVERSED
StatusDescription
PENDINGCreated, awaiting approval
APPROVEDApproved, ready to post
POSTEDEntries applied to account balances
REJECTEDRejected by approver
REVERSEDPosted journal reversed (creates a reversing journal)

Create a Journal

curl -X POST https://api.korastratum.com/api/v1/cba/journals \
-H "Authorization: Bearer $TOKEN" \
-H "X-Tenant-ID: demo_bank" \
-H "Content-Type: application/json" \
-H "X-Idempotency-Key: jnl-$(uuidgen)" \
-d '{
"journal_type": "REVENUE",
"description": "Monthly service charge",
"fiscal_period_id": "period-uuid",
"transaction_date": "2026-02-28",
"effective_date": "2026-02-28",
"source_system": "ACCOUNT_SERVICE",
"source_reference": "FEE20260228001",
"entries": [
{
"account_id": "receivable-uuid",
"amount": 1000.00,
"entry_type": "debit",
"currency_code": "NGN",
"description": "Service charge debit"
},
{
"account_id": "fee-income-uuid",
"amount": 1000.00,
"entry_type": "credit",
"currency_code": "NGN",
"description": "Service charge income"
}
]
}'

Requires teller role. The journal is created with status PENDING.

Validation Rules

  • Must balance — Total debits must equal total credits.
  • Positive amounts — Entry amounts must be greater than zero. The entry_type (debit/credit) determines direction.
  • Open period — The fiscal_period_id must reference an open fiscal period.
  • Active accounts — All referenced accounts must be active and allow direct posting.
  • Same base currency — All entries must resolve to the same base currency.

Approve and Post

POST /api/v1/journals/:id/approve   # Requires officer role
POST /api/v1/journals/:id/post # Requires officer role

When a journal is posted:

  1. Account balance snapshots are created for each affected account.
  2. Cached balances are updated atomically.
  3. A transaction.completed event is emitted.

Reject

POST /api/v1/journals/:id/reject    # Requires officer role

Reverse a Posted Journal

POST /api/v1/journals/:id/reverse   # Requires manager role

Creates a new reversing journal with opposite entries. The original journal's status changes to REVERSED.

Batch Operations

Create multiple journals at once:

POST /api/v1/journals/batch         # Requires officer role

Post multiple journals at once:

POST /api/v1/journals/batch/post    # Requires manager role

Inter-Branch Transfer

Transfer between GL accounts across branches:

POST /api/v1/journals/inter-branch-transfer   # Requires manager role

Multi-Currency Entries

For non-base currency entries, include the exchange rate:

{
"account_id": "usd-account-uuid",
"amount": 1000.00,
"entry_type": "debit",
"currency_code": "USD",
"exchange_rate": 1580.50,
"base_currency_amount": 1580500.00,
"description": "USD receipt"
}

Standing Instructions

Recurring journal entries that execute automatically on a schedule.

Create a Standing Instruction

POST /api/v1/standing-instructions
{
"name": "Monthly depreciation",
"description": "Fixed asset depreciation posting",
"journal_type": "DEPRECIATION",
"frequency": "MONTHLY",
"start_date": "2026-01-01",
"end_date": "2026-12-31",
"max_executions": 12,
"entries": [
{
"account_id": "depreciation-expense-uuid",
"amount": 50000.00,
"entry_type": "debit",
"currency_code": "NGN"
},
{
"account_id": "accumulated-depreciation-uuid",
"amount": 50000.00,
"entry_type": "credit",
"currency_code": "NGN"
}
]
}

Requires officer role. Approval by manager role is required before the instruction becomes active.

Frequencies

FrequencySchedule
DAILYEvery day
WEEKLYEvery 7 days
BI_WEEKLYEvery 14 days
MONTHLYSame day each month
QUARTERLYEvery 3 months
ANNUALLYOnce per year

Manage Standing Instructions

POST /api/v1/standing-instructions/:id/approve   # manager role
POST /api/v1/standing-instructions/:id/pause # officer role
POST /api/v1/standing-instructions/:id/resume # officer role
POST /api/v1/standing-instructions/:id/cancel # manager role
POST /api/v1/standing-instructions/execute # admin role — trigger pending executions

Next Steps