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

# Transaction Monitoring

> List, filter, and manage transactions using the Rain SDK. Build dashboards and reconciliation flows with typed transaction data.

Use the SDK to build transaction views, reconciliation pipelines, or alerting systems. This guide covers listing, filtering, and updating transactions.

## List transactions

Fetch transactions with optional filters for company, user, card, date range, and type:

<CodeGroup>
  ```ts TypeScript theme={null}
  const transactions = await client.transactions.list({
    companyId: 'company_123',
    type: ['spend'],
    authorizedAfter: '2025-01-01',
    limit: 25,
  });

  for (const txn of transactions) {
    if (txn.type === 'spend') {
      console.log(txn.spend.merchantName, txn.spend.amount, txn.spend.status);
    }
  }
  ```

  ```go Go theme={null}
  package main

  import (
  	"context"
  	"fmt"
  	"time"

  	rainsdk "github.com/SignifyHQ/rain-sdk-go"
  	"github.com/SignifyHQ/rain-sdk-go/option"
  )

  func main() {
  	client := rainsdk.NewClient(option.WithAPIKey("YOUR_API_KEY"))

  	after, _ := time.Parse(time.RFC3339, "2025-01-01T00:00:00Z")
  	transactions, err := client.Transactions.List(context.TODO(), rainsdk.TransactionListParams{
  		CompanyID:       rainsdk.String("company_123"),
  		Type:            []string{"spend"},
  		AuthorizedAfter: rainsdk.Time(after),
  		Limit:           rainsdk.Int(25),
  	})
  	if err != nil {
  		panic(err)
  	}

  	for _, txn := range *transactions {
  		switch v := txn.AsAny().(type) {
  		case rainsdk.IssuingTransactionSpend:
  			fmt.Println(v.Spend.MerchantName, v.Spend.Amount, v.Spend.Status)
  		}
  	}
  }
  ```

  ```python Python theme={null}
  transactions = client.transactions.list(
      company_id="company_123",
      type=["spend"],
      authorized_after="2025-01-01",
      limit=25,
  )

  for txn in transactions:
      if txn.type == "spend":
          print(txn.spend.merchant_name, txn.spend.amount, txn.spend.status)
  ```
</CodeGroup>

In Go, `Transactions.List` returns `*[]rainsdk.IssuingTransactionUnion`. Use `txn.AsAny()` to switch over the concrete variant (`IssuingTransactionSpend`, `IssuingTransactionCollateral`, `IssuingTransactionPayment`, `IssuingTransactionFee`), or call accessors like `txn.AsSpend()` directly when you only care about one type.

Rain has four transaction types:

| Type         | Description                                                    |
| ------------ | -------------------------------------------------------------- |
| `spend`      | Card purchases — includes merchant details, amount, and status |
| `collateral` | On-chain deposits and withdrawals                              |
| `payment`    | Balance payments (statement payoffs)                           |
| `fee`        | Platform fees charged to the company or user                   |

Each type has its own nested object (e.g., `txn.spend`, `txn.collateral`) with type-specific fields.

## Filter by date range

Use `authorizedAfter`, `authorizedBefore`, `postedAfter`, and `postedBefore` to scope results:

<CodeGroup>
  ```ts TypeScript theme={null}
  const recentTxns = await client.transactions.list({
    userId: 'user_123',
    authorizedAfter: '2025-03-01',
    authorizedBefore: '2025-03-31',
    type: ['spend', 'fee'],
  });
  ```

  ```go Go theme={null}
  after, _ := time.Parse(time.RFC3339, "2025-03-01T00:00:00Z")
  before, _ := time.Parse(time.RFC3339, "2025-03-31T00:00:00Z")

  recentTxns, err := client.Transactions.List(context.TODO(), rainsdk.TransactionListParams{
  	UserID:           rainsdk.String("user_123"),
  	AuthorizedAfter:  rainsdk.Time(after),
  	AuthorizedBefore: rainsdk.Time(before),
  	Type:             []string{"spend", "fee"},
  })
  ```

  ```python Python theme={null}
  recent_txns = client.transactions.list(
      user_id="user_123",
      authorized_after="2025-03-01",
      authorized_before="2025-03-31",
      type=["spend", "fee"],
  )
  ```
</CodeGroup>

In Go, date filters are `param.Opt[time.Time]` — parse strings with `time.Parse` and wrap with `rainsdk.Time(...)`.

## Paginate through results

For large result sets, use cursor-based pagination:

<CodeGroup>
  ```ts TypeScript theme={null}
  let cursor: string | undefined;

  do {
    const page = await client.transactions.list({
      companyId: 'company_123',
      limit: 100,
      cursor,
    });

    for (const txn of page) {
      // process each transaction
    }

    cursor = page.length === 100 ? page[page.length - 1].id : undefined;
  } while (cursor);
  ```

  ```go Go theme={null}
  var cursor param.Opt[string]

  for {
  	page, err := client.Transactions.List(context.TODO(), rainsdk.TransactionListParams{
  		CompanyID: rainsdk.String("company_123"),
  		Limit:     rainsdk.Int(100),
  		Cursor:    cursor,
  	})
  	if err != nil {
  		panic(err)
  	}

  	for range *page {
  		// process each transaction
  	}

  	if len(*page) < 100 {
  		break
  	}
  	cursor = rainsdk.String((*page)[len(*page)-1].ID)
  }
  ```

  ```python Python theme={null}
  cursor = None

  while True:
      page = client.transactions.list(
          company_id="company_123",
          limit=100,
          cursor=cursor,
      )

      for txn in page:
          pass  # process each transaction

      if len(page) == 100:
          cursor = page[-1].id
      else:
          break
  ```
</CodeGroup>

See [Configuration — Pagination](/sdks/configuration#pagination) for more details.

## Get transaction details

Retrieve a single transaction by ID:

<CodeGroup>
  ```ts TypeScript theme={null}
  const txn = await client.transactions.retrieve('txn_123');

  if (txn.type === 'spend') {
    console.log(`${txn.spend.merchantName}: $${(txn.spend.amount / 100).toFixed(2)}`);
    console.log(`Card: ${txn.spend.cardId}, Status: ${txn.spend.status}`);
  }
  ```

  ```go Go theme={null}
  txn, err := client.Transactions.Get(context.TODO(), "txn_123")
  if err != nil {
  	panic(err)
  }

  if spend := txn.AsSpend(); spend.JSON.Spend.Valid() {
  	fmt.Printf("%s: $%.2f\n", spend.Spend.MerchantName, float64(spend.Spend.Amount)/100)
  	fmt.Printf("Card: %s, Status: %s\n", spend.Spend.CardID, spend.Spend.Status)
  }
  ```

  ```python Python theme={null}
  txn = client.transactions.retrieve("txn_123")

  if txn.type == "spend":
      print(f"{txn.spend.merchant_name}: ${txn.spend.amount / 100:.2f}")
      print(f"Card: {txn.spend.card_id}, Status: {txn.spend.status}")
  ```
</CodeGroup>

## Update a transaction

Add a memo to a transaction for internal tracking:

<CodeGroup>
  ```ts TypeScript theme={null}
  await client.transactions.update('txn_123', {
    memo: 'Team offsite dinner — approved by finance',
  });
  ```

  ```go Go theme={null}
  err := client.Transactions.Update(context.TODO(), "txn_123", rainsdk.TransactionUpdateParams{
  	Memo: rainsdk.String("Team offsite dinner — approved by finance"),
  })
  ```

  ```python Python theme={null}
  client.transactions.update(
      "txn_123",
      memo="Team offsite dinner — approved by finance",
  )
  ```
</CodeGroup>

To attach a receipt, upload it through the receipt sub-resource:

<CodeGroup>
  ```ts TypeScript theme={null}
  import fs from 'fs';

  await client.transactions.receipt.upload('txn_123', {
    receipt: fs.createReadStream('/path/to/receipt.pdf'),
  });
  ```

  ```go Go theme={null}
  f, err := os.Open("/path/to/receipt.pdf")
  if err != nil {
  	panic(err)
  }
  defer f.Close()

  err = client.Transactions.Receipt.Upload(context.TODO(), "txn_123", rainsdk.TransactionReceiptUploadParams{
  	Receipt: f,
  })
  ```

  ```python Python theme={null}
  with open("/path/to/receipt.pdf", "rb") as f:
      client.transactions.receipt.upload(
          "txn_123",
          receipt=f,
      )
  ```
</CodeGroup>

## React to transactions in real time

Use the SDK to pull data from the API. For real-time transaction events, configure [webhooks](/docs/webhooks) in the Dashboard. Rain sends notifications for authorization requests, status changes, and settlements.

<Info>
  For real-time authorization decisions (approve/decline), see [Authorizing Transactions](/docs/authorizing-transactions). This requires a webhook endpoint, not the SDK.
</Info>

## What's next

<Columns cols={3}>
  <Card title="Viewing Transactions" icon="list" href="/docs/viewing-transactions">
    Full guide to transaction data and reporting fields.
  </Card>

  <Card title="Transaction Lifecycle" icon="arrows-spin" href="/docs/transaction-lifecycle">
    How transactions flow from authorization to settlement.
  </Card>

  <Card title="Reporting Fields" icon="table" href="/docs/reporting-field-descriptions">
    Reference for all transaction export fields.
  </Card>
</Columns>
