Import statements¶
Importers never write to your books. The loop:
- Import: drafts land in
staging/(gitignored). - Review and complete each draft.
- Move it to
books/<year>.bean. - Delete the draft.
Nothing reaches the ledger unreviewed.
Applies if
- Legal form: Einzelfirma, GmbH or AG. Same steps for all three.
- Sources: UBS (MT940), Yapeal (CSV), Wise and Stripe (API or JSON export).
- VAT status: any. It only changes how a draft is completed — below.
UBS (MT940)¶
Drafts every movement on the account into staging/. Each draft is flagged:
*— complete as drafted (a rule matched and the booking is unambiguous)!— needs your VAT decision and a linked document before it moves to books
Rules live in quints.toml under [import.ubs] — [payee regex,
counter account, flag] triples. See quints.toml.
Yapeal (CSV)¶
quints import yapeal <statement.csv> drafts a Yapeal account's activity from
the CSV export the same way, with rules under [import.yapeal]. The scaffold
ships a sample statement (statements/yapeal.csv); enable the importer with
quints init --importers ubs,yapeal or by adding the section to quints.toml.
Wise and Stripe¶
quints import wise --fetch --from 2026-07-01 --to 2026-09-30
quints import stripe --fetch --from 2026-07-01 --to 2026-09-30
--fetch pulls from the APIs: QUINTS_WISE_API_TOKEN (plus
QUINTS_WISE_PRIVATE_KEY for SCA-protected profiles) and
QUINTS_STRIPE_API_KEY in .env. Both commands also accept already-fetched
JSON files as arguments. Wise conversions are merged into one transaction;
Stripe fees and payouts are split out, with the VAT inside Stripe's own fees
drafted against InputVAT.
Each import writes a new file in staging/, never over an earlier one: a
second import the same day goes to <date>-<source>-2.bean. If its
drafts are already in an earlier staging file, the import says so; move
each to books/ once.
Imports are idempotent — each transaction carries its source id
(mt940_ref:, wise_id:, stripe_id:), so re-importing a statement never
duplicates a booking. That holds only for what the ledger actually loads:
if it has loader errors, the import lists them and warns that a draft may
repeat an entry the ledger dropped. Run quints check and fix them first.
Complete a draft¶
A ! draft knows the cash leg only. Add the counter leg, link the source
document (document:), flip ! to *. The VAT legs depend on your status
on the transaction date:
Book gross: no InputVAT, no OutputVAT. A foreign service is a plain expense. Bezugsteuer only starts once such purchases pass CHF 10'000 in a calendar year, and then you have to register for it.1
Split a purchase with Swiss VAT into net + InputVAT, and book a sale's
VAT to OutputVAT. For a foreign service, book the Bezugsteuer pair.
quints vat convert … --bezugsteuer prints it in CHF at the right rate.
Book purchases gross: no InputVAT, ever. The Saldosteuersatz already
accounts for input tax. Sales still carry the statutory VAT to
OutputVAT. A foreign service still owes Bezugsteuer, as a cost:
quints vat convert … --bezugsteuer prints the pair.
quints vat report flags a VAT leg that doesn't fit the method in force on
that date.
Payments that quote an invoice¶
An incoming payment is matched to an open invoice by the reference it carries
— the QR reference or RF creditor reference from the QR-bill, or the plain
invoice number — read out of the payee, narration and metadata, verified by its
check digits, and matched exactly, never by substring. A match turns the
draft's counter leg into the receivable clearing, adds invoice: metadata and
the ^number link. It is flagged * only when the payment equals what is
open on the invoice. A short payment, an overpayment, or a payment with no
reference from a customer with open invoices is drafted !, with a ;
comment saying how it was allocated: see
Allocate customer payments. A reference that fits more than
one open invoice matches nothing: the draft stays ! and quints match says
why. How the references are built, and which one your QR-bills use, is in
Payment references.
Stripe customer invoices¶
--invoices additionally files the invoice PDF Stripe renders for each
charge (invoice_pdf) into inbox/, named
YYYY-MM-DD.customer.INVOICENUMBER.pdf — the same convention quints invoice
files its own PDFs under. That is the document carrying the customer's name,
address and tax number, which is what substantiates the place of supply behind
an export booking; the payment itself is already evidenced by the stripe_id:
reference on the draft.
The key needs Invoices: Read on top of the fetch scopes. Every file is
reported on its own line, and anything already in inbox/ or documents/ is
left alone, so re-runs download nothing.
Stripe doesn't reliably link an invoice to the balance transaction that pays
it, so the two are correlated on amount, currency and timing when no shared id
exists. If a charge could belong to more than one invoice, the command says so
and files nothing rather than guessing — the drafts are already in staging/
by then, so only the documents are affected.
Stripe's own monthly fee invoices are a separate matter: they have no API. When a month's fee debit carries VAT, the import says which month needs its tax invoice pulled by hand from the Dashboard (Settings → Plans and fees → Invoice history), which the quarterly VAT close needs.
Supplier bills (payables)¶
A supplier bill is booked when it arrives, not when it is paid: the expense
(and any input VAT) against the trade-payables account from quints.toml.
2026-08-20 * "Treuhand Muster" "Bookkeeping — first half" ^TM-2026-4711
bill: "TM-2026-4711"
due: 2026-09-19
Expenses:CH:GmbH:Admin:Bookkeeping 480.00 CHF
Liabilities:CH:GmbH:Payable:Trade -480.00 CHF
bill: is the supplier's own invoice number; due: is what the aging is
measured against. Both are optional. Without due:, the payment terms run
from the bill date — 30 days, or [payables] default_terms_days. A due:
that isn't a date (due: end of month) is listed as a problem, and the
bill shows without a due date rather than a guessed one. Without
bill:, a lone ^link names the bill; with neither, the bill is grouped by
payee and amount, which nets against a payment for the same payee and the
same amount and nothing else.
The bank payment clears the liability. quints match scores every outgoing
draft against the open bills: the supplier's own reference decides it
outright, otherwise an amount that fits exactly one open bill, from a payee
whose name matches, inside the window after the bill date. An amount that
fits two open bills identifies neither — both are listed with the reason and
the draft stays flagged for you.
Review helpers¶
match scores staging drafts and inbox documents against invoices, open
supplier bills and existing bookings, so you see what belongs together before
you book. inbox inventories inbox/ — filename hints, duplicates, documents
already linked. payables ages the supplier bills you still owe, in their
original currency plus a consolidated total; --at reports as of a date,
--json for an agent. Settled but unpaid VAT is no supplier bill — it sits
on PayableVAT — so it is shown as a footer line, not in the table; the
detail is in quints vat status.
Drop source PDFs into inbox/ named YYYY-MM-DD.payee.narrative.pdf; once
booked, file them under documents/ mirroring the account path, and link
them with document: metadata on the transaction.
What quints doesn't do here¶
- Book a draft for you. The counter leg, the VAT decision and the document are the review step. An AI agent can do it; quints then checks the result (Working with AI agents).
- Fetch Stripe's own fee invoices. Stripe has no API for them. The import says which month to download by hand.
- OCR a PDF. Documents are matched by filename and metadata, not by reading their content.