Skip to content

Ledgers (Chart of Accounts)

Ledgers represent accounts in the chart of accounts. Every financial transaction flows through ledger accounts via journal entries.

Account Types

Type Description Normal Balance
asset Cash, bank accounts, receivables, equipment Debit
liability Payables, loans, credit cards Credit
equity Owner's equity, retained earnings Credit
revenue Sales, service income Credit
expense Rent, payroll, utilities, supplies Debit

List Ledgers

bash
curl "https://api.ondayzero.com/api/v1/ledgers?type=expense&status=active" \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID"

Filter Parameters

Parameter Type Description
name string Partial name match
type string asset, liability, equity, revenue, expense
status string active, inactive
id string Comma-separated ledger UUIDs
include_balances boolean Fill each ledger's balance (cents, oriented on its normal side) from the books. Off by default, when balance is null
as_of_date date Balance date (YYYY-MM-DD) for include_balances; defaults to today

Plus the standard pagination parameters. GET /api/v1/ledgers/{ledger_id} returns one ledger.

Each ledger carries id, name, type, sub_type, debit_credit, sort_code, account_number, status, currency, parent_id, report_cash_flow, cash_flow_section, cfs_class, depreciation_tag, editable, financial_account_type, is_required, system_key (set on system ledgers such as accounts_receivable), and account_mask (last four digits of a linked bank or card account).

Create a Ledger

There are two creation modes — templated (a standard financial account, auto-configured) and custom (you specify the accounting properties):

Templated

bash
curl -X POST "https://api.ondayzero.com/api/v1/ledgers" \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Operating Checking",
    "financial_account_type": "bank_account"
  }'

financial_account_type is one of bank_account, credit_card, payments, payroll, loan, prepaid_card, accounts_receivable, accounts_payable.

Custom

bash
curl -X POST "https://api.ondayzero.com/api/v1/ledgers" \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Prepaid Insurance",
    "type": "asset",
    "sub_type": "current_assets",
    "debit_credit": "debit",
    "sort_code": 1400,
    "report_cash_flow": true,
    "account_number": "1400",
    "description": "Insurance premiums paid in advance",
    "parent_id": "PARENT_LEDGER_UUID"
  }'

Response data is the new ledger (abbreviated):

json
{
  "success": true,
  "data": {
    "id": "019ab37c-d4a2-7b38-85f0-6b2a3c8e9f1a",
    "name": "Prepaid Insurance",
    "type": "asset",
    "sub_type": "current_assets",
    "debit_credit": "debit",
    "sort_code": "1400",
    "account_number": "1400",
    "status": "active",
    "currency": "USD",
    "editable": true,
    "balance": null
  }
}

Custom mode requires name, type, sub_type, debit_credit, sort_code (an integer) and report_cash_flow. Optional extras: currency (USD, CAD, AUD, EUR, GBP), editable (default true; whether journal entries can be posted manually), status (active by default), account_number (chart-of-accounts code), parent_id (nest under a parent account), cash_flow_section (operating, investing, financing, excluded), cfs_class (indirect-method cash flow class such as cash, ar, inventory, ppe, ap, lt_debt, retained_earnings, revenue, cogs, opex; derived from the type when omitted), and depreciation_tag (depreciable / amortizable — lets fixed assets be capitalized from this account's transactions).

Update a Ledger

bash
curl -X PUT "https://api.ondayzero.com/api/v1/ledgers/{ledger_id}" \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Prepaid Insurance (Current)",
    "description": "Short-term insurance prepayments"
  }'

Updates accept the same fields as create except currency (all optional), including type to reclassify an account and status to archive it. An inactive ledger can only have its status changed. Renaming to a name an active ledger already holds returns 409, and a system ledger's name, type and debit_credit cannot be changed (400). An empty body returns the ledger unchanged.

Merge Ledgers

Consolidate multiple accounts into one. All journal entry lines, transactions, budgets, reconciliations, and bank rules are reassigned. Source accounts are archived.

bash
curl -X POST "https://api.ondayzero.com/api/v1/ledgers/merge" \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "source_ledger_ids": ["LEDGER_UUID_1", "LEDGER_UUID_2"],
    "target_ledger_id": "TARGET_LEDGER_UUID",
    "new_name": "Consolidated Office Expenses"
  }'

Source and target must be the same kind of account (same type, sub_type and debit_credit), the target must be active and cannot also be a source, and bank-linked ledgers cannot be merged. System ledgers can only merge into another system ledger and additionally require "confirmation": "MERGE". You cannot rename a system target during a merge. The response is {"message": "...", "merged_ledger": {...}}. Merges are irreversible.

Bulk Update and AI Helpers

  • POST /api/v1/ledgers/bulk-update applies many updates in one call ({"updates": [{"id": "...", "status": "inactive"}, …]}) and returns {"updated": N}. Each update is applied like PUT; a row that fails is skipped and not counted, so compare updated with what you sent.
  • POST /api/v1/ledgers/suggest-cleanup (no body) returns AI suggestions, each with a type (merge, cleanup, reclassify or unused), affected_ledger_ids and, for merges, suggested_target_ledger_id to pass to /ledgers/merge. It is rate limited (10 requests per 5 minutes per user) and counts against the monthly AI quota.
  • POST /api/v1/ledgers/suggest-cash-flow (no body, deterministic) returns suggested_cfs_class and suggested_cash_flow_section for each active account next to its current values.
  • POST /api/v1/ledgers/apply-coa upserts a whole chart of accounts from {"ledgers": [{"name", "type", "sub_type", "sort_code", ...}]}. sort_code is a digits-only string and must be unique in the template; optional per row: debit_credit, report_cash_flow, editable, description, financial_account_type. Rows are matched to existing ledgers by sort code: new codes are created, matches updated, and custom ledgers missing from the template are set inactive. System, required and bank-linked ledgers are skipped. A bad row is reported in failed and does not stop the rest; the response has created, updated, skipped, deactivated, failed and total.

Delete a Ledger

bash
curl -X DELETE "https://api.ondayzero.com/api/v1/ledgers/{ledger_id}" \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID"

Deletion returns 400 for protected accounts (system accounts such as AR and AP, required accounts, and bank-linked ledgers) and 409 Conflict if the ledger still has journal entry lines — move or delete those first, merge the ledger into another, or mark it inactive instead.

To remove a ledger and everything posted to it, preview the blast radius with GET /api/v1/ledgers/{ledger_id}/cascade-preview, then DELETE /api/v1/ledgers/{ledger_id}/cascade. The preview returns counts of journal entries, line entries, transactions, bill payments, reconciliations and more. The delete returns 202 with a workflow_id (or 200 if the ledger is already gone); poll GET /api/v1/ledgers/deletion-status/{workflow_id} for completed, status, success and deleted_count. This is destructive and cannot be undone.

Errors

Status code Cause
400 VALIDATION_066 Custom create without sort_code (the other required custom fields have their own VALIDATION_* codes)
400 VALIDATION_130 / VALIDATION_216 Renaming or changing accounting properties of a system ledger
400 VALIDATION_131 Deleting, or merging away, a system, required or bank-linked ledger
400 VALIDATION_217 Updating anything but status on an inactive ledger
404 NOT_FOUND_014 Ledger not found in this business
409 CONFLICT_015 Another active ledger already has this name (create, rename, reactivate)
409 CONFLICT_013 Deleting a ledger that still has journal entry lines