Method

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's import-append-text slot, 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, as NAMESPACE::MNEMONIC (QIF securities); none for CSV.
  • prices (PricesChanged, required): Prices recorded.
  • imbalanceSplits (array of ImbalanceSplitWire, required): Every Imbalance-<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.