Skip to content
Bkper Bkper

Subledger Bot

by Bkper

The Subledger Bot connects books in a parent–child relationship, automatically consolidating transactions from subledger books into a general ledger. Each subledger operates independently — with its own accounts, permissions, and workflows — while the parent book provides a unified view.

This is useful for dividing work between teams (e.g. one team tracking receivables, another tracking payables) or consolidating subsidiary books into a single parent book.

Why it works this way

In Bkper, every Book is a self-contained zero-sum ledger. The bot must preserve that invariant when consolidating.

  • Permanent accounts (Asset and Liability) carry cumulative balances. In a subledger, many individual child accounts (like Customer A, Customer B) can map to a single consolidated parent account (like Accounts Receivable). This is many-to-one consolidation.
  • Non-permanent accounts (Incoming and Outgoing) track period activity. Revenue and expense categories must exist on both books with the same meaning, so the bot syncs them one-to-one via child_book_id.

This is why the bot supports two different strategies: many-to-one mapping for permanent positions, and one-to-one sync for activity categories.

How it works

The bot listens for events in child books. When a transaction is posted in a child book, the bot records a corresponding transaction in the parent book, mapping child accounts to parent accounts based on configured properties.

flowchart BT subgraph child1["Subledger: Receivables"] C1A["Customer A"]:::asset C1B["Customer B"]:::asset C1R["Service A"]:::incoming end subgraph child2["Subledger: Payables"] C2S["Supplier X"]:::liability C2E["Rent"]:::outgoing end subgraph parent["General Ledger"] PAR["Accounts Receivable"]:::asset PAP["Accounts Payable"]:::liability PR["Revenue"]:::incoming PE["Expenses"]:::outgoing end child1 -- "bot consolidates" --> parent child2 -- "bot consolidates" --> parent

The bot also syncs accounts from parent to child — when you add an account to a synced group on the parent, the bot creates it on the child book automatically.

Consolidating transactions

When you post a transaction on a child book, the bot maps child accounts to parent accounts and records the transaction on the parent.

You post on the child book (Receivables):

05/03  300.00  Service B  >>  Customer A  Invoice #1042

The bot records on the parent book (General Ledger):

05/03  300.00  Service B  >>  Accounts Receivable  Invoice #1042

The bot resolves each account in four steps:

  1. Check the child account for a parent_account property
  2. Check the child account's groups for a parent_account property
  3. Check if the child account belongs to a group linked to the parent via child_book_id; if so, fall back to a parent account with the same name
  4. Fall back to a parent account with the same name

In this example, Customer A is in a group with parent_account: Accounts Receivable, so it maps to the consolidated account. Service B exists on both books (synced via child_book_id), so it maps by name.

flowchart LR subgraph child["Child Book"] CA["Customer A"]:::asset CB["Customer B"]:::asset end subgraph parent["Parent Book"] AR["Accounts Receivable"]:::asset end CA -- "parent_account" --> AR CB -- "parent_account" --> AR
# Book Amount From To Description
You Child 300.00 Service B >> Customer A Invoice #1042
Bot Parent 300.00 Service B >> Accounts Receivable Invoice #1042

The bot copies all visible properties from the child transaction to the parent, preserves the original description, and adds child_from and child_to properties so you can trace the original child accounts. When the child transaction is later updated, attached URLs and files are also synced to the parent.

Syncing accounts

For non-permanent accounts (revenue, expenses) that should exist on both parent and child books, set child_book_id on a group in the parent book. When you add an account to that group, the bot creates it on the child book.

flowchart RL subgraph parent["Parent Book"] PG["Revenue group
child_book_id: abc123"] PA["Service C"]:::incoming end subgraph child["Child Book"] CA["Service C"]:::incoming end PA -- "bot creates" --> CA

This keeps shared account structures in sync without manual duplication. The bot also syncs account updates and deletions.

What gets copied (parent → child):

  • Account or group name
  • Account type
  • Visible properties
  • Archived state
  • Group memberships (only for groups linked via child_book_id)

The child_book_id property itself is not copied to the child book.

Deletion behavior:

  • If the synced account has posted transactions on the child book, it is removed.
  • If it has no posted transactions, it is archived instead.

Configuration

Child book properties

Set on the child book's book properties to establish the parent–child relationship.

Property Description
parent_book_id The bookId of the parent book. Found in the book URL: app.bkper.com/b/#transactions:bookId=<id>. Also accepts the legacy key parent_book

All books in the subledger structure (parent and children) must be part of the same Collection so the bot has permission to read and write across both books. The bot must be installed on all participating books.

YAML
parent_book_id: agtzfmJrcGVyLWhyZBcLEgpHbHhBY291bnQY
Account & Group properties (child book)

Set on accounts or groups in the child book to define how they map to the parent.

Property Description
parent_account Name of the account on the parent book that this child account (or group of accounts) maps to. When set on a group, all accounts in that group map to the same parent account

Example — map an entire receivables group to one parent account:

YAML
# Group: Accounts Receivable (child book)
parent_account: Accounts Receivable

All transactions involving Customer A, Customer B, etc. are recorded on the parent using Accounts Receivable. If the parent account doesn't exist yet, the bot creates it automatically.

Auto-creation only works when parent_account is set on a group. When set directly on an individual child account, the bot looks up the parent account but does not create it — the parent transaction is saved as a draft if the account is missing.

When parent_account is not set, the bot looks for a parent account with the same name as the child account. If neither account can be resolved on the parent, the transaction is created as a draft for manual resolution. Draft transactions are incomplete and do not affect balances; you can review them in the parent book, fix the missing account mapping, and post them manually.

Group events on the child book are also handled. If a child group has the parent_account property, the bot treats group events as instructions to manage the corresponding parent account:

  • GROUP_CREATED on the child → creates the parent account
  • GROUP_UPDATED on the child → updates the parent account name and type
  • GROUP_DELETED on the child → deletes or archives the parent account
Transaction properties

Optional properties to control how individual transactions are consolidated.

Property Description
parent_amount Amount to record on the parent book instead of the child transaction's amount. Set to 0 to skip consolidation entirely

Example — record a different amount on parent:

YAML
parent_amount: 250.00

The child transaction keeps its original amount, but the parent gets 250.00.

Group properties (parent book)

Set on groups in the parent book to enable account syncing from parent to child.

Property Description
child_book_id The bookId of the child book to sync accounts to. When an account is added to this group on the parent, the bot creates it on the child book
YAML
# Group: Revenue (parent book)
child_book_id: agtzfmJrcGVyLWhyZBcLEgpHbHhBY291bnQY

This requires the Subledger Bot to be installed on the parent book as well.

Examples

Permanent accounts — many-to-one consolidation

The child book has individual customer accounts grouped under Accounts Receivable with parent_account: Accounts Receivable. The parent book has a single Accounts Receivable account.

# Book Amount From To
You Child 200.00 Service A >> Customer A
Bot Parent 200.00 Service A >> Accounts Receivable
You Child 300.00 Service B >> Customer A
Bot Parent 300.00 Service B >> Accounts Receivable

Result: Child book shows 500.00 receivable from Customer A. Parent book shows 500.00 in Accounts Receivable — consolidated from all customers.

The parent transactions include child_from and child_to properties for traceability.

Non-permanent accounts — shared account sync

Revenue and expense accounts should exist on both books. Set child_book_id on the parent's Revenue group.

# Book What happens
You Parent Add "Service C" to Revenue group
Bot Child Account "Service C" created automatically

Now when a transaction is posted on the child using Service C, the bot records it on the parent using the same account name.

Custom amounts with parent_amount

When the parent should reflect a different amount (e.g. after tax deductions), set parent_amount on the child transaction.

# Book Amount From To Note
You Child 1,100.00 Revenue >> Client Full amount with tax
Bot Parent 1,000.00 Revenue >> Accounts Receivable parent_amount: 1000

Set parent_amount: 0 to skip recording on the parent entirely.

Events handled

The bot responds to the following Bkper events:

Event Direction Behavior
TRANSACTION_POSTED Child → Parent Creates parent transaction. Posts it if both accounts resolve; otherwise saves as draft.
TRANSACTION_CHECKED Child → Parent If parent transaction exists: checks it (posting first if needed). If missing: creates, posts, and checks it.
TRANSACTION_UPDATED Child → Parent Only if parent transaction exists. Unchecks it first, then updates amount, accounts, description, properties, URLs, and files.
TRANSACTION_DELETED Child → Parent Unchecks if needed, then trashes the parent transaction.
TRANSACTION_RESTORED Child → Parent Untrashes the parent transaction.
ACCOUNT_CREATED Parent → Child Creates account on child (via child_book_id group).
ACCOUNT_UPDATED Parent → Child Updates account on child.
ACCOUNT_DELETED Parent → Child Deletes or archives account on child (archives if no posted transactions).
GROUP_CREATED Parent → Child Creates group on child.
GROUP_UPDATED Parent → Child Updates group on child.
GROUP_DELETED Parent → Child Deletes group on child.
GROUP_CREATED Child → Parent If child group has parent_account, creates the corresponding parent account.
GROUP_UPDATED Child → Parent If child group has parent_account, updates the corresponding parent account.
GROUP_DELETED Child → Parent If child group has parent_account, deletes or archives the corresponding parent account.

Transactions originating from the Exchange Bot are automatically skipped to avoid duplication.

Learn more