# How we spot accounts that might churn

Each day an agent scores every account on early churn warnings from product usage, support and billing, then posts a ranked list to Slack with the reason and a suggested next step for each.

Canonical page: https://themachine.myapps.ai/use-cases/churn-risk

Customers rarely leave out of the blue. They log in less. They open more support
tickets, and the tone gets sharper. A card payment bounces. The renewal date
creeps closer. All the clues are there, but each one lives in a different tool,
and nobody is looking at every tool at once. So when the cancellation finally
arrives, the warning signs have been piling up for weeks.

We put an agent on Machine on watch. Every day it reads those clues and posts a
ranked list of at-risk accounts to our customer-success channel in Slack. It only
reads customer data, and that one Slack post is everything it writes. This is how
we keep an eye on our own customers.

- **Team:** Machine
- **Runs on:** A timer that fires once a day
- **Connected systems:** Postgres · Plain · Stripe · Slack
- **Mode:** Reads only · a single Slack post each day

## The problem

The clues that someone is about to leave are spread out. How they use the product
sits in Postgres. Support headaches sit in Plain. Payment health sits in Stripe,
and renewal dates sit in billing. Each gives you a slice. Lower usage alone may
mean nothing at all. Lower usage plus a growing pile of tickets plus a renewal
next month is a different story.

Typical setups don't join these up. A usage dashboard shows one clue and leaves
you to connect the rest in your head. A health score built into a single tool can
only see that tool. Hand-run account reviews are careful, but they come round
once a quarter, well after the trouble started, and only if someone remembers to
do them.

## What we built

A daily timer on Machine wakes an agent. It opens a **session**, a fresh cloud
computer (a sandbox) used only for that run, with read-only access to Postgres,
Plain and Stripe. The agent scores each account on the early warnings: usage
going down, support friction going up, payments missed or failed, and a renewal
on the horizon. Then it posts a ranked list of at-risk accounts in the
customer-success Slack channel, with the reason behind each one and a suggested
next move. Nothing is written back to any customer system.

## How it works

### Start a fresh run every day

A **cron trigger** (a timer) wakes the agent once a day, and each wake-up creates
a brand-new **session** in its own sandbox. That's one day, one run, one
throwaway computer. The scores are worked out from scratch against today's data
each time, with nothing kept from yesterday.

### Explain how you weigh the warnings

The way we balance the clues is kept in **skills** and **memory**, the playbook
the agent keeps and improves. It says what counts as falling usage, which support
patterns matter, how a failed payment and a near renewal add up, and what a
sensible next step looks like for each type of risk. Whenever we find out which
clues really came before a customer left, we note it, and the scoring gets
sharper.

### Give it read-only access to the data

The agent uses **connectors**: scoped connections to your tools, with keys held
on the server so the model never sees a raw token. Through them it reads:

- **Product usage from Postgres**: activity trends for each account, so a slide
is caught before it hits bottom.
- **Support signals from Plain**: how many threads there are and how they sound,
so growing frustration shows up early.
- **Billing from Stripe**: missed or failed payments and when the next renewal
is due.
- **A Slack post**: the ranked list, with a reason and a suggested next step for
each account.

### Keep it hands-off

The agent is **read-only** in every customer system. It can't write to Postgres,
Plain or Stripe, so accounts, tickets and subscriptions are all beyond its reach.
The Slack post is its only output. Credentials are stored encrypted in the
**Secrets Manager** and only handed to the agents you grant them to.

### Read the ranked list each morning

The result is a single Slack post every morning. Accounts appear in order of
risk, each with the clues that put it on the list (the drop in usage, the
support thread, the failed payment, the renewal date) and a suggested next step.
Your customer-success team reads it and chooses what to do. Nothing gets written
back on its own.

> **The pattern**
> A daily **cron** opens a session with read-only **connectors** into Postgres,
> Plain and Stripe, and the scoring rules live in **skills** and **memory**. The
> agent reads all of it, and the Slack post is the one thing it writes.

## Guardrails

This agent can see into every customer system, so its access is narrow and flows
one way:

- **Isolation.** Each run gets its own sandbox. The session can reach only the
  systems it was scoped to, and the Slack post is the only thing that leaves it.
- **Scoped secrets.** The Postgres, Plain and Stripe credentials are stored
  encrypted in the Secrets Manager, delivered into the sandbox when the run
  starts, and only handed to the agents you grant them to.
- **Read-only.** Every connector into customer data can only read. The agent
  can't alter an account, a ticket or a subscription. It reports, and that's
  all.
- **Everything is code.** The scoring rules, skills and permissions for each
  system are files in your repo. They're versioned, and you change them through a
  reviewed **change request**, not a dashboard toggle.

## The outcome

- **Every day:** Every account scored again on today's data
- **Read-only:** No writes to any customer system
- **4 signals:** Usage, support, billing and renewal rolled into a single score

Warning signs that once hid in four different tools now show up as a single
ranked list, right in the channel your team already lives in. Each account comes
with why it made the list and what to try next. The agent just reads. Your people
decide how to handle each account.
