Skip to main content
Transaction rules are condition trees that fire during sync to auto-categorize, tag, or annotate transactions. These read tools let agents inspect the existing rule set and dry-run conditions before creating new rules. See Rule writes for create_transaction_rule (single or batch via the rules array), update_transaction_rule, delete_transaction_rule, and apply_rules.

list_transaction_rules

Lists transaction rules with optional filters. Agents should always call this before creating new rules to avoid duplicates. Returns each rule’s actions, trigger, priority, hit count, and last-hit timestamp — useful for spotting stale or never-matching rules. Scope: Read Mirrors: GET /api/v1/rules

Parameters

category_slug
string
Filter to rules that set this category.
enabled
boolean
true for only enabled, false for only disabled, omit for both.
Search by rule name. Comma-separated values are ORed.
search_mode
string
default:"contains"
contains, words, or fuzzy.
limit
integer
default:"50"
Max 500.
cursor
string
Pagination cursor.

Example input

{ "enabled": true, "search": "starbucks" }
{
  "rules": [
    {
      "id": "r9Xm2pQr",
      "name": "name: Starbucks → food_and_drink_coffee",
      "conditions": {
        "field": "merchant_name",
        "op": "contains",
        "value": "starbucks"
      },
      "actions": [
        { "type": "set_category", "category_slug": "food_and_drink_coffee" }
      ],
      "trigger": "on_create",
      "category_slug": "food_and_drink_coffee",
      "category_display_name": "Coffee",
      "priority": 10,
      "enabled": true,
      "hit_count": 47,
      "last_hit_at": "2026-04-12T14:32:00Z",
      "created_by_type": "user",
      "created_by_id": "u4Xm9pQ2",
      "created_by_name": "Alice",
      "created_at": "2026-01-15T09:00:00Z",
      "updated_at": "2026-01-15T09:00:00Z"
    }
  ],
  "next_cursor": "",
  "has_more": false,
  "total": 1
}

query_transaction_rules

Richer, filterable query over the rule set — the rules analogue of query_transactions. Adds trigger, creator type, hit-count, and unused filters that list_transaction_rules doesn’t expose, plus sorting by impact. Use this to audit coverage (“which agent-created rules have never fired?”) or prune dead rules (only_unused: true) without loading the full roster. Scope: Read Mirrors: GET /api/v1/rules

Parameters

category_slug
string
Filter to rules whose set_category action targets this category slug.
enabled
boolean
true for only enabled, false for only disabled, omit for both.
trigger
string
Filter by firing trigger: on_create, on_change (alias on_update), or always.
creator_type
string
Filter by who created the rule: user, agent, or system.
search
string
Search by rule name. Comma-separated values are ORed.
search_mode
string
default:"contains"
contains, words, or fuzzy.
min_hit_count
integer
Return only rules whose hit_count is at least this value. Surfaces high-impact rules. Ignored when only_unused is true.
only_unused
boolean
When true, return only rules that have never fired (hit_count = 0) — dead or over-specific rules worth reviewing for deletion.
sort_by
string
default:"priority"
Sort column: priority (pipeline execution order), hit_count, last_hit_at, created_at, or name.
sort_order
string
asc or desc. Default per column: desc for hit_count, last_hit_at, created_at; asc for priority and name.
limit
integer
default:"50"
Max 500.
cursor
string
Pagination cursor. Only applies to the default priority sort — an explicit sort_by returns a single top-N page with no next_cursor.
fields
string
Comma-separated fields to include. Omit for the summary projection (name, enabled, priority, trigger, category, hit_count, last_hit_at — no conditions or actions trees). Pass fields=all for every field.

Example — find dead rules

{ "only_unused": true, "sort_by": "created_at", "sort_order": "desc" }

Example — highest-impact rules for a category

{ "category_slug": "food_and_drink_groceries", "sort_by": "hit_count", "limit": 10 }

preview_rule

Dry-run a condition tree against existing transactions — no writes, no hit-count bump. Returns the match count, total scanned, and a sample of matching transactions. Agents use this to test a condition before committing to a rule. Scope: Read
Preview does not simulate the rule pipeline. It evaluates the supplied condition in isolation against stored data. Tags or categories that earlier-stage rules would have added mid-pass are not visible. For questions like “what does this condition match today?” preview is exactly right; for “what would this rule actually categorize once I ship it?”, you still need to create the rule (ideally disabled) and use apply_rules on a scoped filter.

Parameters

conditions
object
required
Condition tree. Same grammar as create_transaction_rule.conditions. Leaf: {"field":"...","op":"...","value":...}. Combinators: {"and":[...]}, {"or":[...]}, {"not":{...}}.
sample_size
integer
default:"10"
Number of sample matching transactions to return. Max 50. The match_count reflects the full match set regardless of sample size.

Example input

{
  "conditions": {
    "and": [
      { "field": "merchant_name", "op": "contains", "value": "starbucks" },
      { "field": "amount", "op": "gte", "value": 5 }
    ]
  },
  "sample_size": 3
}
{
  "match_count": 47,
  "total_scanned": 12540,
  "sample_matches": [
    {
      "transaction_id": "k7Xm9pQ2",
      "date": "2026-04-12",
      "amount": 6.85,
      "name": "STARBUCKS STORE #4591",
      "category_primary_raw": "FOOD_AND_DRINK",
      "current_category_slug": "food_and_drink_coffee"
    },
    {
      "transaction_id": "k8Yn0qR3",
      "date": "2026-04-10",
      "amount": 12.40,
      "name": "STARBUCKS STORE #4591",
      "category_primary_raw": "FOOD_AND_DRINK",
      "current_category_slug": "food_and_drink_coffee"
    },
    {
      "transaction_id": "k9Zo1rS4",
      "date": "2026-04-08",
      "amount": 5.25,
      "name": "STARBUCKS MOBILE ORDER",
      "category_primary_raw": "FOOD_AND_DRINK",
      "current_category_slug": "food_and_drink_coffee"
    }
  ]
}

Condition grammar

Full DSL is in the Breadbox repo’s docs/rule-dsl.md. Short form:
  • Fieldsname, merchant_name, amount, category_primary, category_detailed, category (the assigned slug, live-updated by earlier-stage rules), pending, provider, account_id, account_name, user_id, user_name, tags.
  • Operators
    • String/category: eq, neq, contains, not_contains, matches (RE2), in.
    • Numeric: eq, neq, gt, gte, lt, lte.
    • Bool: eq, neq.
    • Tags: contains, not_contains, in.
  • Combinatorsand, or, not (nest freely, max depth 10).
Pass {} (or omit conditions entirely on rule creation) to match every transaction.

find_matching_rules

Reports which existing active rules already match a given transaction or merchant — the inverse of preview_rule. Call this before creating a rule to answer “is this merchant already covered?” without loading the entire rule set into context. Scope: Read

Parameters

transaction_id
string
A transaction ID or short ID to evaluate the full active rule set against. Every condition field (amount, category, tags, provider, account, …) is checked against the row’s real values. Provide exactly one of transaction_id or merchant.
merchant
string
Free-text merchant name to check name-based rule coverage for. Builds a synthetic context with only the name fields set — rules that condition on amount, category, or tags won’t match and that is the correct, conservative behavior. Provide exactly one of transaction_id or merchant.

Example input

{ "merchant": "Starbucks" }
{
  "matched_count": 1,
  "rules": [
    {
      "short_id": "r9Xm2pQr",
      "name": "name: Starbucks → food_and_drink_coffee",
      "sets_category": "food_and_drink_coffee",
      "trigger": "on_create",
      "priority": 10,
      "enabled": true,
      "hit_count": 47,
      "match_all": false
    }
  ]
}

Response fields

matched_count
integer
Number of matching rules. Zero means no existing rule covers this transaction or merchant — safe to create a new one.
rules
array
Matching rules ordered by priority ascending — the same order the sync pipeline would apply them.
Trigger is not filtered — a rule is reported if its condition matches, regardless of on_create/on_change. This answers coverage questions, not sync-time simulation. A rule with match_all: true covers every transaction but is not a meaningful merchant match.
Last modified on June 25, 2026