Edit, void and reverse transactions
Correct a transaction in place, void it while keeping a record, undo it with a reversing transaction, or delete it; attach a document link to a receipt.
Mistakes happen, and a bookkeeper has four tools for them, from lightest to heaviest. Which to use depends on whether you want the history to show the mistake.
| You want to | Use |
|---|---|
| Fix a typo or a wrong date or account, as if it had never been wrong | transaction.update |
| Keep the transaction in the book but count it as nothing | transaction.void |
| Cancel its effect with an equal and opposite transaction on a later date | transaction.reverse |
| Remove it altogether | transaction.delete |
Steps
- Find the transaction and its GUID with transaction.list or transaction.find (see Find transactions).
- Edit it with transaction.update: description, notes, date, num, currency and splits. The result must still balance, or the change is refused.
- Void it with transaction.void, giving a
reason. The splits' values are zeroed and the old values kept in slots, so the book remembers what was voided and why. transaction.unvoid restores it. A voided transaction is read-only until then. - Reverse it with transaction.reverse: it posts a new transaction on the
dateyou give, with every value negated. Use it when the original belongs to a closed period and must stay as it was. A transaction can be reversed once; a second call is refused as a conflict. - Delete it with transaction.delete when it should never have existed. Deleting cannot be undone, short of restoring a backup.
- Link a document. To keep a receipt with its transaction, set the book's path head once with
docLink.setPathHead (the folder your documents live in), then put a
docLinkon the transaction with transaction.update. A relative link is resolved against the path head; docLink.transactions lists the links and the full paths they resolve to.
A transaction older than the book's auto read-only threshold, may be refused; the error says why.
Example
Example: with a copy of the reports/test-data example book open as book.gnucash, at 2024-07-01T12:00:00Z.
JSON-RPC
Request:
{"jsonrpc":"2.0","id":1,"method":"transaction.update","params":{"guid":"c0000000000000000000000000000005","description":"Fuel","notes":"corrected"}}
Response:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"description": "Fuel",
"notes": "corrected",
"balanced": true,
"…": "…"
}
}
Request:
{"jsonrpc":"2.0","id":2,"method":"transaction.void","params":{"guid":"c0000000000000000000000000000000","reason":"Duplicate"}}
Response:
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"void": true,
"voidReason": "Duplicate",
"…": "…"
}
}
Request:
{"jsonrpc":"2.0","id":3,"method":"transaction.unvoid","params":{"guid":"c0000000000000000000000000000000"}}
Response:
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"void": false,
"…": "…"
}
}
Request:
{"jsonrpc":"2.0","id":4,"method":"transaction.reverse","params":{"guid":"c0000000000000000000000000000003","date":"2024-07-01"}}
Response:
{
"jsonrpc": "2.0",
"id": 4,
"result": {
"datePosted": "2024-07-01",
"splits": [
{
"accountName": "Root:Asset:Bank",
"value": {
"num": "1500",
"denom": "100"
},
"…": "…"
},
{
"accountName": "Root:Expenses",
"value": {
"num": "-1500",
"denom": "100"
},
"…": "…"
}
],
"…": "…"
}
}
Request:
{"jsonrpc":"2.0","id":5,"method":"docLink.setPathHead","params":{"pathHead":"/home/me/receipts"}}
Response:
{
"jsonrpc": "2.0",
"id": 5,
"result": "…"
}
Request:
{"jsonrpc":"2.0","id":6,"method":"transaction.update","params":{"guid":"c0000000000000000000000000000005","docLink":"2024/fuel.pdf"}}
Response:
{
"jsonrpc": "2.0",
"id": 6,
"result": "…"
}
Request:
{"jsonrpc":"2.0","id":7,"method":"docLink.transactions","params":{}}
Response:
{
"jsonrpc": "2.0",
"id": 7,
"result": {
"links": [
{
"transaction": "c0000000000000000000000000000005",
"docLink": "2024/fuel.pdf",
"relative": true,
"…": "…"
}
],
"…": "…"
}
}
Request:
{"jsonrpc":"2.0","id":8,"method":"transaction.delete","params":{"guid":"c0000000000000000000000000000006"}}
Response:
{
"jsonrpc": "2.0",
"id": 8,
"result": {}
}
Command line
red-ale exec --book book.gnucash --script - <<'EOF'
transaction.update {"guid":"c0000000000000000000000000000005","description":"Fuel","notes":"corrected"}
transaction.void {"guid":"c0000000000000000000000000000000","reason":"Duplicate"}
transaction.unvoid {"guid":"c0000000000000000000000000000000"}
transaction.reverse {"guid":"c0000000000000000000000000000003","date":"2024-07-01"}
docLink.setPathHead {"pathHead":"/home/me/receipts"}
transaction.update {"guid":"c0000000000000000000000000000005","docLink":"2024/fuel.pdf"}
docLink.transactions {}
transaction.delete {"guid":"c0000000000000000000000000000006"}
EOF
It prints:
[
{
"description": "Fuel",
"notes": "corrected",
"balanced": true,
"…": "…"
},
{
"void": true,
"voidReason": "Duplicate",
"…": "…"
},
{
"void": false,
"…": "…"
},
{
"datePosted": "2024-07-01",
"splits": [
{
"accountName": "Root:Asset:Bank",
"value": {
"num": "1500",
"denom": "100"
},
"…": "…"
},
{
"accountName": "Root:Expenses",
"value": {
"num": "-1500",
"denom": "100"
},
"…": "…"
}
],
"…": "…"
},
"…",
"…",
{
"links": [
{
"transaction": "c0000000000000000000000000000005",
"docLink": "2024/fuel.pdf",
"relative": true,
"…": "…"
}
],
"…": "…"
},
{}
]
MCP tool call
Tool call:
{"name":"transaction.update","arguments":{"guid":"c0000000000000000000000000000005","description":"Fuel","notes":"corrected"}}
Result:
{
"structuredContent": {
"description": "Fuel",
"notes": "corrected",
"balanced": true,
"…": "…"
}
}
Tool call:
{"name":"transaction.void","arguments":{"guid":"c0000000000000000000000000000000","reason":"Duplicate"}}
Result:
{
"structuredContent": {
"void": true,
"voidReason": "Duplicate",
"…": "…"
}
}
Tool call:
{"name":"transaction.unvoid","arguments":{"guid":"c0000000000000000000000000000000"}}
Result:
{
"structuredContent": {
"void": false,
"…": "…"
}
}
Tool call:
{"name":"transaction.reverse","arguments":{"guid":"c0000000000000000000000000000003","date":"2024-07-01"}}
Result:
{
"structuredContent": {
"datePosted": "2024-07-01",
"splits": [
{
"accountName": "Root:Asset:Bank",
"value": {
"num": "1500",
"denom": "100"
},
"…": "…"
},
{
"accountName": "Root:Expenses",
"value": {
"num": "-1500",
"denom": "100"
},
"…": "…"
}
],
"…": "…"
}
}
Tool call:
{"name":"docLink.setPathHead","arguments":{"pathHead":"/home/me/receipts"}}
Result:
{
"content": [
{
"type": "text",
"text": "\"…\""
}
]
}
Tool call:
{"name":"transaction.update","arguments":{"guid":"c0000000000000000000000000000005","docLink":"2024/fuel.pdf"}}
Result:
{
"content": [
{
"type": "text",
"text": "\"…\""
}
]
}
Tool call:
{"name":"docLink.transactions","arguments":{}}
Result:
{
"structuredContent": {
"links": [
{
"transaction": "c0000000000000000000000000000005",
"docLink": "2024/fuel.pdf",
"relative": true,
"…": "…"
}
],
"…": "…"
}
}
Tool call:
{"name":"transaction.delete","arguments":{"guid":"c0000000000000000000000000000006"}}
Result:
{
"structuredContent": {}
}