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

# Filtering & Sorting

> Query parameters for filtering, sorting, and paginating transaction data

## Overview

The `/v1/transactions` endpoint supports a rich set of query parameters. All filters are optional and can be combined.

```bash theme={null}
GET /v1/transactions?merchant_id={uuid}&status=CAPTURED&date_from=2026-01-01T00:00:00Z&sort_by=amount&sort_order=desc&page_size=50
```

## Filters

### Payment Method

Filter by how the customer paid:

| Value          | Description                     |
| -------------- | ------------------------------- |
| `QR_PH`        | QR code payments                |
| `CARD_PRESENT` | Card payments (EMV, swipe, tap) |

```bash theme={null}
GET /v1/transactions?payment_method=CARD_PRESENT
```

<Info>
  Omit `payment_method` to get both QR and card-present transactions in a single response.
</Info>

### Merchant

Filter by merchant using the UUID from `/v1/merchants`:

```bash theme={null}
GET /v1/transactions?merchant_id=57846d47-d196-5c48-a881-4003b1d5aa98
```

### Branch

Filter by branch using the UUID from `/v1/branches`:

```bash theme={null}
GET /v1/transactions?branch_id=f3febca6-7bd2-5d10-bcd7-1f796088e90c
```

### Terminal

Filter by terminal using the activation code (the physical device identifier):

```bash theme={null}
GET /v1/transactions?activation_code=XXXX-XXXX-XXXX-XXXX
```

### Status

Filter by one or more transaction statuses (comma-separated):

```bash theme={null}
# Single status
GET /v1/transactions?status=CAPTURED

# Multiple statuses
GET /v1/transactions?status=CAPTURED,PENDING,AUTHORIZED
```

| Status               | Description                  |
| -------------------- | ---------------------------- |
| `CAPTURED`           | Payment completed            |
| `AUTHORIZED`         | Authorized, not yet captured |
| `PENDING`            | Awaiting completion          |
| `DECLINED`           | Declined by processor        |
| `VOIDED`             | Cancelled before settlement  |
| `REFUNDED`           | Fully refunded               |
| `PARTIALLY_REFUNDED` | Partially refunded           |
| `FAILED`             | Payment failed               |
| `EXPIRED`            | Payment expired              |
| `CANCELLED`          | Payment cancelled            |

### Card Brand

Filter by card brand (card-present transactions only):

```bash theme={null}
GET /v1/transactions?card_brand=VISA
```

Accepted values: `VISA`, `MASTERCARD`

### Date Range

Filter by transaction creation date using RFC 3339 timestamps:

```bash theme={null}
# Transactions in January 2026
GET /v1/transactions?date_from=2026-01-01T00:00:00Z&date_to=2026-01-31T23:59:59Z

# Transactions from a specific date onward
GET /v1/transactions?date_from=2026-04-15T00:00:00Z
```

<Tip>
  Both `date_from` and `date_to` are optional. Use one or both to define the range.
</Tip>

## Sorting

Control the order of results with `sort_by` and `sort_order`:

| Parameter    | Values                               | Default      |
| ------------ | ------------------------------------ | ------------ |
| `sort_by`    | `created_at`, `updated_at`, `amount` | `created_at` |
| `sort_order` | `asc`, `desc`                        | `desc`       |

```bash theme={null}
# Newest first (default)
GET /v1/transactions

# Oldest first
GET /v1/transactions?sort_by=created_at&sort_order=asc

# Highest amount first
GET /v1/transactions?sort_by=amount&sort_order=desc

# Most recently updated
GET /v1/transactions?sort_by=updated_at&sort_order=desc
```

## Pagination

Results are cursor-paginated for efficient traversal of large datasets.

### Parameters

| Parameter   | Type    | Default  | Max |
| ----------- | ------- | -------- | --- |
| `page_size` | integer | 20       | 100 |
| `cursor`    | string  | *(none)* | —   |

### How It Works

1. Make your initial request with `page_size`:

```bash theme={null}
GET /v1/transactions?page_size=10
```

2. The response includes pagination metadata:

```json theme={null}
{
  "data": [...],
  "pagination": {
    "page_size": 10,
    "has_more": true,
    "next_cursor": "eyJzb3J0X2J5IjoiY3Jl..."
  }
}
```

3. Pass `next_cursor` to get the next page:

```bash theme={null}
GET /v1/transactions?page_size=10&cursor=eyJzb3J0X2J5IjoiY3Jl...
```

4. Continue until `has_more` is `false`.

<Warning>
  **Don't change `sort_by` between pages.** Cursors are tied to the sort field used when the cursor was created. Changing `sort_by` mid-pagination returns a `400` error. Start a new query instead.
</Warning>

### Combining Filters with Pagination

All filters work with pagination. The cursor remembers the full filter context:

```bash theme={null}
# Page 1: captured transactions for a merchant, sorted by amount
GET /v1/transactions?merchant_id={uuid}&status=CAPTURED&sort_by=amount&sort_order=desc&page_size=20

# Page 2: same filters, next cursor
GET /v1/transactions?merchant_id={uuid}&status=CAPTURED&sort_by=amount&sort_order=desc&page_size=20&cursor=eyJ...
```

## Amount Details

Every transaction includes a consistent `amount_details` object with amounts in the smallest currency unit (cents):

```json theme={null}
{
  "amount_details": {
    "amount_authorized": 16052,
    "amount_capturable": 0,
    "amount_received": 16052,
    "amount_refunded": 0
  }
}
```

| Field               | Description                        |
| ------------------- | ---------------------------------- |
| `amount_authorized` | Amount authorized by the processor |
| `amount_capturable` | Amount available for capture       |
| `amount_received`   | Amount actually received           |
| `amount_refunded`   | Amount refunded to customer        |

<Tip>
  **Calculating GTV:** Filter by `status=CAPTURED` and sum `amount_received` across all pages. This gives you the Gross Transaction Value for the filtered period.
</Tip>

## Error Responses

Invalid filter values return `400 Bad Request`:

```json theme={null}
{
  "error": {
    "code": "BAD_REQUEST",
    "message": "invalid status: INVALID_STATUS"
  }
}
```

Common errors:

* Unknown query parameter → `"unknown query parameter: foo"`
* Invalid status value → `"invalid status: INVALID"`
* Invalid date format → `"invalid date_from: must be RFC 3339"`
* Invalid sort field → `"invalid sort_by: must be created_at, updated_at, or amount"`

## What's Next?

<CardGroup cols={2}>
  <Card title="API Reference" icon="code" href="/api-reference/transaction-reporting/list-transactions">
    Full endpoint reference with request/response schemas
  </Card>

  <Card title="Authentication" icon="key" href="/docs/transaction-reporting/authentication">
    API keys and entity scoping
  </Card>
</CardGroup>
