Why it takes two checks
get_recurring_charges groups charges by merchant and looks for a steady interval, so it needs at least two charges. By then you've paid twice. A check on the first charge is noisier, since a new restaurant looks the same as a new subscription at that point. Running both gets you an early hint and a firm signal a cycle later.
Catch the first charge
Save this prompt as a scheduled run:
Using BankBridge, list every charge from the last 7 days. For each merchant, check get_merchant_history over the 12 months before that. Report merchants with no earlier charge: name, amount, date and last four digits of the account. Mark the ones that look like a subscription or trial. If there are none, say so in one line. Nobody can answer questions during this run, so state any assumption and finish.
The steps for Claude, Claude Code, Hermes Agent, OpenClaw and cron are in scheduled money reviews. The agent judges what looks like a subscription from the merchant name, so expect a few wrong guesses in both directions.
Catch the second charge, no model needed
This script uses only curl, jq and standard shell tools. It keeps a list of every merchant it has seen, so a charge that drops out of the six-month window and comes back later won't alert twice. The first run saves the list and prints nothing. After that it prints only new names, and with cron's usual behavior, no output means no email.
Put your key from BankBridge settings in ~/.bankbridge/key, run chmod 600 on it, and save this as ~/.bankbridge/new-subscriptions.sh:
#!/bin/sh
# Prints merchants that newly show a recurring pattern. Silent when nothing changed.
set -eu
DIR="$HOME/.bankbridge"
SEEN="$DIR/seen-merchants.txt"
NOW="$DIR/now.txt"
KEY=$(cat "$DIR/key")
touch "$SEEN"
curl -sS --fail https://bankbridge.money/api/mcp \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"get_recurring_charges","arguments":{}}}' \
| sed -n 's/^data: //p' \
| jq -r '.result.structuredContent.recurring[] | "\(.merchant)\t\(.amount)\t\(.frequency)"' \
| LC_ALL=C sort > "$NOW"
cut -f1 "$NOW" | LC_ALL=C sort -u > "$NOW.names"
LC_ALL=C sort -u "$SEEN" -o "$SEEN"
LC_ALL=C comm -13 "$SEEN" "$NOW.names" > "$NOW.new"
if [ -s "$SEEN" ] && [ -s "$NOW.new" ]; then
echo "New recurring charges:"
LC_ALL=C join -t "$(printf '\t')" "$NOW.new" "$NOW"
fi
LC_ALL=C sort -u "$SEEN" "$NOW.names" -o "$SEEN"Schedule it with crontab, here every Monday at 8am:
MAILTO=you@example.com
0 8 * * 1 sh $HOME/.bankbridge/new-subscriptions.shTo try it first, put bbk_demo in the key file. That key returns fictional accounts. Run the script once to save the list, delete one line from seen-merchants.txt and run it again. We did this with the demo gym membership and got:
New recurring charges:
Planet Fitness 49 monthlyThat's demo data. Switch to your own key and delete the seen file before you rely on it, or the demo merchants will stay on the list.
What the alert misses
| Situation | What to do |
|---|---|
| An existing subscription raises its price | Check for price increases |
| A merchant changes the name on its charges | It looks new, so you'll get a false alert. Spot renamed charges |
| A yearly charge | The default window is six months, so two charges won't fall inside it. Set start_date further back in the arguments, or rely on the first-charge prompt. |
| A subscription billed through Apple or Google | Your bank shows the store's name, so a new app often looks like an old merchant. See your Apple charges |
| A charge that hasn't posted | The check reads what your bank reports, so it can lag the charge by a day or more. |
For a one-time look at everything you're paying for, run a subscription audit first, then let the alert watch for what's new. BankBridge costs $5 a month or $50 a year per connected bank and is read-only, so cancelling stays with you. Connect a bank to start.