Files
grist-accounting/references/templates.md
Bill Ballou fdb813d647 Add bank reconciliation workflow and templates
New capability for importing bank transactions (Schwab JSON), matching
against existing ledger entries, creating missing transactions, and
reconciling balances. Includes two new Grist tables (Reconciliations,
BankRules), two bank-import templates, and reference documentation.
2026-02-19 20:26:48 -05:00

5.7 KiB

Transaction Templates

JSON templates for common accounting scenarios. Templates contain only writable fields to prevent errors when creating records.

Template Selection Guide

Scenario Template
Vendor invoice paid by business credit card bill-paid-credit-card.json
Vendor invoice paid by owner personally bill-paid-owner.json
Vendor invoice paid from checking account bill-paid-checking.json
Vendor invoice received but not yet paid bill-unpaid.json
Recording payment for previously entered bill pay-existing-bill.json
Bank fees, minor expenses without invoices direct-expense.json
Bank import — unmatched deposit bank-import-deposit.json
Bank import — unmatched withdrawal bank-import-expense.json

Template Structure

Each template contains:

{
  "_meta": {
    "name": "Template name",
    "description": "When to use this template",
    "scenario": "Specific use case"
  },
  "_variables": {
    "variable_name": "description and type"
  },
  "_sequence": [
    "Ordered steps to execute"
  ],
  "records": {
    "record_name": {
      "_doc": "Step documentation",
      "_table": "Target table",
      "_operation": "add_records or update_records",
      "_requires": ["dependent variables"],
      "payload": { ... }
    }
  },
  "journal_entries": {
    "Summary of accounting entries"
  }
}

How to Use Templates

1. Select the Appropriate Template

Read the _meta.scenario to confirm you have the right template.

2. Gather Required Variables

Check _variables section for all required data:

"_variables": {
  "vendor_id": "integer - Vendor record ID",
  "bill_number": "string - Invoice/bill number from vendor",
  "date_timestamp": "integer - Unix timestamp",
  "amount": "number - Total amount including tax"
}

3. Follow the Sequence

Execute steps in order from _sequence. Each step corresponds to a record in records:

1. Create Bill record → get bill_id
2. Create BillLine → links to bill_id
3. Create Transaction → get entry_txn_id
...

4. Substitute Variables

Replace {{variable}} placeholders with actual values:

Template:

{
  "Vendor": "{{vendor_id}}",
  "BillNumber": "{{bill_number}}",
  "Amount": "{{amount}}"
}

Substituted:

{
  "Vendor": 1,
  "BillNumber": "INV-001",
  "Amount": 45.47
}

5. Track Generated IDs

Some steps require IDs from previous steps (noted in _requires):

  • bill_id → returned from Bill creation
  • entry_txn_id → returned from entry Transaction creation
  • payment_txn_id → returned from payment Transaction creation

6. Run Audit

Always verify with audit queries after completing all steps.

Key Account IDs

Quick reference for account substitution:

Account ID Code Use For
Accounts Payable 4 2000 All bill entries
Checking Account 14 1001 Checking payments
Business Credit Card 19 2101 Credit card payments
Due to Owner 22 2203 Owner paid personally
Software & Subscriptions 36 5080 SaaS, API costs
Bank & Merchant Fees 30 5020 Bank fees

Formula Fields (Read-Only)

Never include these fields in add_records payloads:

Table Formula Fields
Bills Amount, AmountPaid, AmountDue
Transactions Total, IsBalanced, Transaction_ID, Fiscal_Year

These are calculated automatically by Grist.

Example: Using bill-paid-credit-card.json

Scenario: Anthropic invoice #43I1T40F-0018 for $45.47 paid by credit card.

Variables:

vendor_id = 1 (Anthropic)
bill_number = "43I1T40F-0018"
date_timestamp = 1768435200 (Jan 14, 2026)
due_date_timestamp = 1768435200
amount = 45.47
expense_account_id = 36 (Software & Subscriptions)
line_description = "API auto-recharge credits"
vendor_name = "Anthropic"
receipt_number = "2687-3787-3014"

Execution:

  1. add_records("Bills", [payload]) → bill_id = 26
  2. add_records("BillLines", [payload]) → uses bill_id
  3. add_records("Transactions", [payload]) → entry_txn_id = 52
  4. add_records("TransactionLines", [payload]) → uses entry_txn_id
  5. update_records("Bills", [link payload]) → link Bill to Transaction
  6. add_records("Transactions", [payload]) → payment_txn_id = 53
  7. add_records("TransactionLines", [payload]) → uses payment_txn_id
  8. add_records("BillPayments", [payload]) → links bill to payment
  9. update_records("Bills", [{id: 26, fields: {Status: "Paid"}}])
  10. Upload attachments
  11. Run audit

SQL Reserved Words

When querying TransactionLines, the column Transaction is a SQL reserved word. Use get_records with filter instead of sql_query:

# Instead of (fails):
sql_query("SELECT * FROM TransactionLines WHERE Transaction = 52")

# Use:
get_records("TransactionLines", filter={"Transaction": [52]})

Available Templates

File Purpose
bill-paid-credit-card.json Invoice paid by business credit card
bill-paid-owner.json Invoice paid by owner (reimbursement)
bill-paid-checking.json Invoice paid from checking account
bill-unpaid.json Invoice recorded but not yet paid
pay-existing-bill.json Payment for previously entered bill
direct-expense.json Direct expense without vendor bill
bank-import-deposit.json Unmatched bank deposit (interest, transfer in)
bank-import-expense.json Unmatched bank withdrawal (ATM, check, ACH)