Skip to main content
The Chart of Accounts is the full tree of Account Groups and Ledger Accounts for an Entity. You build it one group and one account at a time, and read the whole chart in one call. This page also covers the Ledger Account endpoints under entities/:entityId/ledger/accounts, and the group chart that the Organization shares across its Entities.
Open in the app. This resource has a page in the Sintropix web app at https://app.sintropix.com/organizations/{organizationId}/settings/chart-of-accounts, where each id in braces is the same UUID as in the API route or response. Plan de cuentas opens on the group chart (Grupo). Add ?entity={entityId} for one Entity's chart. To show the movements of one account, link /{entityId}/general-ledger?selectedAccountId={accountId} instead. When you mention a record to a user, include that link. See Link to the App for the full URL grammar.

The group chart

The Organization owns one flat group chart. It is a list of Group Accounts (Cuentas de grupo), each with a code, a name, and a type. Every Ledger Account of every Entity of the Organization maps to exactly one Group Account of its own type. Because the mapping is total, the group chart adds up the books of every Entity by construction.
  • A Group Account code is unique in the Organization.
  • A Ledger Account names its Group Account in groupAccountId when you create it. You can’t create one without it.
  • To map a Ledger Account to another Group Account, PATCH it with a new groupAccountId.
  • A Ledger Account that changes type must name a Group Account of the new type in the same request.
  • You can always change a Group Account’s code and name. Its type can’t change, and it can’t be deleted, while a Ledger Account maps to it.
  • An Entity that has Ledger Accounts can’t move to another Organization.
In the app, Plan de cuentas lives in the Organization’s settings. It opens on Grupo, which lists each Group Account with the Ledger Accounts of each Entity nested under it. Pick an Entity in the switcher to see its own chart, with a Cuenta de grupo column. Pick the Organization’s own row, with its logo and name, to go back to the group chart. The group chart routes live under the Organization, not under an Entity. Read the organizationId from the Entity. They need the books permission in the Organization: books read for GET, books write for the other methods. An API key confined to one Entity can call them for that Entity’s Organization, and the listing shows only that Entity’s Ledger Accounts.

The Group Account object

GET /api/organizations/:organizationId/group-accounts

List the Group Accounts of the Organization, ordered by code. Each one carries the Ledger Accounts that map to it.
  • Path param: organizationId (UUID)
  • Success response: array of Group Account objects, each with a ledgerAccounts array
  • Status: 200
Each item of ledgerAccounts carries id, entityId, code, and name, ordered by code.

POST /api/organizations/:organizationId/group-accounts

Create a Group Account.
  • Path param: organizationId (UUID)
  • Body:
  • Success response: the created Group Account object
  • Status: 201

PATCH /api/organizations/:organizationId/group-accounts/:groupAccountId

Rename, recode, or retype a Group Account. Send at least one field. The new code and name show on every Ledger Account that maps to it.
  • Path params: organizationId (UUID), groupAccountId (UUID)
  • Body:
  • Success response: the updated Group Account object
  • Status: 200

DELETE /api/organizations/:organizationId/group-accounts/:groupAccountId

Delete a Group Account that no Ledger Account maps to. Map those accounts to another Group Account first.
  • Path params: organizationId (UUID), groupAccountId (UUID)
  • Success response: the deleted Group Account object
  • Status: 200

GET /api/entities/:entityId/ledger/chart-of-accounts

Read the full Chart of Accounts for an Entity in one document. The response contains all Account Groups and all Ledger Accounts, with derived facts computed on read.
  • Path param: entityId (UUID)
  • Success response: an object with two arrays, groups and accounts
  • Status: 200
Each group in groups carries: Each account in accounts carries:

POST /api/entities/:entityId/ledger/account-groups

Create a new Account Group within the Chart of Accounts.
  • Path param: entityId (UUID)
  • Body:
  • Success response: an object with a single group field holding the created Account Group, in the same shape as the groups rows of the Chart of Accounts
  • Status: 201

GET /api/entities/:entityId/ledger/accounts

List all Ledger Accounts for an Entity.
  • Path param: entityId (UUID)
  • Success response: array of Ledger Accounts
  • Status: 200
Each account carries the stored fields of the Chart of Accounts account row (id, entityId, organizationId, groupAccountId, groupId, code, name, description, type, tracking, subtype, cashFlowCategory, normalSide, createdAt, updatedAt) without groupAccountCode, groupAccountName, and the derived hasEntries, deleteBlockedBy, isDefaultPurchaseAccount, and defaultCashFlowCategory facts.

POST /api/entities/:entityId/ledger/accounts

Create a new Ledger Account.
  • Path param: entityId (UUID)
  • Body:
  • Success response: an object with a single account field holding the created Ledger Account with its derived facts, in the same shape as the accounts rows of the Chart of Accounts
  • Status: 201
normalSide is derived from type. Do not send it in the payload.
An unknown groupAccountId, or one of another Organization, returns 404 with GROUP_ACCOUNT_NOT_FOUND_ERROR. A Group Account of another type returns 422 with LEDGER_ACCOUNT_GROUP_ACCOUNT_TYPE_INCOMPATIBLE_ERROR; params names groupAccountId, groupAccountType, and ledgerAccountType.

PATCH /api/entities/:entityId/ledger/accounts/:accountId

Edit an existing Ledger Account. At least one field must be provided. Accounts with entries can only change type within compatible groups (for example, income to other_income, or operating_expense to cost_of_goods_sold), and can only change a stated sub-type between payable and expense_rendition_payable. See Sub-type changes on an account with entries.
  • Path params: entityId (UUID), accountId (UUID)
  • Body:
  • Success response: an object with a single account field holding the updated Ledger Account with its derived facts, in the same shape as the create response above
  • Status: 200

Sub-type changes on an account with entries

While an account has entries (hasEntries is true), its sub-type follows these rules:
  • An account with no sub-type can still take one.
  • A stated sub-type can switch between payable (Por pagar) and expense_rendition_payable (Rendición por pagar), in either direction. A payable Invoice takes either one as its control account, so the lines already posted keep their meaning.
  • Every other change of a stated sub-type, including clearing it to null, is refused with 409 and LEDGER_ACCOUNT_SUBTYPE_LOCKED_ERROR.
  • An account that a record pins keeps its sub-type even within the pair. For example, while the Expense Claim setting names an account, changing its sub-type is refused with 409 and LEDGER_ACCOUNT_FACT_PINNED_ERROR.
A switch changes only the sub-type. The account’s lines, open items, and Matches stay as they are, and its open lines stay in the payables open positions and the payable total of the home dashboard.
A switch changes the default cash flow category of an account whose cashFlowCategory is null: payable defaults to supplier_payments, and expense_rendition_payable to employee_payments. The cash flow statement then reports the account’s cash under the new category in every period, past periods included. To keep the old category, set cashFlowCategory explicitly.
Use the switch when the Entity already books renditions into a payable account, such as Rendiciones por pagar, and you want the Expense Claim setting to name it as its Rendición por pagar account:
In the app, Editar cuenta on an account with entries offers only Por pagar and Rendición por pagar when the account has one of them, and explains why. For any other sub-type, the Subtipo field is locked.

Cash Accounts

The sub-type cash marks a Cash Account: an account that holds cash, such as a bank current account or petty cash. The cash flow statement reads the entries that post to Cash Accounts, and its closing cash equals their balance. To mark an account as a Cash Account, create it or PATCH it with type: "asset", tracking: "balance", and subtype: "cash". These rules apply:
  • Only an asset account with balance tracking can take the sub-type. Another type is refused with LEDGER_ACCOUNT_SUBTYPE_TYPE_INCOMPATIBLE_ERROR, and open_item tracking with LEDGER_ACCOUNT_SUBTYPE_TRACKING_INCOMPATIBLE_ERROR.
  • A Bank Account of kind bank must map to a Cash Account.
  • While a Bank Account of kind bank maps the account, removing or changing its sub-type returns LEDGER_ACCOUNT_FACT_PINNED_ERROR. Delete the Bank Account first.

Cash flow categories

Every account can carry a cashFlowCategory. It decides where the cash flow statement shows the cash that an entry moves on the account. A category never changes a posted amount, so you can set, change, or clear it at any time. While cashFlowCategory is null, the account uses defaultCashFlowCategory, taken from its sub-type first and then from its type: The statement reports the cash of an account with no category and no default under unclassified. For example, set borrowings on a bank loan account to report its drawdowns and repayments as financing:

The Suspense Account

The sub-type suspense marks the Entity’s Suspense Account. When a bank Match pays more than the target’s Open Amount, Sintropix books the rest there until you assign it. Without a Suspense Account, a Match that leaves a rest is refused. To mark an account as the Suspense Account, create it or PATCH it with type: "asset", tracking: "open_item", and subtype: "suspense". These rules apply:
  • Only an asset account can take the sub-type.
  • An Entity has at most one Suspense Account. A second one is refused with LEDGER_ACCOUNT_SUSPENSE_ALREADY_EXISTS_ERROR.
  • An account takes the sub-type only while it has no lines. Otherwise Sintropix returns LEDGER_ACCOUNT_SUSPENSE_REQUIRES_NO_LINES_ERROR.
  • Only Match, Assign, and Unassign post to it. Manual entries, Reclassify, Scheduled Entries, Bank Account mapping, Booking Templates, and Fixed Asset Classes that name it are refused with LEDGER_ACCOUNT_SUSPENSE_RESERVED_ERROR.

Prepaid expenses and deferred revenue

The sub-types prepaid_expense and deferred_revenue mark the accounts that hold a Deferral: an Invoice line whose amount is recognized over several months instead of in the invoice month. Create the account, or PATCH an existing one, with the matching type, tracking: "balance", and the sub-type. Another type is refused with LEDGER_ACCOUNT_SUBTYPE_TYPE_INCOMPATIBLE_ERROR, and open_item tracking with LEDGER_ACCOUNT_SUBTYPE_TRACKING_INCOMPATIBLE_ERROR. In the cash flow statement, a prepaid expense account counts by default under supplier_payments and a deferred revenue account under customer_receipts.

Expense rendition payable

The sub-type expense_rendition_payable (Rendición por pagar) marks the account for what the Entity owes the people who paid its expenses with their own money. When an Expense Claim is approved, its Expense Rendition credits this account with the person as Partner. Create the account, or PATCH an existing one, with type: "liability", tracking: "open_item", and the sub-type. A payable Invoice accepts it as its control account, as it accepts a payable account. Its open lines appear in the payables open positions (Por pagar) and in the payable total of the home dashboard. In the cash flow statement, it counts by default under employee_payments.

The retained earnings account

The sub-type retained_earnings (Resultados acumulados) marks the account that carries the result of every closed Fiscal Year. Income and expense accounts open each Fiscal Year at 0, and every report adds the result of the earlier years to this account’s balance. Sintropix posts no closing entry: the account keeps its own lines, such as a dividend, and the closed results add to them when a report reads it. Create the account, or PATCH an existing one, with type: "equity", tracking: "balance", and subtype: "retained_earnings". These rules apply:
  • Only an equity account with balance tracking can take the sub-type. Another type is refused with LEDGER_ACCOUNT_SUBTYPE_TYPE_INCOMPATIBLE_ERROR, and open_item tracking with LEDGER_ACCOUNT_SUBTYPE_TRACKING_INCOMPATIBLE_ERROR.
  • An Entity has at most one retained earnings account. A second one is refused with 409 and LEDGER_ACCOUNT_RETAINED_EARNINGS_ALREADY_EXISTS_ERROR.
  • An account that already has lines can take the sub-type.
  • In the cash flow statement, it counts by default under equity_contributions.
Until the Entity has one, the balance sheet and the eight-column balance show the result of the closed years on its own line, Resultados anteriores pendientes de cierre.

DELETE /api/entities/:entityId/ledger/accounts/:accountId

Delete a Ledger Account. The account must not be referenced by any Ledger Entry Line, Bank Account, Partner default purchase account, or vendor Booking Template line; the deleteBlockedBy field of the Chart of Accounts tells you in advance which reference would block the delete.
  • Path params: entityId (UUID), accountId (UUID)
  • Success response:
  • Status: 200

Domain error codes

Status codes