> ## Documentation Index
> Fetch the complete documentation index at: https://breadbox-mintlify-7401d007.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Transaction read MCP reference

> MCP read tools for querying, counting, summarizing transactions and reading comments, matches, and annotations.

The core read surface of Breadbox. Agents query transactions, aggregate spending, and read activity context through the tools on this page. All amounts use the Plaid sign convention: positive = money out, negative = money in. See [Conventions](/mcp/reference/conventions) for the full cross-cutting rules.

***

## query\_transactions

Returns a paginated list of transactions matching the supplied filters. This is the workhorse read tool — almost every agent session goes through it.

**Scope:** Read

**Mirrors:** [`GET /api/v1/transactions`](/api/overview)

### Parameters

<ParamField path="start_date" type="string (YYYY-MM-DD)">
  Start date inclusive.
</ParamField>

<ParamField path="end_date" type="string (YYYY-MM-DD)">
  End date exclusive.
</ParamField>

<ParamField path="account_id" type="string">
  Filter to a single account (UUID or short ID).
</ParamField>

<ParamField path="user_id" type="string">
  Filter to all accounts owned by a family member. Attribution-aware — includes transactions attributed to this user via account links.
</ParamField>

<ParamField path="category_slug" type="string">
  Filter by category slug. Parent slugs include all children.
</ParamField>

<ParamField path="min_amount" type="number">
  Minimum amount (positive = debit, negative = credit).
</ParamField>

<ParamField path="max_amount" type="number">
  Maximum amount.
</ParamField>

<ParamField path="pending" type="boolean">
  Filter by pending status. Omit to return both.
</ParamField>

<ParamField path="flagged" type="boolean">
  Filter to flagged transactions (`true`) or unflagged (`false`). Omit to return both. Use `flagged=true` to retrieve transactions you (or an agent) marked for follow-up via `update_transactions`.
</ParamField>

<ParamField path="search" type="string">
  Case-insensitive substring match on `name` and `merchant_name`. Comma-separate values for OR.
</ParamField>

<ParamField path="search_mode" type="string" default="contains">
  `contains`, `words`, or `fuzzy`.
</ParamField>

<ParamField path="exclude_search" type="string">
  Exclude transactions whose name or merchant matches this text.
</ParamField>

<ParamField path="tags" type="array of strings">
  Tags the transaction must have (AND). The review queue is `["needs-review"]`.
</ParamField>

<ParamField path="any_tag" type="array of strings">
  Tags the transaction must have at least one of (OR).
</ParamField>

<ParamField path="limit" type="integer" default="50">
  Max 500.
</ParamField>

<ParamField path="cursor" type="string">
  Opaque pagination cursor from a previous response. Only valid with `sort_by=date`.
</ParamField>

<ParamField path="sort_by" type="string" default="date">
  `date`, `amount`, or `provider_name`.
</ParamField>

<ParamField path="sort_order" type="string" default="desc">
  `desc` or `asc`.
</ParamField>

<ParamField path="fields" type="string">
  Comma-separated fields or aliases (`minimal`, `core`, `category`, `timestamps`). See [Conventions](/mcp/reference/conventions#fields-aliases). `id` is always included.
</ParamField>

<ParamField path="count_only" type="boolean" default="false">
  When `true`, return only `{"count": N}` for the given filters — no rows, no pagination. `cursor`, `limit`, `sort_by`, `sort_order`, and `fields` are ignored. Use this to size a result set or compare counts across date ranges or categories before paginating. Replaces the retired `count_transactions` tool.
</ParamField>

### Example input

```json theme={null}
{
  "start_date": "2026-03-01",
  "end_date": "2026-04-01",
  "category_slug": "food_and_drink_groceries",
  "fields": "core,category",
  "limit": 100
}
```

<Accordion title="Example output" icon="braces">
  ```json theme={null}
  {
    "transactions": [
      {
        "id": "k7Xm9pQ2",
        "date": "2026-03-28",
        "amount": 67.43,
        "name": "WHOLE FOODS MARKET #10452",
        "iso_currency_code": "USD",
        "category": {
          "slug": "food_and_drink_groceries",
          "display_name": "Groceries",
          "primary_slug": "food_and_drink",
          "primary_display_name": "Food and Drink"
        },
        "category_primary_raw": "FOOD_AND_DRINK",
        "category_detailed_raw": "FOOD_AND_DRINK_GROCERIES"
      }
    ],
    "next_cursor": "eyJkYXRlIjoiMjAyNi0wMy0yOCIsImlkIjoiazdYbTlwUTIifQ",
    "has_more": true,
    "limit": 100
  }
  ```
</Accordion>

***

## Counting matches: `query_transactions(count_only=true)`

There is no separate `count_transactions` tool. To get just a count for a given set of filters, pass `count_only: true` to `query_transactions` with the same filters you'd otherwise use. The response is `{"count": N}` with no rows, no pagination, and no cursor — `cursor`, `limit`, `sort_by`, `sort_order`, and `fields` are ignored. Agents use this as a cheap pre-flight to decide whether to paginate or narrow filters.

**Scope:** Read

**Mirrors:** [`GET /api/v1/transactions/count`](/api/overview)

### Example input

```json theme={null}
{
  "start_date": "2026-01-01",
  "end_date": "2026-04-01",
  "category_slug": "food_and_drink_groceries",
  "count_only": true
}
```

### Example output

```json theme={null}
{ "count": 128 }
```

***

## transaction\_summary

Returns aggregated transaction totals grouped by category, month, week, day, or category × month. Replaces the need to paginate through every transaction for spending analysis. Amounts follow the Plaid convention — positive = money out.

**Scope:** Read

**Mirrors:** [`GET /api/v1/transactions/summary`](/api/overview)

### Parameters

<ParamField path="group_by" type="string" required>
  One of `category`, `month`, `week`, `day`, `category_month`.
</ParamField>

<ParamField path="start_date" type="string (YYYY-MM-DD)">
  Defaults to 30 days ago.
</ParamField>

<ParamField path="end_date" type="string (YYYY-MM-DD)">
  Defaults to today.
</ParamField>

<ParamField path="account_id" type="string">
  Filter by account.
</ParamField>

<ParamField path="user_id" type="string">
  Filter by family member (attribution-aware).
</ParamField>

<ParamField path="category" type="string">
  Filter by primary category before aggregating.
</ParamField>

<ParamField path="include_pending" type="boolean" default="false">
  Include pending transactions.
</ParamField>

### Example input

```json theme={null}
{
  "group_by": "category",
  "start_date": "2026-03-01",
  "end_date": "2026-04-01"
}
```

<Accordion title="Example output" icon="braces">
  ```json theme={null}
  {
    "summary": [
      {
        "category": "food_and_drink_groceries",
        "total_amount": 843.21,
        "transaction_count": 34,
        "iso_currency_code": "USD"
      },
      {
        "category": "transportation_gas",
        "total_amount": 312.50,
        "transaction_count": 18,
        "iso_currency_code": "USD"
      }
    ],
    "totals": {
      "total_amount": 1155.71,
      "transaction_count": 52
    },
    "filters": {
      "start_date": "2026-03-01",
      "end_date": "2026-04-01",
      "group_by": "category"
    }
  }
  ```
</Accordion>

***

## list\_annotations

Returns the activity timeline for a single transaction: comments, tag adds/removes, rule applications, and category sets. Ordered by `created_at` ascending. Use this to reconstruct "what happened to this transaction and when" before making further changes.

Each row carries a generic `kind` plus an `action` for the specific event, so you can branch on the action without parsing the kind string:

| `kind`     | `action` values     | Notes                                                                                        |
| ---------- | ------------------- | -------------------------------------------------------------------------------------------- |
| `comment`  | *(omitted)*         | Free-form comment. `payload.content` carries the body.                                       |
| `rule`     | `applied`           | A transaction rule fired. `payload.rule_name` and `rule_id` are populated.                   |
| `tag`      | `added` / `removed` | Tag attached to or detached from the transaction. `tag_id` and `payload.slug` are populated. |
| `category` | `set`               | Category was set (manual override or via rule).                                              |

**Scope:** Read

### Parameters

<ParamField path="transaction_id" type="string" required>
  UUID or short ID of the transaction.
</ParamField>

<ParamField path="kinds" type="string[]">
  Optional kind filter. Any of `comment`, `rule`, `tag`, `category`. Empty (default) returns the full timeline. Pass `['comment']` for the comment-only view (replaces the deprecated `list_transaction_comments`); pass `['tag']` for both add and remove tag events; pass `['comment','tag','category']` to skip rule-application churn.

  Only the generic kinds above are accepted at the MCP boundary — the underlying DB-level values (`tag_added`, `tag_removed`, `rule_applied`, `category_set`) will be rejected with an `invalid kind` error.
</ParamField>

### Example input

```json theme={null}
{ "transaction_id": "k7Xm9pQ2" }
```

Comment-only view (replaces `list_transaction_comments`):

```json theme={null}
{ "transaction_id": "k7Xm9pQ2", "kinds": ["comment"] }
```

All tag events (added and removed):

```json theme={null}
{ "transaction_id": "k7Xm9pQ2", "kinds": ["tag"] }
```

<Accordion title="Example output" icon="braces">
  ```json theme={null}
  [
    {
      "id": "a1Xm2pQ9",
      "transaction_id": "k7Xm9pQ2",
      "kind": "tag",
      "action": "added",
      "actor_type": "system",
      "actor_name": "system",
      "tag_id": "t1Xm9pQ2",
      "payload": { "slug": "needs-review" },
      "created_at": "2026-03-28T06:00:00Z"
    },
    {
      "id": "a2Yn3qR0",
      "transaction_id": "k7Xm9pQ2",
      "kind": "category",
      "action": "set",
      "actor_type": "agent",
      "actor_name": "Review Agent",
      "session_id": "s9Xm2pQk",
      "payload": {
        "category_slug": "food_and_drink_groceries",
        "note": "clearly groceries"
      },
      "created_at": "2026-03-29T10:12:00Z"
    },
    {
      "id": "a3Zo4rS1",
      "transaction_id": "k7Xm9pQ2",
      "kind": "tag",
      "action": "removed",
      "actor_type": "agent",
      "actor_name": "Review Agent",
      "session_id": "s9Xm2pQk",
      "tag_id": "t1Xm9pQ2",
      "payload": { "slug": "needs-review", "note": "clearly groceries" },
      "created_at": "2026-03-29T10:12:00Z"
    }
  ]
  ```
</Accordion>

<Note>
  `kind` carries the generic event family (`comment`, `rule`, `tag`, `category`) and `action` carries the specific event (`added`, `removed`, `set`, `applied`). Comment rows omit `action` because there is only one event. Actor identity is split across `actor_type` (`user` / `agent` / `system`), `actor_name`, and optional `actor_id`. When a write tool passed a `session_id`, it's echoed here so you can group events by session. Rule applications set `rule_id`; tag events set `tag_id`.
</Note>
