Skip to main content
Subscriptions are the quiet budget-killer of every household. Streaming services nobody watches anymore, a forgotten cloud backup, a free-trial-turned-monthly-charge — they accumulate, and they’re easy to miss because each one is small. Breadbox tracks them under Recurring — the umbrella for any repeating charge, not just subscriptions: mortgage, rent, insurance, utilities, and loans land here too. A series groups the charges from one merchant so you can see the whole thing as one place. A subscription is just the most familiar kind.
Recurring is in Beta. Find it in the admin dashboard under Recurring (the old /subscriptions URL redirects there), plus the REST API and MCP. The shapes below are stable, but expect the surface to keep growing.

A series is a thin, rule-maintained entity

In Breadbox’s rules-as-substrate model, a series is deliberately minimal:
  • Surrogate identity — a stable id / short_id that survives renames.
  • name — the human label you (or an agent) picked. Unique among live series.
  • typesubscription, bill, loan, or other.
That’s it. There’s no shipped detector, no cadence inference, no expected-amount field, no candidate/active/paused/cancelled lifecycle. Membership is exactly the set of charges its assign_series rules match — a series is its governing rules. The admin Recurring detail page makes that explicit: it shows the linked charges side-by-side with the governing rules that define them.

Auto-join charges with a rule

To make every charge from a merchant join a series on sync, use the assign_series rule action. The recurrence idiom — amount approx + day_of_month approx — is the durable way to express a recurring pattern:
{
  "name": "Spotify → subscription series",
  "conditions": {
    "and": [
      { "field": "provider_merchant_name", "op": "contains", "value": "Spotify" },
      { "field": "amount", "op": "approx", "value": 10.99, "tolerance": 1.00 },
      { "field": "day_of_month", "op": "approx", "value": 14, "tolerance": 2 }
    ]
  },
  "actions": [
    { "type": "assign_series", "series_name": "Spotify", "create_if_missing": true },
    { "type": "add_tag", "tag_slug": "streaming" }
  ],
  "trigger": "on_create",
  "stage": "standard"
}
How the action resolves:
  • series_name + create_if_missing: true mints the series the first time a charge matches; every future charge with the same series_name joins the existing one (surrogate-first — the same name always resolves the same series).
  • Provide series_short_id instead to target a series that already exists.
  • A transaction belongs to at most one series. assign_series is NULL-fill only — it never steals a charge already in another series. Across the pipeline, the highest-priority rule wins.
To tag every member of the subscription (e.g. streaming, work-tools), bundle the add_tag action into the same rule. Members get the tag at sync time and on retroactive apply.
Series tags as a separate, inherited surface have been removed. Tag a series by adding an add_tag action to the same rule that does assign_series, or author a separate rule that matches the same conditions.

Back-fill existing charges

Once the rule is in place, future syncs handle themselves. To pull in charges that already exist, apply the rule retroactively:
curl -X POST \
  -H "X-API-Key: bb_your_key" \
  http://localhost:8080/api/v1/rules/rule_abc123/apply
Retroactive apply materializes assign_series (and every other state-mutating action) through both the single-rule and the bulk apply-all paths. You can also link a charge by hand from the admin Recurring page, or with the assign_series MCP tool for a one-off assignment.

Working with series from an agent

The same surface is available over MCP, which is how a scheduled reviewer agent can keep your subscription list tidy:
  • list_series — list every live series (name, type, charge count). Lean by default.
  • get_series — fetch one series’ name and type by short ID or UUID. Its linked charges come from query_transactions(series_id=...).
  • assign_series — a one-off link/mint for transactions an agent has already decided about. For durable patterns, the agent should author an assign_series rule instead.
  • update_series — rename a series or change its type.
  • unlink_series_transactions — detach charges from a series (inverse of assign_series’ link path).
See the MCP tools page for the agent-facing summary.

Auditing what you spend

Once your subscriptions are series:
  • See the portfolio. The Recurring page lists every live series with its name, type, and charge count, and the detail view shows the linked charges plus the governing rules behind them.
  • Total the outflow. Query the transactions linked to your active monthly series (query_transactions(series_id=...)) and sum their amounts. Keep each iso_currency_code separate — don’t mix currencies.
  • Spot creep. A set_metadata rule can stamp the expected price into the transaction’s metadata blob; reviewing actuals against it surfaces silent price hikes.

Deleting a series

Removing a series is non-destructive — its transactions stay exactly where they are and simply lose the series link. Your history is never deleted. To stop new charges from joining, disable or delete the assign_series rules that govern it.
  • Rules — the assign_series action and the full rule DSL.
  • Understanding rules — the recurrence idiom (amount approx + day_of_month approx) explained.
  • MCP tools — the series tools an agent can call.
  • On-demand analysis — ask Claude “which of my subscriptions are underused?” once they’re tracked.
Last modified on June 25, 2026