1
Intake
Files are identified by their content (PDF, PNG, JPEG), never by their names. PDFs pass a bounded safety parse
(no JavaScript, launch actions or embedded files); one that cannot be parsed safely is rebuilt from its
rendered pages. Photos and screenshots become one-page PDFs at their native resolution. In an email, every
attachment is examined, and logos, tracking pixels and inline images are skipped.
2
Split and stitch
Each PDF is split into documents (bank statement, application, other) by page and by statement boundaries:
“Page 1 of N”, or a page printing a different statement period than the one before it. Pieces of one
document are put back together first: bank-portal downloads named
... Pages 1-20.pdf and
... Pages 21-41.pdf, or a photo of each page.3
Read
A statement with a text layer is read from the page’s own geometry: its tables are rebuilt and turned
into a signed ledger, with the period, balances, account number and holder from the header.A scanned or photographed statement is first checked for sharpness, exposure, washed-out ink and skew. One
that cannot be read reliably fails as
image_reupload_required, naming the page and its problems, so you can
ask for a better copy. A readable scan is read by a vision model page by page, and each page is checked
against its own printed running balances. A second, independent read must agree on every amount, date and
balance before the ledger can be accepted.4
Verify
A ledger is verified only when it reconciles to the cent (
opening + credits - debits = closing), matches
the bank’s printed totals and keeps every running-balance chain. A printed amount is never rewritten to make
the balance close; a missing row fails the read instead. A statement that does not verify is
review_required, its rows are withheld (set include_unverified to receive them, flagged), and it is never
used in the metrics.5
Categorize
Every row gets a category and a counterparty: revenue, MCA funding or payment, loan, NSF fee, overdraft fee,
returned item, transfers, payroll, taxes, bank fees, operating expenses, or
unknown. Two independent model
reads label every group of similar rows, and a label stands only where both agree; deterministic rules fill
and cross-check every row, and disagreements are flagged.6
Aggregate
Accounts (one per last four digits) and calendar months are built from each row’s own date, so mid-month
statement cycles and December-to-January statements land in the right month. Partial months are flagged and
kept out of the averages, missing months are flagged, and no day is counted twice.Then positions: the advances and loans being repaid. Each candidate stream is decided by two independent
reads and checked against the rows and their payment cadence; a stream is a position only where both reads
agree. Loans are reported but not counted in the MCA withhold. Finally the monthly summaries (true revenue,
NSF and overdraft counts, EBITDA) and the underwriting block (average monthly revenue, existing MCA burden,
current withhold, stacking, capacity, pricing).
7
Packet
The files are judged as one submission: which documents the decision rests on and why others are excluded,
the merchant’s details with their sources, coverage month by month, and checks only the whole packet can
answer. See The submission packet.
One merchant, several ISOs
A merchant often reaches you through more than one ISO, each sending the same statements in its own files. Nothing is read twice, and the numbers never differ between submissions:- Content fingerprint (
content_fingerprinton each statement): what the pages say, not the file. The same statement re-saved, re-downloaded or merged into another ISO’s PDF matches, and its earlier read is reused (read_reused). - Statement fingerprint (
statement_fingerprint): last four digits, period and balances. The first verified read of a statement is canonical; a later read that disagrees is flaggedstatement_differs_from_earlier_submission. - Merchant linking (
merchant_fingerprint,related_jobs): jobs sharing an EIN or any statement are one merchant, and each result lists the merchant’s earlier jobs.
Cost
Every model call is metered (tokens, cost, latency), and the totals are on each job’susage and in
usage reports. A document sent again is answered from the cache and costs nothing.