Guide

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

  1. 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: a name, a startDate, a schedule (a list of recurrences: {mult: 1, periodType: "month"}), and template transactions whose splits take a debitFormula or creditFormula.
  2. Use a formula, not just a number, when the amount varies. A formula can use variables, which you supply when you apply the proposal.
  3. Preview the dates with scheduledTransaction.occurrences, for an existing schedule or for one you describe.
  4. Ask what is due with scheduledTransaction.sinceLastRun. It lists every occurrence between the last one created and today with a state (toCreate, reminder and so on) and a proposal id. It changes nothing.
  5. Apply it with scheduledTransaction.apply and that id. In choices you can change one instance's state (to postponed or ignored) 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.
  6. For loans, scheduledTransaction.loan is GnuCash's Loan assistant: give the loan account, principal, annual rate, length and the accounts to pay from and charge interest to, and it makes the scheduled transaction with the payment formulas.
  7. 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.