Introduces templates/ directory with pre-built record structures that only include writable fields, preventing 400 errors from formula column writes. Templates: - 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 existing open bill - direct-expense.json: Bank fees and minor expenses Also adds references/templates.md usage guide and updates SKILL.md with template references and formula column warnings.
5.4 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 |
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 creationentry_txn_id→ returned from entry Transaction creationpayment_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:
add_records("Bills", [payload])→ bill_id = 26add_records("BillLines", [payload])→ uses bill_idadd_records("Transactions", [payload])→ entry_txn_id = 52add_records("TransactionLines", [payload])→ uses entry_txn_idupdate_records("Bills", [link payload])→ link Bill to Transactionadd_records("Transactions", [payload])→ payment_txn_id = 53add_records("TransactionLines", [payload])→ uses payment_txn_idadd_records("BillPayments", [payload])→ links bill to paymentupdate_records("Bills", [{id: 26, fields: {Status: "Paid"}}])- Upload attachments
- 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 |