tieout
by ubukhari
README.md
# tieout
Tie your Stripe payouts to your bank deposits, and your QuickBooks or Xero books to your bank
statement, month by month, from the CSV exports you already have. tieout lists what does not tie,
with the amount and the likely reason, and writes a dated sheet an accountant can review.
Prepared for your review. Not tax or accounting advice.
```sh
npx --allow-git=root github:agentwares/tieout statement.csv stripe-payouts.csv
```
Add the itemized payout reconciliation report to see inside each payout, and your books to tie them
too:
```sh
npx --allow-git=root github:agentwares/tieout statement.csv stripe-payouts.csv stripe-itemized.csv general-ledger.csv --account Checking
```
No account, no bank linking, no LLM. It reads the files you name and makes no network request,
unless you ask it to read Stripe with your own restricted key (below).
## What it tells you
**Stripe payouts against bank deposits.** A Stripe payout is the net of many charges, refunds,
disputes and fees, and it lands days after the sales it carries, so it never equals a day's sales.
tieout matches each payout to its deposit, one to one: the same amount, within 5 days of Stripe's
estimated arrival date (`--window`). Each payout:
- **ties**: the same amount, the same day;
- **timing**: the same amount, a few days off. It says how many days, and whether the payout left
Stripe in one month and reached the bank in the next. Such a payout was in transit at that
month's end, which is a reconciling item, not an error.
- **no deposit**: with the likely reason:
- still in transit after the statement ends;
- an instant payout to a debit card;
- a different bank account on the Stripe account;
- **failed**, **after the statement** or **other currency**: no deposit is expected.
Bank lines naming Stripe that no payout explains are listed too: another Stripe account, or a payout
outside the export's dates.
**What is inside each payout**, from the itemized report: gross sales, refunds, disputes (with
Stripe's $15 dispute fee), fees and other adjustments. tieout checks that they add up to the
payout, and writes them as balanced journal lines for review. Booking the deposit alone understates
sales and leaves the fees out.
**Your books against the statement.** For each month, the statement's ending balance is set
against the books'. Each month **ties**, differs by **timing only**, or **does not tie**. A
difference is explained by:
- items in transit at the month end;
- bank lines not in the books: a bank fee, interest, an unrecorded payout;
- book lines not on the statement: a duplicate, a void, a check not yet cashed;
- likely transposed digits: a difference that divides by 9;
- an opening difference;
- any remainder no item explains. When the statement has a running balance, that remainder means
rows are missing from the export.
The first month that does not tie is where a fix starts. Later months carry it.
## The files, and where to get them
| File | Where |
| ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Bank statement | Your bank's website, as CSV (one file or one per month). Signed amounts, debit and credit columns, or amount and type; `--map` names unusual columns; `--day-first`. |
| Stripe payouts | Dashboard → Balances → Payouts → Export. |
| Stripe itemized payouts | Reports → Payout reconciliation → Download → Itemized, for the payouts' arrival dates. |
| Balance transactions | Instead of the itemized report, a balance-transactions export with a payout column. |
| QuickBooks Online | Reports → General Ledger or Transaction Detail by Account → Export to CSV, for the bank account (`--account Checking` when it holds several). |
| Xero | Accounting → Reports → Account Transactions → Export → CSV, for the bank account. |
Files given without a flag are sorted by what they hold. Use `--bank`, `--stripe` and `--ledger` to
say it outright.
## Stripe's own reports, and when they are enough
- **US accounts on automatic payouts:** if you will link your bank account to Stripe, Stripe's free
[Bank reconciliation report](https://docs.stripe.com/reconciliation/bank-reconciliation) marks
each payout Reconciled or Unreconciled against your deposits in the Dashboard.
- **Who it does not cover:** it is "only available for users with direct US-based Stripe accounts
using an automated payout schedule". It does not cover Connect accounts, accounts outside the
US, or manual and instant payouts. It also does not look at your books.
- **What tieout adds:** the same tie from a CSV, with no bank linking, for any account and payout
type, and the books against the statement.
- **The [payout reconciliation report](https://docs.stripe.com/reports/payout-reconciliation)**
itemizes automatic payouts only. You are "responsible for reconciling instant payouts", and
manual payouts go through the Balance report.
## Reading Stripe with your own key
```sh
TIEOUT_STRIPE_KEY=rk_live_… npx --allow-git=root github:agentwares/tieout --bank statement.csv --stripe-api
```
- **The key:** create a restricted key with Read on Payouts and on Balance and nothing else
(Dashboard → Developers → API keys). tieout reads it only from `TIEOUT_STRIPE_KEY`, never from
an argument.
- **Secret keys are refused.** An `sk_` key can move money, so tieout stops before sending any
request.
- **What is sent:** only GET requests, to api.stripe.com: the payouts arriving across the
statement's dates, and the balance transactions inside each automatic payout
([Stripe's guide](https://docs.stripe.com/payouts/reconciliation)).
- **What is kept:** the key is never printed or written.
## The sheet
`tieout-<date>/` holds:
- `tie-out.md`: the summary, every payout, every month, what does not tie with its likely reason,
the journal lines, the sources and a reviewer line;
- `payouts.csv`, `exceptions.csv`, `months.csv` and `journal.csv`.
Each file opens with the disclaimer, and all are written with owner-only permissions. Other
options:
- `--json` prints the whole result;
- `--no-files` writes nothing;
- `--out` puts the sheet elsewhere.
## For agents: `tieout mcp`
A local stdio MCP server with two read-only tools:
- **`tieout_check_payouts`:** Stripe payouts against deposits, and the books when a ledger is
given.
- **`tieout_check_account`:** the books against the statement, month by month.
Both tools:
- take file paths only, never a key, and write nothing;
- set all four annotations: read-only, not destructive, idempotent, closed-world.
```json
{
"mcpServers": {
"tieout": {
"command": "npx",
"args": ["-y", "--allow-git=root", "github:agentwares/tieout", "mcp"]
}
}
}
```
## Catch-up bookkeeping
Catch-up bookkeeping by agent, priced per month behind, is not built.
- **What it would do:**
- the months that do not tie, done from your statements and Stripe;
- every transaction categorized;
- every payout booked gross with its fees, refunds and disputes;
- every account-month tied to its statement;
- review by a person before delivery.
- **No price is set.** The CLI's last line links to a page where one click is counted; it gets
built only if enough people ask.
- `--quiet` drops that line.
## Recorded run
On invented data (`tieout demo`): a bank statement, Stripe's payouts and itemized exports, and a
QuickBooks General Ledger for three months.
<!-- recorded-run -->
```text
$ npx --allow-git=root github:agentwares/tieout demo --out tieout-demo
SYNTHETIC demo data: an invented company, bank statement, Stripe exports and books. Nothing here is anyone's real data.
tieout 0.1.0 · prepared 9 Oct 2026
Prepared for your review. Not tax or accounting advice.
Read
synthetic-bank-statement.csv
bank statement, 22 rows, 1 Jan 2026 to 31 Mar 2026, running balance
synthetic-stripe-payouts.csv
Stripe payouts export, 11 payouts
synthetic-stripe-itemized-payout-reconciliation.csv
Stripe itemized payout reconciliation report, 9 payouts, 21 items
synthetic-quickbooks-general-ledger.csv
QuickBooks General Ledger, Checking, 23 rows
Stripe payouts to bank deposits (USD)
6 tie: same amount, same day
2 timing: same amount, a few days off (1 across a month end)
1 no deposit on the statement
1 failed or cancelled: no deposit expected
1 arrives after the statement's last day
1 bank line names Stripe and matches no payout
Inside 9 itemized payouts: sales 4,043.00 · refunds -50.00 · disputes -120.00 · fees 137.66 · other 640.00
The books against the statement (Checking)
Jan 2026 ties
Feb 2026 timing only -1,200.00 1 in transit
Mar 2026 does not tie 392.00 2 not in the books, 3 not on the statement
What does not tie (7)
1. payout with no deposit 17 Feb 2026 300.00 po_SYNTH0006
synthetic-stripe-payouts.csv
- an instant payout: these often go to a debit card, not this bank account, and Stripe does not itemize them
- paid to a debit card, not a bank account
2. Stripe deposit with no payout 20 Mar 2026 412.50 STRIPE TRANSFER ST-OTHERACCT SYNTHETIC
synthetic-bank-statement.csv row 3
- a payout from another Stripe account, or one outside the dates of the Stripe export: export Payouts for a wider range
3. on the statement, not in the books 17 Mar 2026 397.51 STRIPE TRANSFER ST-SYNTH0010 SYNTHETIC EXAMPLE CO
synthetic-bank-statement.csv row 4
- transposed digits? the books have 379.51 on 2026-03-17 (synthetic-quickbooks-general-ledger.csv row 28); the difference, 18.00, divides by 9
- a Stripe payout not recorded: book it gross, with its fees, from the payout's itemized report
4. on the statement, not in the books 31 Mar 2026 -25.00 MONTHLY SERVICE FEE
synthetic-bank-statement.csv row 2
- a bank fee or interest, which the bank books and the books often miss
- a payment not recorded in the books
5. in the books, not on the statement 6 Mar 2026 49.00 Software subscription
synthetic-quickbooks-general-ledger.csv row 25
- recorded twice? the same amount is on 2026-03-05 (synthetic-quickbooks-general-ledger.csv row 24), and the bank shows it once
- a payment in the books that never left the bank (a void, or another account)
6. in the books, not on the statement 17 Mar 2026 -379.51 Stripe payout po_SYNTH0010
synthetic-quickbooks-general-ledger.csv row 28
- transposed digits? the statement has 397.51 on 2026-03-17
- a deposit in the books that never reached the bank (a void, or another account)
7. in the books, not on the statement 27 Mar 2026 350.00 Check 1042 to contractor
synthetic-quickbooks-general-ledger.csv row 30
- an outstanding check, not yet cashed
- recorded near the statement's end: it may clear on the next statement
Wrote ./tieout-demo: tie-out.md, exceptions.csv, payouts.csv, journal.csv, months.csv
Catch-up bookkeeping by agent, priced per month behind, is not built. Count me in: https://agentwares.vercel.app/reconcile/waitlist/cli
(exit 0)
$ ls tieout-demo
exceptions.csv
journal.csv
months.csv
payouts.csv
synthetic-bank-statement.csv
synthetic-quickbooks-general-ledger.csv
synthetic-stripe-itemized-payout-reconciliation.csv
synthetic-stripe-payouts.csv
tie-out.md
```
<!-- /recorded-run -->
## Sources
Read 9 October 2026:
- [Stripe: Bank reconciliation](https://docs.stripe.com/reconciliation/bank-reconciliation)
- [Stripe: Payout reconciliation report](https://docs.stripe.com/reports/payout-reconciliation)
- [Stripe: Payout reconciliation through the API](https://docs.stripe.com/payouts/reconciliation)
- [Stripe: Pricing](https://stripe.com/pricing): cards 2.9% + 30¢, $15 per dispute received,
instant payouts 1.5% (minimum 50¢)
## License
MIT
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues