Skip to content

General Ledger

The general ledger module provides account-level transaction queries and the enhanced trial balance report (ميزان المراجعة). All endpoints read from posted journal entries only and do not modify data.

API Endpoints

MethodPathDescription
GET/api/accounting/ledger/account/{id}Account ledger with opening balance
GET/api/accounting/ledger/trial-balanceEnhanced trial balance
GET/api/accounting/ledger/balancesMultiple account balances

Trial Balance (ميزان المراجعة)

Returns opening, period movement, and closing balances for each account. Supports date-range filtering, zero-balance inclusion, and account-type filtering.

Opening-balance entries

Journal entries of type opening always count toward the opening balance column, never toward period movement — even when the report's date_from equals the fiscal year's start date (the opening JE is dated on that date). This keeps opening + period movement = closing exact and prevents the opening balance being double-counted.

Parameters

ParameterTypeRequiredDefaultDescription
date_fromdateNoStart of period. Entries before this date become opening balance
date_todateNoEnd of period
include_zero_balancesbooleanNofalseInclude accounts with no movement
levelstringNodetailAccount type filter: detail, header, or all
fiscal_year_idintegerNoFilter by fiscal year

Request

bash
curl -X GET \
  "https://your-domain.com/api/accounting/ledger/trial-balance?date_from=2026-01-01&date_to=2026-06-30" \
  -H "Authorization: Bearer {token}"
dart
final response = await dio.get('/api/accounting/ledger/trial-balance', queryParameters: {
  'date_from': '2026-01-01',
  'date_to': '2026-06-30',
});

Response

json
{
  "data": [
    {
      "account_id": 1,
      "account_code": "1101",
      "account_name": "النقد في الصندوق",
      "classification": "assets",
      "nature": "debit",
      "is_header": false,
      "opening_debit": 50000.000,
      "opening_credit": 0,
      "period_debit": 15000.000,
      "period_credit": 8000.000,
      "closing_debit": 57000.000,
      "closing_credit": 0,
      "total_debit": 65000.000,
      "total_credit": 8000.000,
      "balance": 57000.000
    }
  ],
  "totals": {
    "total_opening_debit": 50000.000,
    "total_opening_credit": 50000.000,
    "total_period_debit": 15000.000,
    "total_period_credit": 15000.000,
    "total_closing_debit": 57000.000,
    "total_closing_credit": 57000.000
  },
  "warnings": []
}

Column Descriptions

ColumnArabicDescription
opening_debitرصيد أول المدة مدينDebit balance before date_from
opening_creditرصيد أول المدة دائنCredit balance before date_from
period_debitحركة الفترة مدينDebit movement between date_from and date_to
period_creditحركة الفترة دائنCredit movement between date_from and date_to
closing_debitرصيد آخر المدة مدينOpening + period debit net balance
closing_creditرصيد آخر المدة دائنOpening + period credit net balance
is_headerحساب رئيسيtrue when the row is a header (control) account that carries direct postings — an anomaly (see warnings)

Header-Account Warnings

A journal entry line must always target a detail account — header (control) accounts only aggregate their children's balances. Posting directly onto one makes the amount vanish from the detail-level report and unbalances the trial balance.

If any posted line sits on a header account, that account is included in the detail-level report anyway (so totals still foot) with is_header: true, and the response warnings array describes it:

json
"warnings": [
  {
    "type": "posting_on_header_account",
    "account_id": 1,
    "account_code": "1",
    "account_name": "الأصول",
    "closing_debit": 744.95,
    "closing_credit": 0,
    "message": "Journal entry lines cannot be posted to header (control) account(s): 1. ..."
  }
]

This condition is also reported by GET /api/accounting/integrity-check (posted_lines_on_header_accounts). New postings to header accounts are now rejected by the API — see Journal Entries.

Behavior Notes

  • When no date_from is provided, all entries are treated as period movement (opening = 0)
  • When include_zero_balances=true, all accounts of the selected level are returned even if they have no entries
  • The classification field values are: assets, liabilities, equity, revenue, expenses
  • Legacy fields total_debit, total_credit, and balance are preserved for backward compatibility

Account Ledger

Returns all posted journal entry lines for a specific account, with an opening balance and per-entry running balance.

Parameters

ParameterTypeRequiredDescription
from_datedateNoStart date filter
to_datedateNoEnd date filter
cost_center_idintegerNoFilter by cost center

Request

bash
curl -X GET \
  "https://your-domain.com/api/accounting/ledger/account/1?from_date=2026-01-01&to_date=2026-12-31" \
  -H "Authorization: Bearer {token}"

Response

json
{
  "data": {
    "opening_balance": 1500.000,
    "entries": [
      {
        "id": 42,
        "journal_entry_id": 15,
        "entry_number": "JV-2026-00015",
        "date": "2026-01-20",
        "entry_description": "Office supplies purchase",
        "debit": 500.000,
        "credit": 0,
        "base_debit": 500.000,
        "base_credit": 0,
        "running_balance": 2000.000,
        "line_number": 1,
        "description": null
      }
    ]
  }
}

Multiple Account Balances

Returns balances for specific accounts, or all detail accounts when no IDs are provided.

Parameters

ParameterTypeRequiredDescription
account_idsstringNoComma-separated account IDs. Omit for all detail accounts
as_of_datedateNoDate to calculate balance up to

Request

bash
curl -X GET \
  "https://your-domain.com/api/accounting/ledger/balances?account_ids=1,2,3" \
  -H "Authorization: Bearer {token}"

Response

json
{
  "data": [
    {
      "account_id": 1,
      "account_code": "1101",
      "account_name": "Cash on Hand",
      "total_debit": 65000.000,
      "total_credit": 8000.000,
      "balance": 57000.000,
      "nature": "debit"
    }
  ]
}

Moon ERP API Documentation