A bill is what the business owes a supplier. It lives in Business Made Books › Payable (/books/ap, a bill opens with ?openId=<sk>). For the same screen from the Business Made side, see Receivable and payable. The endpoints are under business-made/bills and business-made/vendors (appengine business-made/controllers/bill.controller.ts, services/bill.service.ts), called with call_appengine.
draft ──approve──→ approved ──pay part──→ partially_paid ──pay rest──→ paid
│ │
└──void──→ voided └──void (no payments)──→ voided (the posting is reversed)The screen shows these as Draft, Approved, Partly paid, Paid and Void. A bill can also read Open, Waiting for approval (awaiting_approval) or Held for review (disputed). Each of those is approved like a draft.
Nothing is in the books until Approve. Approving is when the bill becomes owed. The books get Dr each line's account and Cr Accounts Payable (2000), dated the bill date (buildBillEntry, ledger/posting-rules.ts). If the org has no 2000 account yet, it's added the first time (tested).
Bills for stock bought for sale don't start here. They come from receiving the goods; see Stock levels. An inventory bill entered by hand is refused at approval with INVENTORY_BILL_NEEDS_DELIVERY.
Ask first
- Who is the vendor? An existing one, or a new name.
- The bill itself: bill #, bill date, due date, and each line's amount with what it was for (rent, utilities, repairs).
- Which account each line goes to. Ask when you can't tell. Don't guess.
- Which location? One business location, or the whole business.
- Paid already? How much, on what date, by what method, and from which bank account.
Steps
1. Books › Payable: the vendor
In the bill drawer, pick the vendor, or type a new name. A typed name becomes a vendor (bm_vendor) when the bill is saved or approved.
The vendor record opens in Storefront › Inventory, on the purchase orders tab (/storefront/inventory?tab=purchase-orders&vendor=<id>). Its Default account for bills (defaultExpenseAccount) is put on every bill line that has no account. A produce supplier's bills land in Cost of goods sold without picking it each time.
Hands on: look the vendor up first: GET business-made/vendors or repo_find on bm_vendor. Create one with POST business-made/vendors { name, defaultExpenseAccount? } only when none matches.
Check: the vendor's defaultExpenseAccount, when set, is a real account in Books › Chart of accounts.
2. Books › Payable: New bill
New bill opens a drawer with these fields:
- Vendor
- Bill # *
- Bill date
- Due date (30 days out by default)
- Location ("Whole business (no location)" or a business location)
- Lines, each with an account, a description and an amount
Save keeps it as Draft. The Status field can't be typed in. Approve, Record payment and Void change it.
Hands on: create it the way the screen does, with repo_create on bm_bill:
{ "billNumber": "INV-2207", "vendorId": "<bm_vendor sk>", "vendorName": "Acme Supply",
"billDate": "2026-10-14", "dueDate": "2026-11-13", "businessLocationId": "<location, or leave out>",
"lineItems": [ { "ledgerAccountCode": "6100", "description": "October rent", "amount": 1200 } ],
"total": 1200, "status": "draft" }POST business-made/bills does the same, but it refuses a bill without a location: "vendorId, businessLocationId, billDate, dueDate required" (tested). Use it only for a bill at one location.
Check: the bill reads Draft in Books › Payable with the right total.
A line with no account goes to a fallback, without a word. At approval, a line without an account takes the vendor's Default account for bills. If the vendor has none, it takes the account map's processing-fees account, 6500 (buildBillEntry, fillVendorDefault 478). Give every line its account before you approve.
3. Books › Payable: Approve
Open the bill and press Approve (POST business-made/bills/<sk>/approve). The screen saves what's in the drawer first, so what is approved is what's on screen. Before sending, it needs a vendor, a bill # and an amount above 0.
Stop: approving posts the expense and the amount owed. Show the vendor, the bill #, the date, each line's account and amount, and the total. Wait for yes.
| Answer | Why |
|---|---|
BILL_NEEDS_VENDOR | "Choose a vendor before approving bill <#>." Tested. |
| "Cannot approve bill in status paid" | Already paid or void. Tested. |
INVENTORY_BILL_NEEDS_DELIVERY | An inventory bill that didn't come from a delivery. |
REORDER_ALREADY_RECEIVED | The goods were received on an intake and are owed on that intake's bill. |
VENDOR_CREDIT | It's a vendor credit, not a bill (step 5). |
Check: Books › Journal has an entry "Bill <#>" with source bill. Its debits are the line accounts and its credit is 2000 for the total. Tested: lines of 50 on an expense account and 30 with no account posted Dr 80 to the vendor's default account and Cr 80 to 2000.
Approve can say Approved with nothing in the books. If posting fails, the bill still reads Approved. The error goes only to the server log, and no retry is queued (postToLedger, bill.service.ts 199–209). A bill with a total of 0 posts nothing (203). After every approval, check that the journal entry is there.
4. Books › Payable: Record payment
Record payment asks for:
- Amount, which defaults to what's owed
- Paid on
- Method: Check, Bank transfer, Card or Cash
- Reference
- Paid from: the default cash account, or a bank account
Then Save payment. The call is POST business-made/bills/<sk>/pay { amount, paymentDate, method: "check"|"ach"|"card"|"cash", reference?, bankAccountId?, notes? } (recordPayment, 260).
The books get Dr 2000 and Cr the paid-from bank's ledger account, or 1000 when none is picked. The bill moves to Partly paid or Paid. Paying a draft approves and posts it first, then pays it (tested: both entries posted).
Stop: a payment records money that left the bank. Record one only when it really was paid, with the date and the account it came from. Show them, and wait for yes. This records the payment in the books only. Nothing is sent to the vendor.
| Answer | Why |
|---|---|
| "Payment 60 exceeds remaining balance 50" | More than is owed. Tested. |
| "Cannot pay voided bill" |
Check: tested, a bill of 80 paid 30 read Partly paid, and the entry credited the bank's ledger account. Paying 60 was refused. Paying 50 read Paid. The payment shows on the bank's line when you reconcile; see Reconcile the bank.
5. Books › Payable: vendor credits
A vendor credit (kind: "credit") comes from goods sent back to the supplier. It's not approved or paid. When the vendor has open credit, an approved or partly paid bill shows "POST business-made/bills/<sk>/apply-credits, optional { creditIds }). What's owed goes down, oldest credit first, and no cash moves. GET business-made/bills/vendor-credits?vendorId= lists a vendor's open credits.
Stop: using credits changes what's owed. Wait for yes.
Check: the bill's owed amount went down by the credit used.
6. Books › Payable: Void bill
Void bill (POST business-made/bills/<sk>/void { reason }) marks it Void (void, 222):
- A draft voids with nothing posted.
- An approved bill's entry is reversed, dated today: "Reversal of <entry #>: Bill voided:
" (tested). - A bill with any payment is refused: "This bill has payments against it. Record a vendor refund or credit instead of voiding it." (tested).
Stop: show the bill and the reason, and wait for yes.
Check: the bill reads Void. For an approved bill, its reversal is in the Journal.
A bill's entries can't be reversed in Books › Journal. The Journal says "Correct it at the bill". Void the bill, or change it with a vendor credit.
What we owe
GET business-made/bills/aging(optionalbusinessLocationId) buckets what's owed by how overdue it is.GET business-made/billslists bills, andGET business-made/bills/payments?billId=lists a bill's payments.- The Period close Payables review reads the open bills at the month's end; see Month-end close.
When it's done
- The bill reads Approved, Partly paid or Paid, and its entry is in the Journal (source
bill). - Each payment's entry is there too (source
bill_payment), crediting the bank it came from. - Or the bill reads Void, with its reversal if it had been approved.
What it can't do yet
- A failed approval posting isn't flagged (step 3).
POST business-made/billsneeds a location. A whole-business bill has to be saved as a record, as the screen does.- Paying doesn't send money. No check printing and no bank transfer. It's a record only.
- A payment's record has no bill number.
billNumberonbm_bill_paymentis read from a field bills don't have (bill.service.ts283).
Don'ts
- Don't approve, pay, use credits or void without a yes on that bill.
- Don't approve with a line that has no account.
- Don't record a payment that hasn't been made.
- Don't delete an approved or paid bill (
DELETE business-made/bills/<sk>orrepo_delete). Its entries stay in the books with no bill behind them. Void it. - Don't enter a stock delivery as a bill here. Receive it in Inventory.