# How we catch wasted SaaS spend

Once a week our agent lines up card and bank charges with our subscription register and points out duplicate tools, idle seats, price rises and shadow IT. It suggests fixes and never cancels anything.

Canonical page: https://themachine.myapps.ai/use-cases/saas-spend-audit

Software subscriptions multiply when nobody is looking. Someone tries a tool,
the free trial ends, and the charge keeps coming. Two teams each buy a product
that does roughly the same job and never compare notes. A vendor bumps its price
and the bill just quietly grows. A card pays for something no one ever wrote
down. You only spot any of it when a person lines up a spreadsheet against the
bank transactions, and that rarely happens: the job is dull, and by the time
someone gets to it the spreadsheet is out of date anyway.

So we gave the job to an agent on Machine. Each week it compares our card and
bank charges with our subscription register and shares what it found in Slack.
It never alters a subscription. All it does is suggest. That is how we keep our
software bill honest.

- **Team:** Machine
- **Runs on:** A weekly schedule
- **Connected systems:** Plaid · Google Sheets · Slack
- **Mode:** Reads only · suggests only · cancels nothing

## The problem

Catching waste means comparing two lists: what we are really being charged, and
what we think we are paying for. They are kept in separate places and slowly
stop agreeing. Every repeat charge appears in the bank feed. The subscription
register reflects what finance believes it has signed up for. A trial paid on
someone's personal card never reaches the register at all. A price rise looks
like the same line with a slightly bigger number, and it is easy to overlook
among a hundred other charges.

A quarterly review catches part of it, but that is a one-off snapshot done by
hand, and a duplicate tool or a forgotten renewal can rack up three months of
charges in between. Checking more often would mean someone redoing the same
comparison every single week. That never happens, because nobody has a free
afternoon each week to spend on it.

## What we built

On Machine, a weekly **cron** wakes up an agent that keeps the same
**session**, its own cloud computer (a sandbox), from one week to the next. It
pulls repeat card and bank charges from Plaid, pulls the subscription register
we maintain in Google Sheets, and compares the two. It looks for tools that
duplicate or overlap, seats that appear idle, prices that have gone up since its
last check, renewals arriving soon, and shadow IT: charges with no row in the
register whatsoever. The findings go to Slack, and the agent remembers what it
has already raised, so an item still waiting on a fix is not announced fresh
every week.

## How it works

### Keep one session going week to week

A **cron trigger** goes off once a week. Most scheduled agents start from
scratch each time, but this one lives in a **reusable session**: the same
session is woken up again rather than replaced. That continuity is how it
recalls which subscriptions it has already raised and what it suggested before.
A duplicate tool nobody has dealt with yet earns a single line in the summary,
not another alarm every Monday.

### Teach it the audit rules

The definitions sit in a **skill**, the playbook the agent brings to every run:
what makes a tool a duplicate, when a seat counts as unused, how big a price
change must be to matter, and which renewals are worth a mention. The skill
also covers how a bank charge gets matched to a register row, the cutoff for
reporting a price move, and how each suggestion should be laid out. When we
adjust a cutoff, we change the skill rather than giving a one-time instruction.

### Link the systems so it can only look

Using **connectors**, narrow connections to your tools whose keys stay on our
servers so the model never handles a raw token, the agent reads:

- **Repeat charges via Plaid.** It takes the card and bank feed and groups
charges into recurring merchants over a rolling window.
- **The register in Google Sheets.** This is what finance thinks we pay for,
and what it thinks each one costs.
- **Slack, for posting.** That is where the weekly summary of new and
still-open findings goes.

It cannot write to Plaid or to the register. Adding a row, deleting one or
editing a price in either place is simply beyond its reach.

### Set the boundaries

Reading two systems and posting in Slack is everything this agent can do. It
**recommends** cancelling, downgrading or merging tools, and it never cancels,
pauses, downgrades or in any way changes a subscription or a payment method on
its own. Making that call, and actually clicking the button, belongs to a
person. Credentials are stored encrypted in the **Secrets Manager** and only
handed to the agents you grant them to.

### Share the weekly summary

Every weekly post separates what is new (a fresh shadow IT charge, a price that
just changed, an upcoming renewal) from what is still open from earlier weeks,
and leaves out anything that has not moved. Each line shows its proof, which is
the charge, the register row, or the missing row, along with a suggested next
step. Finance reads it and chooses what to cancel or renegotiate.

> **The pattern**
> A weekly **cron** wakes a long-lived **session** that compares Plaid with a
> Google Sheets register through look-only **connectors**. The audit rules sit
> in a **skill**, a **ledger** keeps track of what has already been raised, and
> the agent only suggests. Every cancellation is a person's decision.

## Guardrails

This work means reading two sets of financial records, so the limits are spelled
out plainly:

- **Isolation.** Each run takes place in a sandbox of its own. The session can
  reach only Plaid and the register it was given, and the Slack summary is the
  only thing it sends back out.
- **Scoped secrets.** The Plaid access token and the Sheets keys are stored
  encrypted in the Secrets Manager and only handed to the agents you grant them
  to.
- **Recommend-only.** The agent cannot write to Plaid, has no billing API, and
  has no means to cancel, downgrade or pause anything. All it ever produces is a
  Slack message with a suggestion. Any change to a subscription is made by a
  human.
- **No repeat noise.** A ledger carries over from week to week, so an open
  finding shows up once instead of setting off a new alert on every run. Only
  waste that is new or has changed gets reported as new.
- **Everything is code.** The agent's persona, its audit rules and its
  permissions for each system live as files in the repo. They keep their
  history, and changes go through a reviewed **change request** rather than a
  dashboard toggle.

## The outcome

- **Every week:** Charges checked against the register like clockwork
- **Recommend-only:** No subscription is cancelled or changed automatically
- **5 waste signals:** Duplicate tools, idle seats, price rises, renewals and shadow IT

The side-by-side check that once meant someone sitting with a spreadsheet and a
bank statement now happens every week on its own, and it only speaks up about
things that are new or still unresolved. The agent reads the charges and the
register. Finance picks which suggestions to act on.
