Guide

Reconcile an account

Match an account to a bank or card statement: start with the statement date and ending balance, tick the splits that appear on it, and finish when the difference is zero, or postpone.

Reconciling checks your books against the statement the bank sends. You tick every split that appears on the statement; when the ticked splits bring the account to the statement's ending balance, the difference is zero and you finish. The ticked splits become reconciled (y), and the next reconciliation starts from there. Each split is in one of three states: not cleared (n), cleared (c, ticked but not final) or reconciled (y).

red-ale keeps no reconcile window. Each call is complete in itself: you carry the statement date, the ending balance and the list of ticked splits from call to call.

Steps

  1. Start with reconcile.start: the account, the statementDate and the endingBalance from the statement. It changes nothing. It returns the splits to consider, with the cleared ones already ticked, the startingBalance (what was reconciled last time), the tickedBalance and the difference still to explain. Amounts use the account's raw sign, so for a credit card the balance is negative. Leave out the date and balance to get GnuCash's defaults, or a postponed reconciliation's.
  2. Tick splits. Try a selection with reconcile.status, passing mark: the splits you would tick, and it returns the new balances without keeping anything. To keep a split cleared between calls, set it with reconcile.setState, state c.
  3. Let red-ale find a selection with reconcile.autoClear: give the clearedBalance the ticked splits must reach, and it finds the uncleared splits that make up the difference, as GnuCash's Auto-clear does. It refuses when no subset reaches that balance (reason unreachable).
  4. Finish with reconcile.finish, passing the same statement and the list of ticked splits. It is refused unless the difference is zero. The ticked splits become reconciled; the date and balance are remembered for next time (reconcile.info).
  5. Cannot finish today? reconcile.postpone saves your ticks as cleared and remembers the statement; the next reconcile.start picks it up (resumedPostponed: true).
  6. Find the cause of a difference by checking amounts and dates against the statement, and look for a transaction entered twice or not at all. If a transaction is missing, post it (Record deposits and withdrawals) and start again.

Example

Example: with a copy of the reports/reconcile example book open as book.gnucash.

JSON-RPC

Request:

{"jsonrpc":"2.0","id":1,"method":"reconcile.start","params":{"account":"Root:Asset:Bank","statementDate":"1970-03-01","endingBalance":"21.00"}}

Response:

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "statementDate": "1970-03-01",
    "endingBalance": {
      "num": "2100",
      "denom": "100"
    },
    "resumedPostponed": false,
    "difference": {
      "num": "0",
      "denom": "100"
    },
    "ticked": [
      "d0000000000000000000000000000005"
    ],
    "…": "…"
  }
}

Request:

{"jsonrpc":"2.0","id":2,"method":"reconcile.status","params":{"account":"Root:Asset:Bank","statementDate":"1970-03-01","endingBalance":"21.00","mark":["d0000000000000000000000000000006"]}}

Response:

{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "tickedBalance": {
      "num": "1400",
      "denom": "100"
    },
    "difference": {
      "num": "1500",
      "denom": "100"
    },
    "…": "…"
  }
}

Request:

{"jsonrpc":"2.0","id":3,"method":"reconcile.finish","params":{"account":"Root:Asset:Bank","statementDate":"1970-03-01","endingBalance":"21.00","ticked":["d0000000000000000000000000000005"]}}

Response:

{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "reconciled": [
      {
        "split": "d0000000000000000000000000000005",
        "from": "c",
        "to": "y",
        "…": "…"
      }
    ],
    "difference": {
      "num": "0",
      "denom": "100"
    },
    "…": "…"
  }
}

Request:

{"jsonrpc":"2.0","id":4,"method":"reconcile.info","params":{"account":"Root:Asset:Bank"}}

Response:

{
  "jsonrpc": "2.0",
  "id": 4,
  "result": {
    "lastDate": "…",
    "postponeDate": null,
    "…": "…"
  }
}

Command line

red-ale exec --book book.gnucash --script - <<'EOF'
reconcile.start {"account":"Root:Asset:Bank","statementDate":"1970-03-01","endingBalance":"21.00"}
reconcile.status {"account":"Root:Asset:Bank","statementDate":"1970-03-01","endingBalance":"21.00","mark":["d0000000000000000000000000000006"]}
reconcile.finish {"account":"Root:Asset:Bank","statementDate":"1970-03-01","endingBalance":"21.00","ticked":["d0000000000000000000000000000005"]}
reconcile.info {"account":"Root:Asset:Bank"}
EOF

It prints:

[
  {
    "statementDate": "1970-03-01",
    "endingBalance": {
      "num": "2100",
      "denom": "100"
    },
    "resumedPostponed": false,
    "difference": {
      "num": "0",
      "denom": "100"
    },
    "ticked": [
      "d0000000000000000000000000000005"
    ],
    "…": "…"
  },
  {
    "tickedBalance": {
      "num": "1400",
      "denom": "100"
    },
    "difference": {
      "num": "1500",
      "denom": "100"
    },
    "…": "…"
  },
  {
    "reconciled": [
      {
        "split": "d0000000000000000000000000000005",
        "from": "c",
        "to": "y",
        "…": "…"
      }
    ],
    "difference": {
      "num": "0",
      "denom": "100"
    },
    "…": "…"
  },
  {
    "lastDate": "…",
    "postponeDate": null,
    "…": "…"
  }
]

MCP tool call

Tool call:

{"name":"reconcile.start","arguments":{"account":"Root:Asset:Bank","statementDate":"1970-03-01","endingBalance":"21.00"}}

Result:

{
  "structuredContent": {
    "statementDate": "1970-03-01",
    "endingBalance": {
      "num": "2100",
      "denom": "100"
    },
    "resumedPostponed": false,
    "difference": {
      "num": "0",
      "denom": "100"
    },
    "ticked": [
      "d0000000000000000000000000000005"
    ],
    "…": "…"
  }
}

Tool call:

{"name":"reconcile.status","arguments":{"account":"Root:Asset:Bank","statementDate":"1970-03-01","endingBalance":"21.00","mark":["d0000000000000000000000000000006"]}}

Result:

{
  "structuredContent": {
    "tickedBalance": {
      "num": "1400",
      "denom": "100"
    },
    "difference": {
      "num": "1500",
      "denom": "100"
    },
    "…": "…"
  }
}

Tool call:

{"name":"reconcile.finish","arguments":{"account":"Root:Asset:Bank","statementDate":"1970-03-01","endingBalance":"21.00","ticked":["d0000000000000000000000000000005"]}}

Result:

{
  "structuredContent": {
    "reconciled": [
      {
        "split": "d0000000000000000000000000000005",
        "from": "c",
        "to": "y",
        "…": "…"
      }
    ],
    "difference": {
      "num": "0",
      "denom": "100"
    },
    "…": "…"
  }
}

Tool call:

{"name":"reconcile.info","arguments":{"account":"Root:Asset:Bank"}}

Result:

{
  "structuredContent": {
    "lastDate": "…",
    "postponeDate": null,
    "…": "…"
  }
}

A statement that does not match is refused, and nothing is reconciled:

Example: with a copy of the reports/reconcile example book open as book.gnucash.

JSON-RPC

Request:

{"jsonrpc":"2.0","id":1,"method":"reconcile.finish","params":{"account":"Root:Asset:Bank","statementDate":"1970-03-01","endingBalance":"9.00","ticked":[]}}

Response:

{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": 2001,
    "message": "…",
    "data": {
      "help": "error/invalid"
    }
  }
}

Command line

red-ale exec --book book.gnucash reconcile.finish '{"account":"Root:Asset:Bank","statementDate":"1970-03-01","endingBalance":"9.00","ticked":[]}'

It fails with exit status 2, printing on standard error:

{
  "error": {
    "code": 2001,
    "message": "…",
    "data": {
      "help": "error/invalid"
    }
  }
}

MCP tool call

Tool call:

{"name":"reconcile.finish","arguments":{"account":"Root:Asset:Bank","statementDate":"1970-03-01","endingBalance":"9.00","ticked":[]}}

Result:

{
  "isError": true,
  "structuredContent": {
    "error": {
      "code": 2001,
      "name": "invalid",
      "message": "…",
      "data": {
        "help": "error/invalid"
      }
    }
  }
}