> ## Documentation Index
> Fetch the complete documentation index at: https://docs.baanx.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Transaction Management

> Query transaction history, apply filters, and generate statements

## Overview

The Transaction API provides comprehensive access to card transaction history with powerful filtering, pagination, and statement generation capabilities. View detailed transaction information including merchant details, amounts, fees, and crypto funding sources.

<Info>
  Transactions are returned in reverse chronological order (most recent first) for easy access to recent activity.
</Info>

## Transaction Data Structure

Each transaction includes detailed information across multiple dimensions:

<CardGroup cols={3}>
  <Card title="Transaction Details" icon="receipt">
    ID, timestamp, merchant, type, MCC category
  </Card>

  <Card title="Financial Data" icon="dollar-sign">
    Amounts, fees, currencies, conversion rates
  </Card>

  <Card title="Funding Sources" icon="wallet">
    Crypto wallets, networks, transaction hashes
  </Card>
</CardGroup>

### Sample Transaction

```json theme={null}
{
  "id": "100a99cf-f4d3-4fa1-9be9-2e9828b20ebb",
  "cardId": "1234537292209260487",
  "panLast4": "9189",
  "transactionId": "1122334477422",
  "dateTime": "2024-10-14T10:44:36.276Z",
  "sign": "DEBIT",
  "merchantNameLocation": "WWW.ALIEXPRESS.COM, LONDON",
  "merchantType": "OutOfWalletOnline",
  "mcc": 5964,
  "mccCategory": "MISC",
  "transactionCurrency": "EUR",
  "amountInTransactionCurrency": "0.79",
  "feesInTransactionCurrency": "0",
  "originalCurrency": "USD",
  "amountInOriginalCurrency": "0.85",
  "feesInOriginalCurrency": "0",
  "billingConversionRate": "0.9294117647058824",
  "ecbRate": "0.9161704076958315",
  "status": "CONFIRMED",
  "declineReason": "",
  "fundingSources": [
    {
      "id": "3181a37a-07fa-41dc-b423-6c2db07a7ba1",
      "address": "0x3a11a86cf218c448be519728cd3ac5c741fb3424",
      "network": "linea",
      "txHash": "0xb92de09d893e8162b0861c0f7321f68df02212efbc58f208839ae3f176d89638",
      "currency": "usdc",
      "amount": "0.104201",
      "fees": "0",
      "swapFee": "0.00208",
      "sign": "DEBIT",
      "status": "CONFIRMED",
      "dateTime": "2024-10-14T10:44:36.288Z"
    }
  ]
}
```

## Fetching Transaction History

### Basic Request

<CodeGroup>
  ```javascript JavaScript/Node.js theme={null}
  const response = await fetch('https://dev.api.baanx.com/v1/card/transactions', {
    headers: {
      'X-Client-ID': 'your_client_id',
      'Authorization': `Bearer ${userAccessToken}`
    }
  });

  const transactions = await response.json();
  console.log(`Retrieved ${transactions.length} transactions`);
  ```

  ```python Python theme={null}
  import requests

  response = requests.get(
      'https://dev.api.baanx.com/v1/card/transactions',
      headers={
          'X-Client-ID': 'your_client_id',
          'Authorization': f'Bearer {user_access_token}'
      }
  )

  transactions = response.json()
  print(f'Retrieved {len(transactions)} transactions')
  ```

  ```bash cURL theme={null}
  curl -X GET https://dev.api.baanx.com/v1/card/transactions \
    -H "X-Client-ID: your_client_id" \
    -H "Authorization: Bearer YOUR_USER_ACCESS_TOKEN"
  ```
</CodeGroup>

### With Pagination

```javascript theme={null}
// Fetch page 2 (0-indexed, so page=1 is actually the second page)
const response = await fetch(
  'https://dev.api.baanx.com/v1/card/transactions?page=1',
  {
    headers: {
      'X-Client-ID': clientId,
      'Authorization': `Bearer ${accessToken}`
    }
  }
);

const transactions = await response.json();
```

<Note>
  Pages are 0-indexed. `page=0` is the first page, `page=1` is the second page, etc. If you request a page that doesn't exist, it returns page 0 (first page).
</Note>

## Filtering Transactions

### By Date Range

Filter transactions within a specific time period:

<CodeGroup>
  ```javascript JavaScript/Node.js theme={null}
  const params = new URLSearchParams({
    dateFrom: '2024-10-01',
    dateTo: '2024-10-31'
  });

  const response = await fetch(
    `https://dev.api.baanx.com/v1/card/transactions?${params}`,
    {
      headers: {
        'X-Client-ID': clientId,
        'Authorization': `Bearer ${accessToken}`
      }
    }
  );

  const transactions = await response.json();
  ```

  ```python Python theme={null}
  params = {
      'dateFrom': '2024-10-01',
      'dateTo': '2024-10-31'
  }

  response = requests.get(
      'https://dev.api.baanx.com/v1/card/transactions',
      headers={
          'X-Client-ID': client_id,
          'Authorization': f'Bearer {access_token}'
      },
      params=params
  )

  transactions = response.json()
  ```

  ```bash cURL theme={null}
  curl -X GET "https://dev.api.baanx.com/v1/card/transactions?dateFrom=2024-10-01&dateTo=2024-10-31" \
    -H "X-Client-ID: your_client_id" \
    -H "Authorization: Bearer YOUR_USER_ACCESS_TOKEN"
  ```
</CodeGroup>

<ParamField query="dateFrom" type="string">
  Start date in ISO 8601 format (YYYY-MM-DD). Required if `dateTo` is specified.

  Example: `2024-10-01`
</ParamField>

<ParamField query="dateTo" type="string">
  End date in ISO 8601 format (YYYY-MM-DD). Required if `dateFrom` is specified.

  Example: `2024-10-31`
</ParamField>

<Warning>
  Both `dateFrom` and `dateTo` must be provided together. Specifying only one will result in an error.
</Warning>

### By Merchant Name

Search for transactions from specific merchants:

```javascript theme={null}
const params = new URLSearchParams({
  searchKey: 'PayPal'
});

const response = await fetch(
  `https://dev.api.baanx.com/v1/card/transactions?${params}`,
  {
    headers: {
      'X-Client-ID': clientId,
      'Authorization': `Bearer ${accessToken}`
    }
  }
);
```

<ParamField query="searchKey" type="string">
  Search term to filter merchant names. Case-insensitive partial match.

  Example: `"PayPal"`, `"Amazon"`, `"Starbucks"`
</ParamField>

### By Category

Filter by merchant category code (MCC) category:

```javascript theme={null}
const params = new URLSearchParams({
  mccCategories: 'FOOD,TRAVEL'
});

const response = await fetch(
  `https://dev.api.baanx.com/v1/card/transactions?${params}`,
  {
    headers: {
      'X-Client-ID': clientId,
      'Authorization': `Bearer ${accessToken}`
    }
  }
);
```

<ParamField query="mccCategories" type="string">
  Comma-separated list of categories to filter by.

  **Available Categories:**

  * `SUBSCRIPTIONS`: Streaming services, memberships
  * `FOOD`: Restaurants, groceries, delivery
  * `TRAVEL`: Hotels, airlines, car rentals
  * `ENTERTAINMENT`: Movies, concerts, games
  * `HEALTH`: Healthcare, pharmacy, fitness
  * `ATM`: ATM withdrawals
  * `UTILITIES`: Bills, phone, internet
  * `MISC`: Everything else

  Example: `"FOOD,ENTERTAINMENT"`, `"TRAVEL"`
</ParamField>

### Combined Filters

All filters can be combined:

```javascript theme={null}
const params = new URLSearchParams({
  dateFrom: '2024-10-01',
  dateTo: '2024-10-31',
  searchKey: 'uber',
  mccCategories: 'TRAVEL,FOOD',
  page: 0
});

const response = await fetch(
  `https://dev.api.baanx.com/v1/card/transactions?${params}`,
  {
    headers: {
      'X-Client-ID': clientId,
      'Authorization': `Bearer ${accessToken}`
    }
  }
);

// Returns: Uber transactions in October 2024 categorized as TRAVEL or FOOD
```

## Transaction Response Fields

### Core Transaction Fields

<ResponseField name="id" type="string">
  Unique transaction identifier
</ResponseField>

<ResponseField name="cardId" type="string">
  ID of card used for transaction
</ResponseField>

<ResponseField name="panLast4" type="string">
  Last 4 digits of card number
</ResponseField>

<ResponseField name="transactionId" type="string">
  Merchant transaction ID
</ResponseField>

<ResponseField name="dateTime" type="string">
  Transaction timestamp (ISO 8601)
</ResponseField>

<ResponseField name="sign" type="enum">
  Transaction direction: `DEBIT` or `CREDIT`

  * `DEBIT`: Money leaving account (purchase)
  * `CREDIT`: Money entering account (refund, reversal)
</ResponseField>

<ResponseField name="merchantNameLocation" type="string">
  Merchant name and location (e.g., "AMAZON.COM, SEATTLE")
</ResponseField>

<ResponseField name="merchantType" type="string">
  Type of merchant transaction (e.g., "OutOfWalletOnline", "InStoreWithPin")
</ResponseField>

<ResponseField name="mcc" type="number">
  Merchant Category Code (numeric code)
</ResponseField>

<ResponseField name="mccCategory" type="enum">
  Human-readable category: `SUBSCRIPTIONS`, `FOOD`, `TRAVEL`, `ENTERTAINMENT`, `HEALTH`, `ATM`, `UTILITIES`, `MISC`
</ResponseField>

### Financial Fields

<ResponseField name="transactionCurrency" type="string">
  Card currency (e.g., "EUR", "USD")
</ResponseField>

<ResponseField name="amountInTransactionCurrency" type="string">
  Amount charged to card (decimal string)
</ResponseField>

<ResponseField name="feesInTransactionCurrency" type="string">
  Fees charged in card currency (decimal string)
</ResponseField>

<ResponseField name="originalCurrency" type="string">
  Merchant's original currency
</ResponseField>

<ResponseField name="amountInOriginalCurrency" type="string">
  Original amount in merchant currency
</ResponseField>

<ResponseField name="feesInOriginalCurrency" type="string">
  Fees in original currency
</ResponseField>

<ResponseField name="billingConversionRate" type="string">
  Conversion rate used for billing
</ResponseField>

<ResponseField name="ecbRate" type="string">
  European Central Bank reference rate
</ResponseField>

### Status Fields

<ResponseField name="status" type="enum">
  Transaction status:

  * `CONFIRMED`: Transaction completed successfully
  * `PENDING`: Transaction processing
  * `DECLINED`: Transaction rejected
  * `REVERTED`: Transaction reversed/refunded
</ResponseField>

<ResponseField name="declineReason" type="string" optional>
  Reason for decline (only present when `status: "DECLINED"`)

  Examples: "Insufficient funds", "Invalid PIN", "Card frozen"
</ResponseField>

### Funding Source Fields

<ResponseField name="fundingSources" type="array">
  Array of crypto funding sources used for this transaction

  <Expandable title="Funding Source Object">
    <ResponseField name="id" type="string">
      Funding source identifier
    </ResponseField>

    <ResponseField name="address" type="string">
      Wallet address that funded this transaction
    </ResponseField>

    <ResponseField name="network" type="enum">
      Blockchain network: `linea`, `solana`, `ethereum`
    </ResponseField>

    <ResponseField name="txHash" type="string">
      Blockchain transaction hash
    </ResponseField>

    <ResponseField name="currency" type="string">
      Cryptocurrency used (e.g., "usdc", "usdt")
    </ResponseField>

    <ResponseField name="amount" type="string">
      Amount of crypto used (decimal string)
    </ResponseField>

    <ResponseField name="fees" type="string">
      Network/gas fees
    </ResponseField>

    <ResponseField name="swapFee" type="string">
      Currency conversion fee
    </ResponseField>

    <ResponseField name="sign" type="enum">
      `DEBIT` or `CREDIT`
    </ResponseField>

    <ResponseField name="status" type="enum">
      `CONFIRMED`, `PENDING`, or `DECLINED`
    </ResponseField>

    <ResponseField name="dateTime" type="string">
      Funding transaction timestamp
    </ResponseField>
  </Expandable>
</ResponseField>

## Implementing Transaction History UI

### Basic Transaction List

<CodeGroup>
  ```javascript React Component theme={null}
  import { useState, useEffect } from 'react';

  export function TransactionHistory({ clientId, accessToken }) {
    const [transactions, setTransactions] = useState([]);
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState(null);
    const [page, setPage] = useState(0);

    useEffect(() => {
      fetchTransactions();
    }, [page]);

    async function fetchTransactions() {
      setLoading(true);
      setError(null);

      try {
        const response = await fetch(
          `/v1/card/transactions?page=${page}`,
          {
            headers: {
              'X-Client-ID': clientId,
              'Authorization': `Bearer ${accessToken}`
            }
          }
        );

        if (!response.ok) {
          throw new Error('Failed to fetch transactions');
        }

        const data = await response.json();
        setTransactions(data);
      } catch (err) {
        setError(err.message);
      } finally {
        setLoading(false);
      }
    }

    if (loading) return <div>Loading transactions...</div>;
    if (error) return <div>Error: {error}</div>;

    return (
      <div className="transaction-history">
        <h2>Transaction History</h2>

        <div className="transactions-list">
          {transactions.map((tx) => (
            <TransactionItem key={tx.id} transaction={tx} />
          ))}
        </div>

        <div className="pagination">
          <button
            onClick={() => setPage(Math.max(0, page - 1))}
            disabled={page === 0}
          >
            Previous
          </button>

          <span>Page {page + 1}</span>

          <button
            onClick={() => setPage(page + 1)}
            disabled={transactions.length === 0}
          >
            Next
          </button>
        </div>
      </div>
    );
  }

  function TransactionItem({ transaction }) {
    const isCredit = transaction.sign === 'CREDIT';
    const statusIcon = {
      CONFIRMED: '✅',
      PENDING: '⏳',
      DECLINED: '❌',
      REVERTED: '↩️'
    }[transaction.status];

    return (
      <div className="transaction-item">
        <div className="transaction-merchant">
          <span className="merchant-name">
            {transaction.merchantNameLocation}
          </span>
          <span className="transaction-date">
            {new Date(transaction.dateTime).toLocaleDateString()}
          </span>
        </div>

        <div className="transaction-details">
          <span className="category-badge">
            {transaction.mccCategory}
          </span>
          <span className={`amount ${isCredit ? 'credit' : 'debit'}`}>
            {isCredit ? '+' : '-'}
            {transaction.transactionCurrency} {transaction.amountInTransactionCurrency}
          </span>
          <span className="status">{statusIcon}</span>
        </div>
      </div>
    );
  }
  ```
</CodeGroup>

### With Filters

<CodeGroup>
  ```javascript React Component with Filters theme={null}
  import { useState, useEffect } from 'react';

  export function TransactionHistoryWithFilters({ clientId, accessToken }) {
    const [transactions, setTransactions] = useState([]);
    const [loading, setLoading] = useState(false);
    const [filters, setFilters] = useState({
      dateFrom: '',
      dateTo: '',
      searchKey: '',
      mccCategories: [],
      page: 0
    });

    useEffect(() => {
      fetchTransactions();
    }, [filters]);

    async function fetchTransactions() {
      setLoading(true);

      try {
        const params = new URLSearchParams();

        if (filters.dateFrom) params.append('dateFrom', filters.dateFrom);
        if (filters.dateTo) params.append('dateTo', filters.dateTo);
        if (filters.searchKey) params.append('searchKey', filters.searchKey);
        if (filters.mccCategories.length > 0) {
          params.append('mccCategories', filters.mccCategories.join(','));
        }
        params.append('page', filters.page.toString());

        const response = await fetch(
          `/v1/card/transactions?${params}`,
          {
            headers: {
              'X-Client-ID': clientId,
              'Authorization': `Bearer ${accessToken}`
            }
          }
        );

        const data = await response.json();
        setTransactions(data);
      } catch (err) {
        console.error('Failed to fetch transactions:', err);
      } finally {
        setLoading(false);
      }
    }

    function updateFilter(key, value) {
      setFilters(prev => ({ ...prev, [key]: value, page: 0 }));
    }

    function toggleCategory(category) {
      setFilters(prev => ({
        ...prev,
        mccCategories: prev.mccCategories.includes(category)
          ? prev.mccCategories.filter(c => c !== category)
          : [...prev.mccCategories, category],
        page: 0
      }));
    }

    const categories = [
      'FOOD', 'TRAVEL', 'ENTERTAINMENT', 'SUBSCRIPTIONS',
      'HEALTH', 'UTILITIES', 'ATM', 'MISC'
    ];

    return (
      <div className="transaction-history-with-filters">
        <div className="filters">
          <h3>Filters</h3>

          <div className="date-range">
            <input
              type="date"
              placeholder="From"
              value={filters.dateFrom}
              onChange={(e) => updateFilter('dateFrom', e.target.value)}
            />
            <input
              type="date"
              placeholder="To"
              value={filters.dateTo}
              onChange={(e) => updateFilter('dateTo', e.target.value)}
            />
          </div>

          <div className="search">
            <input
              type="text"
              placeholder="Search merchant..."
              value={filters.searchKey}
              onChange={(e) => updateFilter('searchKey', e.target.value)}
            />
          </div>

          <div className="categories">
            {categories.map(category => (
              <button
                key={category}
                onClick={() => toggleCategory(category)}
                className={filters.mccCategories.includes(category) ? 'active' : ''}
              >
                {category}
              </button>
            ))}
          </div>

          <button onClick={() => setFilters({
            dateFrom: '', dateTo: '', searchKey: '',
            mccCategories: [], page: 0
          })}>
            Clear Filters
          </button>
        </div>

        <div className="transactions">
          {loading ? (
            <div>Loading...</div>
          ) : transactions.length > 0 ? (
            transactions.map(tx => (
              <TransactionItem key={tx.id} transaction={tx} />
            ))
          ) : (
            <div>No transactions found</div>
          )}
        </div>
      </div>
    );
  }
  ```
</CodeGroup>

## Transaction Statements

Generate downloadable transaction statements in CSV or PDF format.

### Generate Statement

<CodeGroup>
  ```javascript JavaScript/Node.js theme={null}
  // Generate CSV statement
  const response = await fetch(
    'https://dev.api.baanx.com/v1/card/transactions/statement?dateFrom=2024-10-01&dateTo=2024-10-31',
    {
      headers: {
        'Accept': 'text/csv',
        'X-Client-ID': clientId,
        'Authorization': `Bearer ${accessToken}`
      }
    }
  );

  const csvData = await response.text();

  // Download as file
  const blob = new Blob([csvData], { type: 'text/csv' });
  const url = URL.createObjectURL(blob);
  const link = document.createElement('a');
  link.href = url;
  link.download = 'transactions-october-2024.csv';
  link.click();
  ```

  ```python Python theme={null}
  import requests

  # Generate PDF statement
  response = requests.get(
      'https://dev.api.baanx.com/v1/card/transactions/statement',
      headers={
          'Accept': 'application/pdf',
          'X-Client-ID': client_id,
          'Authorization': f'Bearer {access_token}'
      },
      params={
          'dateFrom': '2024-10-01',
          'dateTo': '2024-10-31'
      }
  )

  # Save as file
  with open('statement-october-2024.pdf', 'wb') as f:
      f.write(response.content)
  ```

  ```bash cURL (CSV) theme={null}
  curl -X GET "https://dev.api.baanx.com/v1/card/transactions/statement?dateFrom=2024-10-01&dateTo=2024-10-31" \
    -H "Accept: text/csv" \
    -H "X-Client-ID: your_client_id" \
    -H "Authorization: Bearer YOUR_USER_ACCESS_TOKEN" \
    -o transactions.csv
  ```
</CodeGroup>

### Statement Parameters

<ParamField query="dateFrom" type="string" optional>
  Start date for statement (ISO 8601). If omitted, includes all transactions from the beginning.
</ParamField>

<ParamField query="dateTo" type="string" optional>
  End date for statement (ISO 8601). If omitted, includes all transactions up to now.
</ParamField>

<ParamField header="Accept" type="string" required>
  Format for statement:

  * `text/csv`: CSV format
  * `application/pdf`: PDF format
</ParamField>

<Note>
  Unlike the transactions endpoint, you can specify `dateFrom` without `dateTo` (or vice versa) for open-ended date ranges.
</Note>

### CSV Format

```csv theme={null}
Timestamp,Merchant,Merchant Type,Transaction Currency,Transaction currency amount,Card currency,Card currency amount,Funding Tokens,Funding Addresses
2024-10-14T10:44:36.276Z,"WWW.ALIEXPRESS.COM, LONDON",OutOfWalletOnline,USD,0.85,EUR,0.79,"usdc","0x3a11a86cf218c448be519728cd3ac5c741fb3424"
2024-10-13T15:22:11.143Z,"UBER TRIP, NEW YORK",OutOfWalletOnline,USD,15.50,EUR,14.32,"usdc","0x3a11a86cf218c448be519728cd3ac5c741fb3424"
```

### Statement Generation Component

<CodeGroup>
  ```javascript React Component theme={null}
  import { useState } from 'react';

  export function StatementGenerator({ clientId, accessToken }) {
    const [loading, setLoading] = useState(false);
    const [dateFrom, setDateFrom] = useState('');
    const [dateTo, setDateTo] = useState('');
    const [format, setFormat] = useState('csv');

    async function generateStatement() {
      setLoading(true);

      try {
        const params = new URLSearchParams();
        if (dateFrom) params.append('dateFrom', dateFrom);
        if (dateTo) params.append('dateTo', dateTo);

        const response = await fetch(
          `/v1/card/transactions/statement?${params}`,
          {
            headers: {
              'Accept': format === 'csv' ? 'text/csv' : 'application/pdf',
              'X-Client-ID': clientId,
              'Authorization': `Bearer ${accessToken}`
            }
          }
        );

        if (!response.ok) {
          throw new Error('Failed to generate statement');
        }

        // Download file
        const blob = await response.blob();
        const url = URL.createObjectURL(blob);
        const link = document.createElement('a');
        link.href = url;
        link.download = `statement-${dateFrom || 'all'}-${dateTo || 'latest'}.${format}`;
        link.click();
        URL.revokeObjectURL(url);

      } catch (err) {
        console.error('Statement generation failed:', err);
        alert('Failed to generate statement');
      } finally {
        setLoading(false);
      }
    }

    return (
      <div className="statement-generator">
        <h3>Generate Statement</h3>

        <div className="date-range">
          <label>
            From:
            <input
              type="date"
              value={dateFrom}
              onChange={(e) => setDateFrom(e.target.value)}
            />
          </label>

          <label>
            To:
            <input
              type="date"
              value={dateTo}
              onChange={(e) => setDateTo(e.target.value)}
            />
          </label>
        </div>

        <div className="format-selector">
          <label>
            <input
              type="radio"
              value="csv"
              checked={format === 'csv'}
              onChange={(e) => setFormat(e.target.value)}
            />
            CSV
          </label>

          <label>
            <input
              type="radio"
              value="pdf"
              checked={format === 'pdf'}
              onChange={(e) => setFormat(e.target.value)}
            />
            PDF
          </label>
        </div>

        <button
          onClick={generateStatement}
          disabled={loading}
          className="btn-generate"
        >
          {loading ? 'Generating...' : 'Download Statement'}
        </button>

        {!dateFrom && !dateTo && (
          <p className="info-text">
            No date range specified - will include all transactions
          </p>
        )}
      </div>
    );
  }
  ```
</CodeGroup>

## Transaction Analytics

### Spending by Category

```javascript theme={null}
function calculateSpendingByCategory(transactions) {
  const spending = {};

  transactions.forEach(tx => {
    if (tx.status === 'CONFIRMED' && tx.sign === 'DEBIT') {
      const category = tx.mccCategory;
      const amount = parseFloat(tx.amountInTransactionCurrency);

      spending[category] = (spending[category] || 0) + amount;
    }
  });

  return spending;
}

// Usage
const categorySpending = calculateSpendingByCategory(transactions);
// { FOOD: 150.50, TRAVEL: 450.00, ENTERTAINMENT: 75.25, ... }
```

### Monthly Spending Trend

```javascript theme={null}
function calculateMonthlySpending(transactions) {
  const monthlySpend = {};

  transactions.forEach(tx => {
    if (tx.status === 'CONFIRMED' && tx.sign === 'DEBIT') {
      const date = new Date(tx.dateTime);
      const monthKey = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}`;
      const amount = parseFloat(tx.amountInTransactionCurrency);

      monthlySpend[monthKey] = (monthlySpend[monthKey] || 0) + amount;
    }
  });

  return monthlySpend;
}

// Usage
const monthlyTrend = calculateMonthlySpending(transactions);
// { '2024-10': 675.75, '2024-09': 542.30, ... }
```

### Top Merchants

```javascript theme={null}
function getTopMerchants(transactions, limit = 5) {
  const merchantSpend = {};

  transactions.forEach(tx => {
    if (tx.status === 'CONFIRMED' && tx.sign === 'DEBIT') {
      const merchant = tx.merchantNameLocation;
      const amount = parseFloat(tx.amountInTransactionCurrency);

      merchantSpend[merchant] = (merchantSpend[merchant] || 0) + amount;
    }
  });

  return Object.entries(merchantSpend)
    .sort(([, a], [, b]) => b - a)
    .slice(0, limit)
    .map(([merchant, amount]) => ({ merchant, amount }));
}

// Usage
const topMerchants = getTopMerchants(transactions);
// [
//   { merchant: 'AMAZON.COM, SEATTLE', amount: 350.00 },
//   { merchant: 'UBER TRIP, NEW YORK', amount: 125.50 },
//   ...
// ]
```

## Troubleshooting

<AccordionGroup>
  <Accordion title="Empty array returned despite having transactions">
    **Cause**: Invalid page number or filters too restrictive

    **Solution**: Reset to page 0 and verify filters

    ```javascript theme={null}
    // Start from first page
    const response = await fetch('/v1/card/transactions?page=0');

    // Remove filters
    const response = await fetch('/v1/card/transactions');
    ```
  </Accordion>

  <Accordion title="Date range filter returns error">
    **Cause**: Only one of `dateFrom`/`dateTo` specified

    **Solution**: Provide both dates or neither

    ```javascript theme={null}
    // ❌ Bad: Only one date
    ?dateFrom=2024-10-01

    // ✅ Good: Both dates
    ?dateFrom=2024-10-01&dateTo=2024-10-31

    // ✅ Good: No dates (all transactions)
    // (no date parameters)
    ```
  </Accordion>

  <Accordion title="Statement download fails">
    **Cause**: Missing or incorrect Accept header

    **Solution**: Set proper Accept header for desired format

    ```javascript theme={null}
    // For CSV
    headers: {
      'Accept': 'text/csv'
    }

    // For PDF
    headers: {
      'Accept': 'application/pdf'
    }
    ```
  </Accordion>

  <Accordion title="Funding sources array is empty">
    **Cause**: Transaction not yet settled or failed

    **Solution**: Check transaction status

    ```javascript theme={null}
    if (transaction.status === 'PENDING') {
      console.log('Funding sources not yet finalized');
    } else if (transaction.status === 'DECLINED') {
      console.log('Transaction declined - no funding occurred');
    }
    ```
  </Accordion>
</AccordionGroup>

## Best Practices

### Performance

<Check>Implement pagination for large transaction lists</Check>
<Check>Cache recent transactions locally with reasonable TTL</Check>
<Check>Use date filters to limit data transfer</Check>
<Check>Lazy load transaction details on demand</Check>

### User Experience

<Check>Show loading states during fetch</Check>
<Check>Display transaction status clearly (confirmed, pending, declined)</Check>
<Check>Group transactions by date for readability</Check>
<Check>Provide search and filter capabilities</Check>
<Check>Allow statement downloads for record keeping</Check>

### Data Display

<Check>Format amounts with proper decimal places</Check>
<Check>Show currency symbols clearly</Check>
<Check>Display timestamps in user's timezone</Check>
<Check>Use color coding for transaction types (debit/credit)</Check>
<Check>Show funding source details for transparency</Check>

### Error Handling

```javascript theme={null}
async function fetchTransactions(filters) {
  try {
    const response = await fetch(buildTransactionUrl(filters));

    if (!response.ok) {
      if (response.status === 404) {
        return []; // No transactions yet
      }
      throw new Error('Failed to fetch transactions');
    }

    return await response.json();
  } catch (error) {
    console.error('Transaction fetch error:', error);
    // Show user-friendly error message
    throw error;
  }
}
```

## Next Steps

<CardGroup cols={2}>
  <Card title="Card Management" icon="toggle-on" href="/guides/card/management">
    Freeze, unfreeze, and control cards
  </Card>

  <Card title="PIN Operations" icon="lock" href="/guides/card/pin-operations">
    Secure PIN viewing and management
  </Card>

  <Card title="Order Cards" icon="credit-card" href="/guides/card/ordering">
    Issue new virtual cards
  </Card>

  <Card title="API Reference" icon="code" href="/api-reference/card/transactions">
    Complete API documentation
  </Card>
</CardGroup>
