Schedule a transaction
Set up a transaction that repeats (rent, a salary, a loan payment), see when it falls due, and create what is due with Since Last Run.
Some transactions come round on a rhythm: rent on the first of the month, a salary every fortnight, a loan payment. A scheduled transaction keeps a template of such a transaction and a schedule, and creates the real transactions when they fall due. Nothing happens by itself in a headless program: you ask what is due, look at it, and apply it, usually when you open the book. GnuCash calls this Since Last Run.
Steps
- Start from an existing transaction. If you have already posted the first rent payment, call
scheduledTransaction.fromTransaction with its GUID and a
frequency(monthly,weekly, and so on). It returns the scheduled transaction it would make from it, to check or adjust. Or build one from scratch with scheduledTransaction.create: aname, astartDate, aschedule(a list of recurrences:{mult: 1, periodType: "month"}), and template transactions whose splits take adebitFormulaorcreditFormula. - Use a formula, not just a number, when the amount varies. A formula can use variables, which you supply when you apply the proposal.
- Preview the dates with scheduledTransaction.occurrences, for an existing schedule or for one you describe.
- Ask what is due with scheduledTransaction.sinceLastRun. It lists every
occurrence between the last one created and today with a state (
toCreate,reminderand so on) and a proposalid. It changes nothing. - Apply it with scheduledTransaction.apply and that
id. Inchoicesyou can change one instance's state (topostponedorignored) or give a variable its value. All instances are checked first, so if one fails none is created. Or drop the proposal with scheduledTransaction.discard. - For loans, scheduledTransaction.loan is GnuCash's Loan assistant: give the
loan account, principal, annual
rate,lengthand the accounts to pay from and charge interest to, and it makes the scheduled transaction with the payment formulas. - List them with scheduledTransaction.list.
Example
Example: with a new, empty book open as book.gnucash, at 2024-07-01T12:00:00Z.
JSON-RPC
Request:
{"jsonrpc":"2.0","id":1,"method":"account.create","params":{"name":"Checking","type":"BANK","commodity":"USD"}}
Response:
{
"jsonrpc": "2.0",
"id": 1,
"result": "…"
}
Request:
{"jsonrpc":"2.0","id":2,"method":"account.create","params":{"name":"Rent","type":"EXPENSE","commodity":"USD"}}
Response:
{
"jsonrpc": "2.0",
"id": 2,
"result": "…"
}
Request:
{"jsonrpc":"2.0","id":3,"method":"scheduledTransaction.create","params":{"name":"Monthly rent","startDate":"2024-05-01","schedule":[{"mult":1,"periodType":"month"}],"templateTransactions":[{"description":"Rent","splits":[{"account":"Rent","debitFormula":"750"},{"account":"Checking","creditFormula":"750"}]}]}}
Response:
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"name": "Monthly rent",
"enabled": true,
"nextOccurrence": "2024-05-01",
"…": "…"
}
}
Request:
{"jsonrpc":"2.0","id":4,"method":"scheduledTransaction.sinceLastRun","params":{}}
Response:
{
"jsonrpc": "2.0",
"id": 4,
"result": {
"id": "slr-1",
"today": "2024-07-01",
"summary": {
"toCreate": 3,
"reminders": 0,
"postponed": 0,
"errors": 0,
"…": "…"
},
"…": "…"
}
}
Request:
{"jsonrpc":"2.0","id":5,"method":"scheduledTransaction.apply","params":{"proposal":"slr-1"}}
Response:
{
"jsonrpc": "2.0",
"id": 5,
"result": {
"created": [
{
"index": 0,
"date": "2024-05-01",
"transactions": [
"…"
],
"…": "…"
},
{
"index": 1,
"date": "2024-06-01",
"transactions": [
"…"
],
"…": "…"
},
{
"index": 2,
"date": "2024-07-01",
"transactions": [
"…"
],
"…": "…"
}
],
"ignored": [],
"postponed": [],
"reminders": [],
"schedules": [
"…"
],
"imbalanceSplits": [],
"warnings": []
}
}
Command line
red-ale exec --book book.gnucash --script - <<'EOF'
account.create {"name":"Checking","type":"BANK","commodity":"USD"}
account.create {"name":"Rent","type":"EXPENSE","commodity":"USD"}
scheduledTransaction.create {"name":"Monthly rent","startDate":"2024-05-01","schedule":[{"mult":1,"periodType":"month"}],"templateTransactions":[{"description":"Rent","splits":[{"account":"Rent","debitFormula":"750"},{"account":"Checking","creditFormula":"750"}]}]}
scheduledTransaction.sinceLastRun {}
scheduledTransaction.apply {"proposal":"slr-1"}
EOF
It prints:
[
"…",
"…",
{
"name": "Monthly rent",
"enabled": true,
"nextOccurrence": "2024-05-01",
"…": "…"
},
{
"id": "slr-1",
"today": "2024-07-01",
"summary": {
"toCreate": 3,
"reminders": 0,
"postponed": 0,
"errors": 0,
"…": "…"
},
"…": "…"
},
{
"created": [
{
"index": 0,
"date": "2024-05-01",
"transactions": [
"…"
],
"…": "…"
},
{
"index": 1,
"date": "2024-06-01",
"transactions": [
"…"
],
"…": "…"
},
{
"index": 2,
"date": "2024-07-01",
"transactions": [
"…"
],
"…": "…"
}
],
"ignored": [],
"postponed": [],
"reminders": [],
"schedules": [
"…"
],
"imbalanceSplits": [],
"warnings": []
}
]
MCP tool call
Tool call:
{"name":"account.create","arguments":{"name":"Checking","type":"BANK","commodity":"USD"}}
Result:
{
"content": [
{
"type": "text",
"text": "\"…\""
}
]
}
Tool call:
{"name":"account.create","arguments":{"name":"Rent","type":"EXPENSE","commodity":"USD"}}
Result:
{
"content": [
{
"type": "text",
"text": "\"…\""
}
]
}
Tool call:
{"name":"scheduledTransaction.create","arguments":{"name":"Monthly rent","startDate":"2024-05-01","schedule":[{"mult":1,"periodType":"month"}],"templateTransactions":[{"description":"Rent","splits":[{"account":"Rent","debitFormula":"750"},{"account":"Checking","creditFormula":"750"}]}]}}
Result:
{
"structuredContent": {
"name": "Monthly rent",
"enabled": true,
"nextOccurrence": "2024-05-01",
"…": "…"
}
}
Tool call:
{"name":"scheduledTransaction.sinceLastRun","arguments":{}}
Result:
{
"structuredContent": {
"id": "slr-1",
"today": "2024-07-01",
"summary": {
"toCreate": 3,
"reminders": 0,
"postponed": 0,
"errors": 0,
"…": "…"
},
"…": "…"
}
}
Tool call:
{"name":"scheduledTransaction.apply","arguments":{"proposal":"slr-1"}}
Result:
{
"structuredContent": {
"created": [
{
"index": 0,
"date": "2024-05-01",
"transactions": [
"…"
],
"…": "…"
},
{
"index": 1,
"date": "2024-06-01",
"transactions": [
"…"
],
"…": "…"
},
{
"index": 2,
"date": "2024-07-01",
"transactions": [
"…"
],
"…": "…"
}
],
"ignored": [],
"postponed": [],
"reminders": [],
"schedules": [
"…"
],
"imbalanceSplits": [],
"warnings": []
}
}
The proposal's id is the one sinceLastRun gave; it counts up from slr-1 in each server process. Applying creates the
three rent transactions, 750.00 each, and moves the schedule on. A second scheduledTransaction.sinceLastRun then finds
nothing to create until the next occurrence, 1 August.