import.apply
Apply a held Import proposal with the caller's changes, as one Mutation.
Applies a held Import proposal as one change, with the changes you make to it, or does nothing. It is destructive: it adds transactions, accounts, prices, documents or customers to the book.
changes alter a record by its index: a new action (add, clear, update, skip; clear and update need a
match, the split GUID of one of the transaction's matches), and for an add the account that balances it and its
amount when that account is in another commodity. The account you choose is learned into the import map, so the next
file is proposed with it. Records you do not name keep the proposal's choice. Errors in the proposal stop the apply
unless you pass skipErrors, which leaves those rows out.
The result lists what was added, cleared, updated and skipped, the accounts and commodities created, every
Imbalance-<CUR> split made, and what was learned. A proposal stays held after a failed apply, so you can fix it and
try again. If the book has changed since the preview, the proposal is refused with conflict: preview again.
Examples
A proposal that is not held, because it was applied, discarded, pushed out or made before the book was opened, is refused:
Example: with a new, empty book open as book.gnucash.
JSON-RPC
Request:
{"jsonrpc":"2.0","id":1,"method":"import.apply","params":{"proposal":"imp-999999"}}
Response:
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": 2000,
"message": "…",
"data": {
"kind": "importProposal",
"id": "imp-999999",
"help": "error/not-found"
}
}
}
Command line
red-ale exec --book book.gnucash import.apply '{"proposal":"imp-999999"}'
It fails with exit status 2, printing on standard error:
{
"error": {
"code": 2000,
"message": "…",
"data": {
"kind": "importProposal",
"id": "imp-999999",
"help": "error/not-found"
}
}
}
MCP tool call
Tool call:
{"name":"import.apply","arguments":{"proposal":"imp-999999"}}
Result:
{
"isError": true,
"structuredContent": {
"error": {
"code": 2000,
"name": "not-found",
"message": "…",
"data": {
"kind": "importProposal",
"id": "imp-999999",
"help": "error/not-found"
}
}
}
}
A bank statement previewed and applied, giving Food as the account that balances Coffee. Proposal IDs count up from
imp-1 in each server. Lunch, given no account, is balanced against Imbalance-USD:
Example: with a new, empty book open as book.gnucash.
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":"Food","type":"EXPENSE","commodity":"USD"}}
Response:
{
"jsonrpc": "2.0",
"id": 2,
"result": "…"
}
Request:
{"jsonrpc":"2.0","id":3,"method":"import.preview","params":{"format":"csvTransactions","files":[{"name":"bank.csv","text":"Date,Description,Amount\n2024-06-03,Coffee,-3.50\n2024-06-04,Lunch,-12.00\n"}],"layout":{"format":"csv","separators":",","skipStartLines":1,"dateFormat":"y-m-d","currencyFormat":"period","encoding":"utf-8","baseAccount":"Checking","columns":["Date","Description","Amount"]}}}
Response:
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"id": "imp-1",
"…": "…"
}
}
Request:
{"jsonrpc":"2.0","id":4,"method":"import.apply","params":{"proposal":"imp-1","changes":[{"index":0,"account":"Food"}]}}
Response:
{
"jsonrpc": "2.0",
"id": 4,
"result": {
"added": [
{
"index": 0,
"transaction": "…"
},
{
"index": 1,
"transaction": "…"
}
],
"skipped": [],
"imbalanceSplits": [
{
"index": 1,
"account": "…",
"value": {
"num": "1200",
"denom": "100"
},
"…": "…"
}
],
"learned": "…",
"warnings": "…",
"…": "…"
}
}
Command line
red-ale exec --book book.gnucash --script - <<'EOF'
account.create {"name":"Checking","type":"BANK","commodity":"USD"}
account.create {"name":"Food","type":"EXPENSE","commodity":"USD"}
import.preview {"format":"csvTransactions","files":[{"name":"bank.csv","text":"Date,Description,Amount\n2024-06-03,Coffee,-3.50\n2024-06-04,Lunch,-12.00\n"}],"layout":{"format":"csv","separators":",","skipStartLines":1,"dateFormat":"y-m-d","currencyFormat":"period","encoding":"utf-8","baseAccount":"Checking","columns":["Date","Description","Amount"]}}
import.apply {"proposal":"imp-1","changes":[{"index":0,"account":"Food"}]}
EOF
It prints:
[
"…",
"…",
{
"id": "imp-1",
"…": "…"
},
{
"added": [
{
"index": 0,
"transaction": "…"
},
{
"index": 1,
"transaction": "…"
}
],
"skipped": [],
"imbalanceSplits": [
{
"index": 1,
"account": "…",
"value": {
"num": "1200",
"denom": "100"
},
"…": "…"
}
],
"learned": "…",
"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":"Food","type":"EXPENSE","commodity":"USD"}}
Result:
{
"content": [
{
"type": "text",
"text": "\"…\""
}
]
}
Tool call:
{"name":"import.preview","arguments":{"format":"csvTransactions","files":[{"name":"bank.csv","text":"Date,Description,Amount\n2024-06-03,Coffee,-3.50\n2024-06-04,Lunch,-12.00\n"}],"layout":{"format":"csv","separators":",","skipStartLines":1,"dateFormat":"y-m-d","currencyFormat":"period","encoding":"utf-8","baseAccount":"Checking","columns":["Date","Description","Amount"]}}}
Result:
{
"structuredContent": {
"id": "imp-1",
"…": "…"
}
}
Tool call:
{"name":"import.apply","arguments":{"proposal":"imp-1","changes":[{"index":0,"account":"Food"}]}}
Result:
{
"structuredContent": {
"added": [
{
"index": 0,
"transaction": "…"
},
{
"index": 1,
"transaction": "…"
}
],
"skipped": [],
"imbalanceSplits": [
{
"index": 1,
"account": "…",
"value": {
"num": "1200",
"denom": "100"
},
"…": "…"
}
],
"learned": "…",
"warnings": "…",
"…": "…"
}
}
Effect: destructive, on the Book.
Params
The params of import.apply.
proposal(string, required): The proposal's ID.changes(array of ChangeParam): The caller's changes, by index.skipErrors(boolean): Apply although the proposal lists errors, leaving those rows out (GnuCash's "Skip errors").appendText(boolean or null): For update: append the imported description and notes instead of replacing them. Default: the import account'simport-append-textslot, as GnuCash's checkbox defaults.
Result
The result of import.apply.
added(array of IndexedTransaction, required): Transactions added.cleared(array of IndexedTransaction, required): Existing transactions cleared.updated(array of IndexedTransaction, required): Existing transactions updated and cleared.skipped(array of integer (uint), required): Indexes skipped: transactions, or a CSV account or price import's rows.accounts(AccountsChanged, required): Accounts created and changed.commodities(array of string, required): Commodities created, asNAMESPACE::MNEMONIC(QIF securities); none for CSV.prices(PricesChanged, required): Prices recorded.imbalanceSplits(array of ImbalanceSplitWire, required): EveryImbalance-<CUR>split made.learned(LearnedWire, required): Import map entries written.warnings(array of WarningWire, required): Every Imbalance split again, every transaction applied read-only by date, and the matcher's own warnings.documents(RecordsChanged or null):csvDocuments: the documents created, updated (entries appended) and posted.owners(RecordsChanged or null):csvOwners: the customers or vendors created and updated.