Skip to main content
A packet is every document of one merchant’s submission, sent in one request or one email thread. Each packet goes through the same steps.
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_fingerprint on 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 flagged statement_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’s usage and in usage reports. A document sent again is answered from the cache and costs nothing.