Accounts Receivable
Accounts Receivable is everything between "the customer owes us" and "the customer paid us". In Solid that's a small set of well-defined moving parts: customers (a kind of contact), invoices, estimates, payments applied to invoices, credit memos, the aging report, and customer statements.
This page assumes you've read General Ledger for the underlying vocabulary (debits/credits, normal balance, posting). Everything in AR is just a journal entry with extra metadata; AR-specific behavior is the metadata, not a separate ledger.
Customers
Customers are stored alongside vendors and employees in a single contacts table — the difference is the contact_type field (customer, vendor, employee, other). A contact can be more than one type if you do business that way (a customer who's also a contractor you 1099, for example).
What's stored on a customer:
| Field | Notes |
|---|---|
| Display name | What appears on invoices, statements, pickers |
| Company name + first/last name | Either / both — accommodates B2B and individuals |
| Email, phone, mobile, fax, website | Standard contact info |
| Default payment terms | Net 30, Net 15, Due on Receipt, etc. — used as the default on new invoices |
| Default income account | Suggested account on new invoice lines (override per line) |
| Currency | Per-customer currency for multi-currency books |
| Credit limit | Optional; warns at invoice creation if a new invoice would push them past |
| Active flag | Inactive customers don't appear in pickers; their history stays |
| TIN (encrypted) | Tax ID stored AES-256-encrypted at rest, with tax_id_type (SSN, EIN, SIN) — used for 1099 filing on contractors |
Adding a customer: Lists → Customers → New, or just create one inline while writing your first invoice. Every form that asks for a customer name has a + button to create one without leaving the form.
Invoicing
An invoice is a journal entry of transaction_type = 'invoice' with a customer attached. Posting an invoice produces this GL effect:
DR Accounts Receivable total
CR Income (per line, on the line's account)
CR Sales Tax Payable (if tax applied)
The income side splits per line — different services or items go to different income accounts as configured. AR is a single posting per invoice (for the total), making the AR account easy to reconcile against the customer's open balance.
Invoice fields
- Invoice number — auto-generated from the configurable sequence, or override per invoice
- Date — the transaction date; drives which fiscal period the entry posts to
- Due date — derived from the customer's payment terms or set explicitly
- Customer — required; one customer per invoice
- Line items — one or more, each with item/description, quantity, unit price, line total, optional tax
- Tax — applied per line via tax codes; tax codes can be combined into tax groups (e.g. State + County)
- Memo — optional; appears on the invoice and statement
- Reference number — optional; useful for matching to a customer PO
- Currency + exchange rate — defaults to the customer's currency; the rate is stored on the invoice so historical reports stay reproducible
- Custom fields — JSON; set up per file under settings if you need extra data per invoice
Status flow
| Status | Meaning |
|---|---|
draft | Created but not posted; doesn't affect the GL or aging |
posted | Posted to GL; appears on AR aging and the customer's open balance |
reversed | A reversing entry has been posted against it; net effect on the GL is zero |
void | Posted then voided; same as reversed but explicitly marked void on UI |
You can edit a draft freely. Once posted, edits go through the audit-trail path: post a reversing entry and a corrected new invoice, both linked. The original entry remains in the file forever — see General Ledger → Audit trail.
Sending an invoice
Solid prints to PDF for email or paper. Email delivery from inside the app is a future feature; for now, generate the PDF and send it through your own email. Customers don't need a Solid Accounting account to read or pay an invoice.
Estimates
An estimate is a proposed invoice — a quote you send to a customer before they commit. Estimates don't post to the GL. They live in their own table and produce no AR effect until they're converted to an invoice.
Status flow
| Status | Meaning |
|---|---|
draft | Being written |
sent | Delivered to the customer |
accepted | Customer agreed; ready to convert to invoice |
rejected | Customer declined |
converted | Converted to an invoice; the converted-to entry ID is stored on the estimate |
expired | Past the expiration date with no acceptance |
When you convert, the estimate stays in the file (so you can see the original quote) but is marked converted and points at the resulting invoice via converted_to_je_id. The invoice posts to the GL like any other.
Why a separate table for estimates? Because estimates aren't accounting events — they're sales-pipeline data. Mixing them into the journal entries would either pollute the GL with non-financial data or leave you without a way to ever see the original quote text after conversion. Separate tables, one-way reference at conversion time.
Receive Payment
When a customer pays, you record a Receive Payment — a journal entry of transaction_type = 'receive_payment'. The GL effect:
DR Bank (or Undeposited Funds, if you batch deposits)
CR Accounts Receivable
That clears the AR balance. The trick is that one payment can pay multiple invoices, partially pay one invoice, or pay an invoice that doesn't exist yet (a customer prepaying). Solid handles all three through the payment_applications table — each application is a row linking one payment to one invoice for one specific amount.
Applying payments
When you record a payment for a customer, Solid shows their open invoices and lets you apply portions of the payment to each:
Payment from Acme Corp 2,500.00
Apply:
Invoice 1042 (open: 1,800.00) 1,800.00 full
Invoice 1051 (open: 900.00) 700.00 partial
--------
Applied 2,500.00
Unapplied (customer credit) 0.00
If the payment is more than the open balance, the remainder shows as unapplied — a customer credit that future invoices can draw against. If less than the open balance, the corresponding invoice goes from open to partial.
Undeposited Funds
For customers who batch deposits (a stack of checks deposited at the bank as one), Receive Payment can post to Undeposited Funds (an asset account) instead of the bank account. Then a separate Make Deposit entry moves a batch from Undeposited Funds to the bank, matching the actual deposit on your statement. This keeps reconciliation clean.
For digital payments (Stripe, PayPal) where each payment lands in your account individually, posting straight to the bank account is fine and matches the statement directly.
Credit Memos
A credit memo is a journal entry of transaction_type = 'credit_memo' — a refund or write-down against a customer. The GL effect (the reverse of an invoice):
DR Income (or specific reversal account)
CR Accounts Receivable
Credit memos can be applied to existing open invoices (canceling out part of the AR) or held as a customer credit (offset against future invoices via payment_applications).
Common cases:
- Returned merchandise — credit memo against the original invoice, reducing the customer's balance
- Pricing error on a posted invoice — credit memo for the difference
- Refund check — credit memo + a Check entry to actually send the money
Voiding the original invoice is usually the wrong move because it erases history. Credit memos are the documented, audit-friendly way to undo charges.
AR Aging
The AR Aging report buckets every customer's open balance by how overdue it is. Standard four-bucket layout:
| Bucket | Meaning |
|---|---|
| Current | Not yet due |
| 1–30 days | 1–30 days past due |
| 31–60 days | 31–60 days past due |
| 61–90 days | 61–90 days past due |
| Over 90 | More than 90 days past due |
One row per customer, columns by bucket, totals at the bottom. Click any number to drill into the invoices that compose it, then drill further to the underlying transaction.
The aging report is the report you run when deciding who to chase for collections, and the report your CFO or auditor wants to see for the AR Allowance for Doubtful Accounts calculation.
Customer Statements
A statement is a customer-facing summary of their account: opening balance, every invoice and payment in the period, and the closing balance. It's what you send a customer who asks "what do I owe?" or to remind them gently that several invoices are unpaid.
Statements are generated from the customer's transaction history in the GL — there's no separate "statement" data structure. Every Receive Payment, every Invoice, every Credit Memo touching that customer in the period appears in chronological order, and the running balance is computed from the GL.
PDF export and email-friendly format are the two main delivery paths.
Multi-currency invoicing
If a customer has a non-base currency, invoices created for them default to that currency. The exchange rate is captured at the time the invoice posts and stored on the entry — so historical reports are reproducible regardless of how the rate has moved since.
When the customer pays, the paid amount in the customer's currency is what they sent; the base-currency amount on your bank deposit may differ from the base-currency amount of the invoice (because the rate moved between issue and payment). That difference posts as a realized FX gain/loss to a configured FX-difference account. See General Ledger → Multi-currency for the full picture.
Common gotchas
Posting an invoice to the wrong period. The transaction date on an invoice drives the fiscal period it posts to. If you post a January invoice with a February date, it lands in February. Edit the date on the draft before posting; once posted, you'd have to reverse and re-post.
Customer balance doesn't match a sum of invoices. Almost always a payment applied to the wrong invoice, or an unapplied credit sitting on the customer. Drill into the customer's transaction list to find the rogue payment.
Sales tax shows on the GL but not on the invoice. The tax line is computed and posts separately to a Sales Tax Payable account; it's part of the invoice's total but a separate journal-entry line in the GL. This is correct accounting — sales tax isn't your revenue, it's a liability you owe to the tax authority — but can surprise people coming from simpler systems.
Voided invoice still shows on the customer's statement. Voids leave the original entry in the file (with a reversing entry) so the audit trail stays intact. The customer's open balance won't include it, but the statement shows the full transaction history including the void/reverse pair. If you want a cleaner statement, generate it for a date range that excludes the original.
Currency exchange rate on an old invoice can't be edited. By design — historical rates are stored on the transaction, not derived. To correct an exchange rate on a posted invoice, post an adjusting journal entry to the FX-difference account.