.qfx, .ofx, .qbo, or CSV. This works on a machine with no bank connection
and, behind a client’s firewall, no way to have one. A live
connection is available as a paid add-on and fills
the same queue; nothing after arrival can tell the two apart.
Setting up an account
Once per bank or card account, name the QuickBooks account its lines belong in: “Set up the Amex Platinum feed for Ridgeline. Its lines post to the Amex Platinum credit card account.” Until an account is set up, there is nowhere for its lines to go.qb_feed_accounts lists what is registered and how many lines sit in each
state.
Importing a statement
Two steps, on purpose. CSV column detection is a guess about somebody else’s spreadsheet, and a wrong guess quietly misfiles a month:1
Preview it
qb_preview_statement reads the file and reports which column was read as the
date, the description, and the amount, plus how many rows parse and how many it
would skip. It stages nothing.2
Import it
qb_import_statement stages the rows and runs your coding
rules over what is new.Importing the same month twice does not double it. Lines are deduplicated
three ways — by the bank’s own
FITID where the format carries one, by a
content hash, and by reference heuristics against what the queue already
holds. Overlapping date ranges are recognised, not restaged.Working the queue
qb_feed_lines returns the queue oldest first, and the console’s Bank
feed tab shows the same queue as
buckets:
The page opens on what is open, because that is the only bucket that is work.
Code a line with
qb_code_feed_lines — the account, and optionally the payee
and class. Nothing is written to QuickBooks by coding; you are filling in what
a plan would post.
qb_exclude_feed_line takes a line out without posting it and remembers that
you did: a personal charge, a duplicate the bank will reverse.
What is already in the file
This is the part a hosted feed cannot do as well, and the mistake it exists to prevent is expensive: posting something the books already hold. It reconciles either way, so nobody notices. Zeno holds a local copy of the company file’s own transactions, soqb_match_feed can recognise a statement line as the
check somebody hand-entered last Tuesday rather than posting it a second time.
It proposes; it never decides. qb_accept_feed_match records that a line is
something already posted, which takes it out of the queue without posting
anything.
Posting what is left
qb_plan_feed turns the coded lines into an approval table — exactly the same
one qb_plan_batch produces, for the same reason:
“Plan the coded Amex lines for Ridgeline.”
From there it is the ordinary loop. Read the table, approve it, apply it, and
the run id undoes it. See your first batch.
A planned line leaves the queue while its plan waits. Once the plan is
decided, the line goes where the plan took it: Posted for every line the
run put in the file, and back to Ready to plan for the rest — a run that
failed a line, or a plan you rejected. A rejected feed plan hands its lines
back so you can recode them and plan again; nothing stays stranded “in a
plan” behind a decision that was already made.
A feed that posted its own entries would be a second path into the company
file, and a second path is a path where the gates are not.
A line’s content hash becomes its entry’s
sourceRef, so a plan built twice
from one statement carries the same idempotency key — and
qb_explain_transaction reads that link back to you months later.Where the queue lives
In the run journal, not in the local copy of the company file. That copy is disposable and gets rebuilt whenever it is wrong. A half-coded month of bank lines is work somebody did, and work does not live in a cache. On a shared journal it also means the person who imports the statement and the person who reviews it need not be the same person.A live bank connection
Optional, paid, and the one part of this product that needs an account and a network. The direction is the point: transactions come in, and nothing about the company file goes out. The relay never learns a chart of accounts, a vendor name, how a line was coded, or which client it belongs to. It holds your bank connection, not your bank history, and forgets each transaction as soon as the workstation confirms it staged it.1
Sign the workstation in
qb_relay_signin signs this workstation in to the feed. Every workstation on
the same journal shares it.2
Connect the bank
qb_connect_bank returns a link. The person who holds the banking credentials
opens it in whatever browser they like, on whatever device, and signs in to the
bank directly. The credentials never reach the workstation.Say where the feed should start. syncFromDate does two things at once: it
asks the bank for history back to that date, and it skips anything dated
before it, so a login connected in September for books you have kept from
statements since June does not queue June again. Banks share up to two years,
and they decide that once, when the login is connected — ask for everything
the books will ever need. Without a date, the bank shares its last ninety
days. The start can be moved later with qb_set_feed_start: earlier re-reads
the bank’s history without doubling what is already staged, and reaches back
as far as the bank agreed to when the login was made.3
Choose the accounts
qb_select_bank_accounts picks which accounts sync and where each one’s lines
post. One business login routinely carries a savings account and a personal
account nobody will ever code — syncing those costs money and fills the queue
with noise. Selection is what is billed.4
Collect what arrives
qb_sync_bank_feed pulls what the bank has sent into the same queue a
statement import fills. Once a line has arrived it is indistinguishable from
one off a downloaded statement.qb_disconnect_bank disconnects a login and stops paying for it. Lines already
staged are left alone: disconnecting stops the future, it does not rewrite the
past.
The bank balance beside the books
qb_bank_balance puts what the bank says each fed account holds — or, for a
card, owes — next to the QuickBooks balance, both read when you ask: the
bank’s from the feed’s last read of the bank, the books’ from QuickBooks
itself. The two agree only in the moment a feed is fully drained and posted,
so the point is not the gap but why: how much of it is lines at the bank not
yet in QuickBooks (and of those, how many sit in a plan awaiting approval or
are still uncoded), and how much the feed cannot account for — a cheque
written and not yet cashed, or money at the bank before the feed’s start. A
bank account in another currency is shown beside the QuickBooks figure rather
than subtracted from it.
The console’s feed page shows the bank’s half of this with a prompt that hands
the comparison to the chat, since the console never opens a company file.