# How we close the books on expenses each month

Once a month a Machine agent checks Stripe and the bank feed against our invoices, records the result in Google Sheets and posts a summary. Anything it cannot match goes to a person.

Canonical page: https://themachine.myapps.ai/use-cases/expense-reconciliation

Month-end reconciliation sounds easy and feels endless. You set the money that
actually moved beside the money that should have moved, find the gaps, and
explain each one. On a small team, one person loses an afternoon to it, and it
is the same lost afternoon every single month.

We gave that afternoon to an agent that runs on a schedule. Once a month it
checks payments against invoices, points out anything that does not add up, and
writes up a summary. Here is how we run it on Machine, from the connections to
the steps to the limits we set.

- **Team:** Machine
- **Connected systems:** Stripe · Bank feed · Google Sheets
- **Trigger:** A cron job, once a month
- **Mode:** Runs on a schedule · unmatched items go to a person

## The problem

Matching numbers is dull right up to the moment it matters. Nearly every line
pairs off cleanly. What you are really hunting for is the small handful that
will not: a payment that never arrived, a fee that leaves the totals off by a
little, an invoice with no deposit to match it. You only find those by checking
all of it, and doing one tedious comparison hundreds of times is slow and easy
to get wrong.

A spreadsheet formula spots perfect matches and misses the almost-matches,
which is exactly where trouble tends to sit. So you choose between a quick pass
that lets things slip and a thorough one that swallows someone's whole day.
Either way, it only gets done when someone finds the time.

## What we built

A monthly **cron** wakes a reconciliation agent on Machine. Each run gets its
own **session**: a fresh cloud computer (a sandbox) used for that run alone,
with limited access to the three places reconciliation needs, Stripe, the bank
feed and the Google Sheet where we keep our records. The agent pairs payments
with invoices, flags anything that does not line up, writes a summary into the
sheet, and passes whatever it cannot match to a person.

## How it works

### Set a monthly schedule to start it

A **cron** trigger kicks off the project once a month, after the period has
closed. Every time, Machine opens a brand new **session** on its own sandbox.
Each month gets its own run on a throwaway machine, and nothing from the
previous month comes along.

### Hand the agent your reconciliation rules

Our way of reconciling is kept as **skills** and **memory**, a playbook loaded
into every session that the agent keeps improving. It defines what a match is,
how much slack we allow on fees and on timing, which accounts we follow, and the
mismatches we have already explained in earlier months. The agent sticks to
those rules instead of making up its own, and its memory grows as the same
patterns come round again.

### Connect only what reconciliation needs

**Connectors** are scoped links to your tools. The keys stay on our servers, so
the model never holds a raw token. Through them the agent can:

- **Look at Stripe**: the period's charges, payouts and fees.
- **Look at the bank feed**: money in and money out, to pair with Stripe and
the invoices.
- **Read and update the Google Sheet**: the ledger it checks against, and the
place it writes its summary.

### Draw the lines it cannot cross

Stripe and the bank are look-only. The tracking sheet is the one thing the agent
can write to, and it never moves money. If something will not match within our
allowed slack, it goes **to a person**; the agent does not squeeze it into a
match or write it off. Credentials are stored encrypted in the **Secrets
Manager** and only handed to the agents you grant them to.

### Let the month take care of itself

From then on, each month ends with a reconciled sheet and a summary, and nobody
had to press start. Lines that match are ticked off quietly. A payout that comes
up short by a fee gets an explanation. An invoice with no deposit gets flagged
and sent to someone to follow up, with the two records that would not pair
attached.

> **The pattern**
> Start the project with a monthly **cron**. Use scoped **connectors** so the
> agent can read Stripe and the bank feed and write to the sheet. Keep your
> reconciliation rules in **skills** and **memory**, and send every item it
> cannot match to a person.

## Guardrails

Letting an agent near your financial systems is, before anything else, a
security decision. Here is how Machine keeps it safe:

- **Isolation.** Every run happens in a private sandbox. The session can read
  the accounts it needs, and the summary it writes into the sheet is the only
  thing that leaves.
- **Scoped secrets.** The keys for Stripe, the bank and Sheets are stored
  encrypted in the **Secrets Manager**, passed into the sandbox when the run
  starts, and only handed to the agents you grant them to.
- **Human approval gate.** Items that will not match within the allowed slack go
  to a person instead of being forced to fit, and the agent never moves money.
- **Everything is code.** The agent's persona, skills and permissions are files
  in the repo, kept in version control. Changing them takes a reviewed **change
  request**, never a dashboard click.

## The outcome

- **Every month:** Books reconciled on a timetable, not when someone is free
- **Mismatches only:** People review the exceptions instead of every line
- **3 systems:** Stripe, the bank feed and the sheet, handled by one agent

The afternoon once spent checking hundreds of lines now goes on sorting out the
few the agent could not pair. Reconciliation happens every month, busy or not,
and the summary is already in the sheet when your finance person opens it.

Four things hold it together: a private sandbox for each run, the **Secrets
Manager** guarding the Stripe, bank and Sheets keys, a clear route to a person
for anything unmatched, and memory that keeps known explanations from one month
to the next.
