Entries

An entry is one account's share of a transaction: a debit or a credit, never both, never negative.

Read-only. There is no POST. Entries are created only as part of a transaction, because an entry writable on its own could leave a transaction unbalanced — and the single write path exists precisely so that cannot happen. See transactions.

When to use this instead of transactions

/api/v1/transactions answers what happened. This answers what landed on this account, in this period, under this cost centre.

For a question like "every entry against Rent Expense in Q1", going through the transactions endpoint means fetching whole transactions to look at one line of each and filtering client-side — most of the ledger over the wire to answer a question about a fraction of it.


GET /api/v1/entries

ParamNotes
accountAccount id
account_subtreeA group id — every postable account beneath it
account_typeasset, liability, equity, income or expense
date_from, date_toInclusive, on the parent's accounting date
statusParent status. Defaults to posted; all opts out
typeParent transaction type
transactionEntries of one transaction
dimension.<key>e.g. dimension.cost_centre=Mumbai
has_dimensionfalse finds unallocated entries, true allocated ones
page, limitDefault 100 per page, max 500

has_dimension cannot be combined with a dimension.<key> filter — the key filter already implies the entry has that dimension, so the combination is either redundant or impossible.

The posted default matters. An entry on a draft is not part of the books. Including one silently would put a figure into an analysis that no report would agree with.

account_subtree and account_type are how a report figure is drilled into. A group's figure is the sum of its descendants and a section total the sum of a type, so neither can be expressed as a single account id — without them the most interesting figures in a statement would be the only ones you could not trace back to entries.

Response

Each entry carries its parent's date, narration, type, status and source alongside its own amounts — an entry without them is a number with no context, and every caller would otherwise make the same follow-up request.

{
  "data": [
    {
      "id": "e1f2g3h4i5j6",
      "transaction": "t1u2v3w4x5y6",
      "account": "a1b2c3d4e5f6",
      "debit": 3000000,
      "credit": 0,
      "memo": null,
      "dimensions": { "cost_centre": "Mumbai" },
      "date": "2026-08-05",
      "narration": "Rent paid — Aug 2026",
      "transaction_type": "vendor_paid",
      "transaction_status": "posted",
      "source": "sap",
      "source_ref": "4900001234"
    }
  ],
  "page_context": { "count": 1, "page": 1, "per_page": 100, "total": 1, "has_more": false }
}

Useful queries

An account ledger for a period

curl "…/api/v1/entries?account=a1b2c3d4e5f6&date_from=2026-04-01&date_to=2026-06-30&sort_order=ASC" \
  -H "api-key: $KEY" -H "api-secret: $SECRET"

Everything under one cost centre

curl "…/api/v1/entries?dimension.cost_centre=Mumbai&date_from=2026-04-01&date_to=2027-03-31"

What is missing a cost centre — run this before trusting any dimension-filtered total, since unallocated entries are exactly what such a report leaves out:

curl "…/api/v1/entries?has_dimension=false&date_from=2026-04-01&date_to=2027-03-31"

Reading the amounts

Every entry has exactly one of debit or credit non-zero, both in minor units. There are no negative amounts anywhere in the ledger.

To turn entries into a balance a person would recognise, subtract in the direction the account's type normally sits:

  • debit-normal (asset, expense): sum(debit) - sum(credit)
  • credit-normal (liability, equity, income): sum(credit) - sum(debit)

The normal_balance field on accounts tells you which applies, so this never has to be guessed from the type.