import.preview
Read a file and propose what importing it would do: the Import proposal, held by ID. Changes nothing.
Reads a file and says what importing it would do, without changing the book. The answer, the Import proposal, is held
under an id until you apply or discard it. Nothing reaches the book
without a preview first, whatever the format.
format is one of csvTransactions (GnuCash's Import Transactions from CSV), qif (Import QIF), csvAccounts,
csvPrices, csvDocuments (Import Bills & Invoices) and csvOwners (Import Customers & Vendors). The file's content
goes in files as text, or as base64 with an encoding; there is no path to read. Only QIF takes several files.
The other params depend on the format: for CSV transactions and prices, a layout, by name or written out whole, which
says the separator, the date and number formats and what each column is.
Only CSV transactions go through GnuCash's duplicate matcher (action is add, clear, update or skip for each
transaction, with matches to choose from). A transaction that does not balance is not refused, as in GnuCash: applying
it adds an Imbalance-<CUR> split, and the proposal flags it with imbalance beforehand. Rows that cannot be imported
are listed in errors with GnuCash's own messages and are left out.
Proposal IDs (imp-1, …) count up from 1 in each server and are never reused while it runs, so a proposal made before
the book was opened, or pushed out by 16 newer ones, is gone. Applying a proposal made at an older revision of the book is refused.
Examples
A bank's statement in a CSV file, as a layout with a base account describes it. The transfer account is unknown, so each
transaction would be balanced against Imbalance-USD; give the account at import.apply.
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":"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": 2,
"result": {
"id": "…",
"format": "csvTransactions",
"summary": {
"add": 2,
"imbalanced": 2,
"errors": 0,
"…": "…"
},
"newAccounts": [
{
"name": "Imbalance-USD",
"type": "BANK",
"commodity": "CURRENCY::USD"
}
],
"transactions": [
{
"index": 0,
"description": "Coffee",
"datePosted": "2024-06-03",
"action": "add",
"splits": [
{
"accountName": "Checking",
"value": {
"num": "-350",
"denom": "100"
},
"…": "…"
}
],
"imbalance": {
"value": {
"num": "350",
"denom": "100"
},
"…": "…"
},
"…": "…"
},
{
"index": 1,
"description": "Lunch",
"…": "…"
}
],
"…": "…"
}
}
Command line
red-ale exec --book book.gnucash --script - <<'EOF'
account.create {"name":"Checking","type":"BANK","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"]}}
EOF
It prints:
[
"…",
{
"id": "…",
"format": "csvTransactions",
"summary": {
"add": 2,
"imbalanced": 2,
"errors": 0,
"…": "…"
},
"newAccounts": [
{
"name": "Imbalance-USD",
"type": "BANK",
"commodity": "CURRENCY::USD"
}
],
"transactions": [
{
"index": 0,
"description": "Coffee",
"datePosted": "2024-06-03",
"action": "add",
"splits": [
{
"accountName": "Checking",
"value": {
"num": "-350",
"denom": "100"
},
"…": "…"
}
],
"imbalance": {
"value": {
"num": "350",
"denom": "100"
},
"…": "…"
},
"…": "…"
},
{
"index": 1,
"description": "Lunch",
"…": "…"
}
],
"…": "…"
}
]
MCP tool call
Tool call:
{"name":"account.create","arguments":{"name":"Checking","type":"BANK","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": "…",
"format": "csvTransactions",
"summary": {
"add": 2,
"imbalanced": 2,
"errors": 0,
"…": "…"
},
"newAccounts": [
{
"name": "Imbalance-USD",
"type": "BANK",
"commodity": "CURRENCY::USD"
}
],
"transactions": [
{
"index": 0,
"description": "Coffee",
"datePosted": "2024-06-03",
"action": "add",
"splits": [
{
"accountName": "Checking",
"value": {
"num": "-350",
"denom": "100"
},
"…": "…"
}
],
"imbalance": {
"value": {
"num": "350",
"denom": "100"
},
"…": "…"
},
"…": "…"
},
{
"index": 1,
"description": "Lunch",
"…": "…"
}
],
"…": "…"
}
}
The base account can also be given beside the layout, which overrides the layout's own or gives one to a layout that has none, as choosing the account in GnuCash's assistant does. A saved layout can then serve several accounts:
Example: with a new, empty book open as book.gnucash.
JSON-RPC
Request:
{"jsonrpc":"2.0","id":1,"method":"account.create","params":{"name":"Savings","type":"BANK","commodity":"USD"}}
Response:
{
"jsonrpc": "2.0",
"id": 1,
"result": "…"
}
Request:
{"jsonrpc":"2.0","id":2,"method":"import.preview","params":{"format":"csvTransactions","files":[{"text":"2024-06-03,Interest,1.25\n"}],"layout":{"format":"csv","separators":",","dateFormat":"y-m-d","currencyFormat":"period","encoding":"utf-8","columns":["Date","Description","Amount"]},"baseAccount":"Savings"}}
Response:
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"transactions": [
{
"index": 0,
"description": "Interest",
"splits": [
{
"accountName": "Savings",
"value": {
"num": "125",
"denom": "100"
},
"…": "…"
}
],
"…": "…"
}
],
"…": "…"
}
}
Command line
red-ale exec --book book.gnucash --script - <<'EOF'
account.create {"name":"Savings","type":"BANK","commodity":"USD"}
import.preview {"format":"csvTransactions","files":[{"text":"2024-06-03,Interest,1.25\n"}],"layout":{"format":"csv","separators":",","dateFormat":"y-m-d","currencyFormat":"period","encoding":"utf-8","columns":["Date","Description","Amount"]},"baseAccount":"Savings"}
EOF
It prints:
[
"…",
{
"transactions": [
{
"index": 0,
"description": "Interest",
"splits": [
{
"accountName": "Savings",
"value": {
"num": "125",
"denom": "100"
},
"…": "…"
}
],
"…": "…"
}
],
"…": "…"
}
]
MCP tool call
Tool call:
{"name":"account.create","arguments":{"name":"Savings","type":"BANK","commodity":"USD"}}
Result:
{
"content": [
{
"type": "text",
"text": "\"…\""
}
]
}
Tool call:
{"name":"import.preview","arguments":{"format":"csvTransactions","files":[{"text":"2024-06-03,Interest,1.25\n"}],"layout":{"format":"csv","separators":",","dateFormat":"y-m-d","currencyFormat":"period","encoding":"utf-8","columns":["Date","Description","Amount"]},"baseAccount":"Savings"}}
Result:
{
"structuredContent": {
"transactions": [
{
"index": 0,
"description": "Interest",
"splits": [
{
"accountName": "Savings",
"value": {
"num": "125",
"denom": "100"
},
"…": "…"
}
],
"…": "…"
}
],
"…": "…"
}
}
In a book that has imported before, the Bayesian matcher proposes the account the same words and weekday went to
last time (from: "bayes"), so import.apply needs no account for them:
Example: with a copy of the synthetic/import-map example book open as book.gnucash.
JSON-RPC
Request:
{"jsonrpc":"2.0","id":1,"method":"import.preview","params":{"format":"csvTransactions","files":[{"text":"2024-06-03,Corner Grocer,-23.40\n2024-06-28,Salary ACME,2000.00\n"}],"layout":{"columns":["Date","Description","Amount"],"dateFormat":"y-m-d"},"baseAccount":"Assets:Checking"}}
Response:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"transactions": [
{
"description": "Corner Grocer",
"action": "add",
"other": {
"accountName": "Expenses:Groceries",
"from": "bayes",
"…": "…"
},
"…": "…"
},
{
"description": "Salary ACME",
"other": {
"accountName": "Income:Salary",
"from": "bayes",
"…": "…"
},
"…": "…"
}
],
"…": "…"
}
}
Command line
red-ale exec --book book.gnucash import.preview '{"format":"csvTransactions","files":[{"text":"2024-06-03,Corner Grocer,-23.40\n2024-06-28,Salary ACME,2000.00\n"}],"layout":{"columns":["Date","Description","Amount"],"dateFormat":"y-m-d"},"baseAccount":"Assets:Checking"}'
It prints:
{
"transactions": [
{
"description": "Corner Grocer",
"action": "add",
"other": {
"accountName": "Expenses:Groceries",
"from": "bayes",
"…": "…"
},
"…": "…"
},
{
"description": "Salary ACME",
"other": {
"accountName": "Income:Salary",
"from": "bayes",
"…": "…"
},
"…": "…"
}
],
"…": "…"
}
MCP tool call
Tool call:
{"name":"import.preview","arguments":{"format":"csvTransactions","files":[{"text":"2024-06-03,Corner Grocer,-23.40\n2024-06-28,Salary ACME,2000.00\n"}],"layout":{"columns":["Date","Description","Amount"],"dateFormat":"y-m-d"},"baseAccount":"Assets:Checking"}}
Result:
{
"structuredContent": {
"transactions": [
{
"description": "Corner Grocer",
"action": "add",
"other": {
"accountName": "Expenses:Groceries",
"from": "bayes",
"…": "…"
},
"…": "…"
},
{
"description": "Salary ACME",
"other": {
"accountName": "Income:Salary",
"from": "bayes",
"…": "…"
},
"…": "…"
}
],
"…": "…"
}
}
Prices from a file with a date and a rate on each line:
Example: with a new, empty book open as book.gnucash.
JSON-RPC
Request:
{"jsonrpc":"2.0","id":1,"method":"import.preview","params":{"format":"csvPrices","files":[{"text":"2024-06-28,1.0850\n"}],"layout":{"format":"csv","separators":",","skipStartLines":0,"dateFormat":"y-m-d","currencyFormat":"period","encoding":"utf-8","columns":["Date","Amount"],"fromCommodity":"CURRENCY::EUR","toCurrency":"USD"}}}
Response:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"id": "…",
"format": "csvPrices",
"summary": {
"add": 1,
"errors": 0,
"…": "…"
},
"prices": [
{
"index": 0,
"commodity": "CURRENCY::EUR",
"currency": "CURRENCY::USD",
"date": "2024-06-28",
"amount": {
"num": "10850",
"denom": "10000"
},
"action": "add",
"existing": null,
"…": "…"
}
],
"…": "…"
}
}
Command line
red-ale exec --book book.gnucash import.preview '{"format":"csvPrices","files":[{"text":"2024-06-28,1.0850\n"}],"layout":{"format":"csv","separators":",","skipStartLines":0,"dateFormat":"y-m-d","currencyFormat":"period","encoding":"utf-8","columns":["Date","Amount"],"fromCommodity":"CURRENCY::EUR","toCurrency":"USD"}}'
It prints:
{
"id": "…",
"format": "csvPrices",
"summary": {
"add": 1,
"errors": 0,
"…": "…"
},
"prices": [
{
"index": 0,
"commodity": "CURRENCY::EUR",
"currency": "CURRENCY::USD",
"date": "2024-06-28",
"amount": {
"num": "10850",
"denom": "10000"
},
"action": "add",
"existing": null,
"…": "…"
}
],
"…": "…"
}
MCP tool call
Tool call:
{"name":"import.preview","arguments":{"format":"csvPrices","files":[{"text":"2024-06-28,1.0850\n"}],"layout":{"format":"csv","separators":",","skipStartLines":0,"dateFormat":"y-m-d","currencyFormat":"period","encoding":"utf-8","columns":["Date","Amount"],"fromCommodity":"CURRENCY::EUR","toCurrency":"USD"}}}
Result:
{
"structuredContent": {
"id": "…",
"format": "csvPrices",
"summary": {
"add": 1,
"errors": 0,
"…": "…"
},
"prices": [
{
"index": 0,
"commodity": "CURRENCY::EUR",
"currency": "CURRENCY::USD",
"date": "2024-06-28",
"amount": {
"num": "10850",
"denom": "10000"
},
"action": "add",
"existing": null,
"…": "…"
}
],
"…": "…"
}
}
Accounts, in the layout GnuCash's account export writes:
Example: with a new, empty book open as book.gnucash.
JSON-RPC
Request:
{"jsonrpc":"2.0","id":1,"method":"import.preview","params":{"format":"csvAccounts","files":[{"text":"Type,Full Account Name,Account Name,Account Code,Description,Account Color,Notes,Symbol,Namespace,Hidden,Tax Info,Placeholder\nBANK,Savings,Savings,,,,,USD,CURRENCY,F,F,F\n"}]}}
Response:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"id": "…",
"format": "csvAccounts",
"newAccounts": [
{
"name": "Savings",
"type": "BANK",
"commodity": "CURRENCY::USD"
}
],
"accounts": [
{
"index": 0,
"fullName": "Savings",
"action": "add",
"…": "…"
}
],
"…": "…"
}
}
Command line
red-ale exec --book book.gnucash import.preview '{"format":"csvAccounts","files":[{"text":"Type,Full Account Name,Account Name,Account Code,Description,Account Color,Notes,Symbol,Namespace,Hidden,Tax Info,Placeholder\nBANK,Savings,Savings,,,,,USD,CURRENCY,F,F,F\n"}]}'
It prints:
{
"id": "…",
"format": "csvAccounts",
"newAccounts": [
{
"name": "Savings",
"type": "BANK",
"commodity": "CURRENCY::USD"
}
],
"accounts": [
{
"index": 0,
"fullName": "Savings",
"action": "add",
"…": "…"
}
],
"…": "…"
}
MCP tool call
Tool call:
{"name":"import.preview","arguments":{"format":"csvAccounts","files":[{"text":"Type,Full Account Name,Account Name,Account Code,Description,Account Color,Notes,Symbol,Namespace,Hidden,Tax Info,Placeholder\nBANK,Savings,Savings,,,,,USD,CURRENCY,F,F,F\n"}]}}
Result:
{
"structuredContent": {
"id": "…",
"format": "csvAccounts",
"newAccounts": [
{
"name": "Savings",
"type": "BANK",
"commodity": "CURRENCY::USD"
}
],
"accounts": [
{
"index": 0,
"fullName": "Savings",
"action": "add",
"…": "…"
}
],
"…": "…"
}
}
Effect: read.
Params
The params of import.preview: the common ones and each format's own, chosen by format.
Type: PreviewParam.
Result
The Import proposal.
id(string, required): The proposal's ID, forimport.applyandimport.discard.format(string, required): The format, as given.bookRevision(integer (uint64), required): The Book revision it was made at: the number of Mutations the session had applied.thresholdDate(Date or null): The auto read-only threshold date at the time of the preview, or null with no threshold.summary(Summary, required): Counts.ignoredLines(array of IgnoredLineWire, required): Lines the reader skipped.errors(array of RowErrorWire, required): Rows that can't be imported, with GnuCash's message. None of their records appear below.warnings(array of WarningWire, required): Things the caller should know about the whole import; each transaction's own are in itswarnings.newAccounts(array of NewAccountWire, required): Accounts the import will create, by full name, parents first.newCommodities(array of NewCommodityWire, required): Commodities the import will create (QIF securities); none for CSV.transactions(array of ImportedTransactionWire, required): One per transaction the file holds, in the order the importer builds them.csv(CsvWire or null): CSV's own state: each account name the file uses and where it resolved.documents(array of DocumentWire or null):csvDocuments: the documents, by index.owners(array of OwnerWire or null):csvOwners: the customers or vendors, by index.qif(QifWire or null): QIF's own state: the date formats to choose between, the account, category and payee maps, and the securities.accounts(array of AccountRecordWire or null):csvAccounts: one per account row, in file order.prices(array of PriceRecordWire or null):csvPrices: one per price line, in file order.