Guide

Import business data

Load customers or vendors, and invoices or bills with their lines, from CSV files in GnuCash's layouts, with a preview before anything changes.

If your customers and invoices live in a spreadsheet or another program, you can bring them in with the business imports. They work as other imports do: preview shows what would be created or updated, and apply does it. The files use GnuCash's fixed column layouts, because red-ale reads the same files GnuCash does.

Customers and vendors

  1. Make a CSV with one owner on each line and 19 fields, in this order: id, company, name, addr1 to addr4, phone, fax, email, notes, then a shipping address (shipname, shipaddr1 to shipaddr4, shipphone, shipfax, shipemail). An empty id takes the next number from the counter. An empty company takes the name. There is no header row, and a header is imported as a row.
  2. Call import.preview with format: "csvOwners", the file in files, ownerKind (customer or vendor) and the separator (comma, semicolon, ...). The proposal's owners say, per row, add or update (an owner with that id exists), and which fields would change.
  3. Apply with import.apply. A row can be skipped with changes.

There is no employee import; GnuCash has none.

Invoices and bills

  1. The customer or vendor must exist already (its id is in the file).
  2. Make a CSV with one line per entry and 22 fields: id, date_opened, owner_id, billing_id, notes, date, desc, action, account, quantity, price, disc_type, disc_how, discount, taxable, taxincluded, tax_table, date_posted, due_date, account_posted, memo_posted, accu_splits. Lines with the same id are the entries of one document. Fill date_posted and account_posted to post it as well.
  3. Call import.preview with format: "csvDocuments", documentKind (invoice or bill, the default) and dateFormat (iso for 2024-03-01). Each document in the proposal has its entries, its totals as they would be, and, if it would be posted, whether it willPost and why not if it will not. A row with an error drops its whole document, and the error is GnuCash's own message.
  4. Apply with import.apply. changes can only set a document's action to skip.

The proposal id counts up from imp-1 in each server process, as in Import transactions.

Example

Import one customer, then preview and import one invoice for them.

Example: with a new, empty book open as book.gnucash, at 2024-03-10T12:00:00Z.

JSON-RPC

Request:

{"jsonrpc":"2.0","id":1,"method":"import.preview","params":{"format":"csvOwners","files":[{"name":"customers.csv","text":"C1,Acme Ltd,Wile E,1 Main St,,,,555-1234,,billing@acme.example,,,,,,,,,\n"}],"separator":"comma"}}

Response:

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "id": "imp-1",
    "format": "csvOwners",
    "owners": [
      {
        "index": 0,
        "kind": "customer",
        "id": "C1",
        "action": "add",
        "…": "…"
      }
    ],
    "…": "…"
  }
}

Request:

{"jsonrpc":"2.0","id":2,"method":"import.apply","params":{"proposal":"imp-1"}}

Response:

{
  "jsonrpc": "2.0",
  "id": 2,
  "result": "…"
}

Request:

{"jsonrpc":"2.0","id":3,"method":"account.create","params":{"name":"Income","type":"INCOME","commodity":"USD"}}

Response:

{
  "jsonrpc": "2.0",
  "id": 3,
  "result": "…"
}

Request:

{"jsonrpc":"2.0","id":4,"method":"import.preview","params":{"format":"csvDocuments","files":[{"name":"invoices.csv","text":"B1,2024-03-01,C1,PO-1,,2024-03-01,Design,,Income,2,50,,,,,,,,,,,\n"}],"documentKind":"invoice","dateFormat":"iso","separator":"comma"}}

Response:

{
  "jsonrpc": "2.0",
  "id": 4,
  "result": {
    "id": "imp-2",
    "format": "csvDocuments",
    "documents": [
      {
        "id": "B1",
        "type": "invoice",
        "action": "add",
        "…": "…"
      }
    ],
    "…": "…"
  }
}

Request:

{"jsonrpc":"2.0","id":5,"method":"import.apply","params":{"proposal":"imp-2"}}

Response:

{
  "jsonrpc": "2.0",
  "id": 5,
  "result": "…"
}

Command line

red-ale exec --book book.gnucash --script - <<'EOF'
import.preview {"format":"csvOwners","files":[{"name":"customers.csv","text":"C1,Acme Ltd,Wile E,1 Main St,,,,555-1234,,billing@acme.example,,,,,,,,,\n"}],"separator":"comma"}
import.apply {"proposal":"imp-1"}
account.create {"name":"Income","type":"INCOME","commodity":"USD"}
import.preview {"format":"csvDocuments","files":[{"name":"invoices.csv","text":"B1,2024-03-01,C1,PO-1,,2024-03-01,Design,,Income,2,50,,,,,,,,,,,\n"}],"documentKind":"invoice","dateFormat":"iso","separator":"comma"}
import.apply {"proposal":"imp-2"}
EOF

It prints:

[
  {
    "id": "imp-1",
    "format": "csvOwners",
    "owners": [
      {
        "index": 0,
        "kind": "customer",
        "id": "C1",
        "action": "add",
        "…": "…"
      }
    ],
    "…": "…"
  },
  "…",
  "…",
  {
    "id": "imp-2",
    "format": "csvDocuments",
    "documents": [
      {
        "id": "B1",
        "type": "invoice",
        "action": "add",
        "…": "…"
      }
    ],
    "…": "…"
  },
  "…"
]

MCP tool call

Tool call:

{"name":"import.preview","arguments":{"format":"csvOwners","files":[{"name":"customers.csv","text":"C1,Acme Ltd,Wile E,1 Main St,,,,555-1234,,billing@acme.example,,,,,,,,,\n"}],"separator":"comma"}}

Result:

{
  "structuredContent": {
    "id": "imp-1",
    "format": "csvOwners",
    "owners": [
      {
        "index": 0,
        "kind": "customer",
        "id": "C1",
        "action": "add",
        "…": "…"
      }
    ],
    "…": "…"
  }
}

Tool call:

{"name":"import.apply","arguments":{"proposal":"imp-1"}}

Result:

{
  "content": [
    {
      "type": "text",
      "text": "\"…\""
    }
  ]
}

Tool call:

{"name":"account.create","arguments":{"name":"Income","type":"INCOME","commodity":"USD"}}

Result:

{
  "content": [
    {
      "type": "text",
      "text": "\"…\""
    }
  ]
}

Tool call:

{"name":"import.preview","arguments":{"format":"csvDocuments","files":[{"name":"invoices.csv","text":"B1,2024-03-01,C1,PO-1,,2024-03-01,Design,,Income,2,50,,,,,,,,,,,\n"}],"documentKind":"invoice","dateFormat":"iso","separator":"comma"}}

Result:

{
  "structuredContent": {
    "id": "imp-2",
    "format": "csvDocuments",
    "documents": [
      {
        "id": "B1",
        "type": "invoice",
        "action": "add",
        "…": "…"
      }
    ],
    "…": "…"
  }
}

Tool call:

{"name":"import.apply","arguments":{"proposal":"imp-2"}}

Result:

{
  "content": [
    {
      "type": "text",
      "text": "\"…\""
    }
  ]
}