> ## 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.

# List Transactions

> Returns a paginated list of transactions with sorting and filtering

<Info>
  All transactions are returned through a single endpoint regardless of payment method. Results are sorted by the selected field and paginated using cursors.
</Info>

## Sorting

Use `sort_by` and `sort_order` to control result ordering:

| sort\_by     | Description                         |
| ------------ | ----------------------------------- |
| `created_at` | Transaction creation time (default) |
| `updated_at` | Last update time                    |
| `amount`     | Transaction amount in cents         |

Both `asc` and `desc` are supported for `sort_order` (default: `desc`).

## Filtering

<AccordionGroup>
  <Accordion title="By Payment Method" icon="credit-card">
    Use `payment_method=QR_PH` or `payment_method=CARD_PRESENT` to filter by payment type.

    ```
    GET /v1/transactions?payment_method=CARD_PRESENT
    ```
  </Accordion>

  <Accordion title="By Merchant" icon="store">
    Use `merchant_id` with the UUID from `/v1/merchants`.

    ```
    GET /v1/transactions?merchant_id=57846d47-d196-5c48-a881-4003b1d5aa98
    ```
  </Accordion>

  <Accordion title="By Branch" icon="code-branch">
    Use `branch_id` with the UUID from `/v1/branches`.

    ```
    GET /v1/transactions?branch_id=f3febca6-7bd2-5d10-bcd7-1f796088e90c
    ```
  </Accordion>

  <Accordion title="By Date Range" icon="calendar">
    Use `date_from` and `date_to` with RFC 3339 timestamps.

    ```
    GET /v1/transactions?date_from=2026-01-01T00:00:00Z&date_to=2026-01-31T23:59:59Z
    ```
  </Accordion>

  <Accordion title="By Status" icon="circle-check">
    Use `status` with comma-separated values.

    ```
    GET /v1/transactions?status=CAPTURED,PENDING
    ```
  </Accordion>

  <Accordion title="By Activation Code" icon="barcode">
    Use `activation_code` to filter by terminal device identifier.

    ```
    GET /v1/transactions?activation_code=XXXX-XXXX-XXXX-XXXX
    ```
  </Accordion>
</AccordionGroup>

## Pagination

Results are cursor-paginated. Use `page_size` (default 20, max 100) and the `next_cursor` from the response:

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

# Next page
GET /v1/transactions?page_size=10&cursor=eyJzb3J0X2J5Ijoi...
```

<Tip>
  Cursors are tied to the `sort_by` field. Changing `sort_by` between pages will return a `400` error — start a new query instead.
</Tip>

## Next Steps

<CardGroup cols={2}>
  <Card title="Get Transaction" icon="magnifying-glass" href="/api-reference/transaction-reporting/get-transaction">
    Retrieve full detail for a single transaction
  </Card>

  <Card title="List Merchants" icon="store" href="/api-reference/transaction-reporting/list-merchants">
    Get merchant UUIDs for filtering
  </Card>
</CardGroup>


## OpenAPI

````yaml api-reference/transaction-reporting/openapi.json GET /v1/transactions
openapi: 3.0.3
info:
  title: Transaction Reporting API
  description: >-
    Unified REST API for querying transaction history across all payment
    methods. Provides entity-scoped data isolation with cursor-based pagination.


    **Entity Hierarchy:** Partner → Merchant → Branch → Terminal → Transaction.
    All data access is scoped to the authenticated API key's entity level.


    **Cursor Pagination:** All list endpoints use opaque cursor-based
    pagination. Default page size is 20, maximum is 100.


    **Sorting:** Transactions can be sorted by `created_at` (default),
    `updated_at`, or `amount` in ascending or descending order.


    **Unified Response Model:** All transactions use the same `amount_details`
    schema regardless of payment method. The canonical GTV field is
    `amount_received`.
  version: 1.1.0
  contact:
    name: API Support
    email: support@moduluslabs.io
  license:
    name: Proprietary
servers:
  - url: https://api.sbx.moduluslabs.io/reports
    description: Sandbox
security:
  - ApiKeyAuth: []
tags:
  - name: Transactions
    description: Transaction queries and reporting
  - name: Entities
    description: Merchant and branch listing
  - name: Health
    description: Health check endpoints
paths:
  /v1/transactions:
    get:
      tags:
        - Transactions
      summary: List transactions
      description: >-
        Returns a unified transaction stream from both all payment sources.

        Results are merge-sorted by the selected `sort_by` field and
        `sort_order`.


        **Both databases are always queried** (even with `payment_method=QR_PH`)
        to include

        richer QRPH shadow copies from the card_present database. The CP repo

        automatically filters to the correct `transaction_type`.


        **Entity scoping:** Results are automatically filtered to the
        authenticated API

        key's entity hierarchy.
      operationId: listTransactions
      parameters:
        - $ref: '#/components/parameters/MerchantId'
        - $ref: '#/components/parameters/BranchId'
        - $ref: '#/components/parameters/ActivationCode'
        - $ref: '#/components/parameters/PaymentMethod'
        - $ref: '#/components/parameters/CardBrand'
        - $ref: '#/components/parameters/Status'
        - $ref: '#/components/parameters/DateFrom'
        - $ref: '#/components/parameters/DateTo'
        - $ref: '#/components/parameters/SortBy'
        - $ref: '#/components/parameters/SortOrder'
        - $ref: '#/components/parameters/PageSize'
        - $ref: '#/components/parameters/Cursor'
      responses:
        '200':
          description: Successful response with transaction list
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TransactionListResponse'
        '207':
          description: |
            Partial content — one database circuit breaker is open.
            Check `X-Degraded` header for unavailable source.
          headers:
            X-Degraded:
              $ref: '#/components/headers/X-Degraded'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TransactionListResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
components:
  parameters:
    MerchantId:
      name: merchant_id
      in: query
      required: false
      description: >
        Filter by logical merchant UUID from the Merchant Registry.

        Works cross-DB — returns transactions from both databases if the
        merchant exists in both.
      schema:
        type: string
        format: uuid
    BranchId:
      name: branch_id
      in: query
      required: false
      description: >-
        Filter by logical branch UUID from the Merchant Registry. Works
        cross-DB.
      schema:
        type: string
        format: uuid
    ActivationCode:
      name: activation_code
      in: query
      required: false
      description: >
        Filter by terminal activation code. Works cross-DB.

        Activation codes are device identifiers (printed on hardware), not
        secrets.
      schema:
        type: string
    PaymentMethod:
      name: payment_method
      in: query
      required: false
      description: Filter by payment method. Omit to query both databases.
      schema:
        type: string
        enum:
          - QR_PH
          - CARD_PRESENT
    CardBrand:
      name: card_brand
      in: query
      required: false
      description: Filter by card brand.
      schema:
        type: string
        enum:
          - VISA
          - MASTERCARD
    Status:
      name: status
      in: query
      required: false
      description: Comma-separated list of canonical transaction statuses.
      schema:
        type: string
      example: CAPTURED,PENDING
    DateFrom:
      name: date_from
      in: query
      required: false
      description: Start of date range (inclusive, RFC 3339).
      schema:
        type: string
        format: date-time
    DateTo:
      name: date_to
      in: query
      required: false
      description: End of date range (inclusive, RFC 3339).
      schema:
        type: string
        format: date-time
    SortBy:
      name: sort_by
      in: query
      required: false
      description: |
        Field to sort by. Default: `created_at`.
        Cursor pagination works correctly across all sort fields.
      schema:
        type: string
        enum:
          - created_at
          - updated_at
          - amount
        default: created_at
    SortOrder:
      name: sort_order
      in: query
      required: false
      description: 'Sort direction. Default: desc.'
      schema:
        type: string
        enum:
          - asc
          - desc
        default: desc
    PageSize:
      name: page_size
      in: query
      required: false
      description: Number of items per page.
      schema:
        type: integer
        minimum: 1
        maximum: 100
        default: 20
    Cursor:
      name: cursor
      in: query
      required: false
      description: Opaque cursor token from a previous response's `next_cursor` field.
      schema:
        type: string
  schemas:
    TransactionListResponse:
      type: object
      required:
        - data
        - pagination
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/Transaction'
        pagination:
          $ref: '#/components/schemas/PaginationMeta'
    Transaction:
      type: object
      required:
        - id
        - status
        - amount
        - currency
        - payment_method
        - created_at
        - updated_at
      properties:
        id:
          type: string
          description: Transaction business key.
        status:
          $ref: '#/components/schemas/TransactionStatus'
        amount:
          type: integer
          format: int64
          description: Amount in smallest currency unit (cents).
        currency:
          type: string
          example: PHP
        payment_method:
          type: string
          enum:
            - QR_PH
            - CARD_PRESENT
          description: Always QR_PH for QRPH, CARD_PRESENT for card-present.
        card_brand:
          type: string
          nullable: true
          description: Card brand. Null for QR payments.
        card_last_four:
          type: string
          nullable: true
          description: Last four digits. Only for CARD_PRESENT.
        correlation_id:
          type: string
          nullable: true
        amount_details:
          $ref: '#/components/schemas/AmountDetails'
        receipt:
          $ref: '#/components/schemas/Receipt'
        merchant_details:
          $ref: '#/components/schemas/MerchantDetails'
        terminal_details:
          $ref: '#/components/schemas/TerminalDetails'
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
    PaginationMeta:
      type: object
      required:
        - page_size
        - has_more
      properties:
        page_size:
          type: integer
          example: 20
        has_more:
          type: boolean
          example: true
        next_cursor:
          type: string
          nullable: true
    Error:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          required:
            - code
            - message
          properties:
            code:
              type: string
            message:
              type: string
    TransactionStatus:
      type: string
      enum:
        - CAPTURED
        - PENDING
        - AUTHORIZED
        - DECLINED
        - VOIDED
        - REFUNDED
        - EXPIRED
        - CANCELLED
        - PARTIALLY_REFUNDED
        - FAILED
    AmountDetails:
      type: object
      description: >
        Unified amount breakdown. The top 4 fields are always present regardless
        of

        payment source. The bottom 3 are QRPH-specific tax breakdown (additional
        context).

        **Canonical GTV field: `amount_received`.**
      properties:
        amount_authorized:
          type: integer
          format: int64
          description: Authorized amount in cents. Always present.
        amount_capturable:
          type: integer
          format: int64
          description: Capturable amount in cents. Always present.
        amount_received:
          type: integer
          format: int64
          description: Received/captured amount in cents. Always present. **Use for GTV.**
        amount_refunded:
          type: integer
          format: int64
          description: Refunded amount in cents. Always present.
        original_amount:
          type: integer
          format: int64
          nullable: true
          description: Original amount before tax in cents (QRPH only).
        tax_amount:
          type: integer
          format: int64
          nullable: true
          description: Tax amount in cents (QRPH only).
        final_amount:
          type: integer
          format: int64
          nullable: true
          description: Final amount after tax in cents (QRPH only).
    Receipt:
      type: object
      description: Receipt and reference data (fields vary by source).
      properties:
        receipt_number:
          type: string
          nullable: true
          description: Receipt number (QRPH).
        auth_number:
          type: string
          nullable: true
          description: Authorization number (QRPH).
        batch_number:
          type: string
          nullable: true
          description: Batch number (QRPH).
        approval_code:
          type: string
          nullable: true
          description: Approval code (card_present).
        reference_number:
          type: string
          nullable: true
          description: Reference number (card_present).
    MerchantDetails:
      type: object
      required:
        - merchant_name
      properties:
        merchant_id:
          type: string
          format: uuid
          nullable: true
          description: Stable logical merchant UUID from the Merchant Registry.
        partner_name:
          type: string
          nullable: true
        merchant_name:
          type: string
        branch_id:
          type: string
          format: uuid
          nullable: true
          description: Stable logical branch UUID from the Merchant Registry.
        branch_name:
          type: string
          nullable: true
    TerminalDetails:
      type: object
      properties:
        terminal_name:
          type: string
          nullable: true
        activation_code:
          type: string
          nullable: true
        serial_number:
          type: string
          nullable: true
  headers:
    X-Degraded:
      description: >-
        Indicates which database source is unavailable. Present only on 207
        responses.
      schema:
        type: string
        enum:
          - qrph
          - card_present
  responses:
    Unauthorized:
      description: Missing or invalid API key.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Forbidden:
      description: Entity hierarchy does not permit access.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    RateLimited:
      description: Rate limit exceeded (enforced by APISIX).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    InternalError:
      description: Unhandled server error.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    ServiceUnavailable:
      description: Both database circuit breakers are open, or registry unavailable.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
      description: >
        API key for authentication. Verified by APISIX via Vanguard.

        APISIX injects identity headers and strips the raw key before
        forwarding.

````