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

# Transaction Ledger

> Paginated wallet transaction history.

**How to call** — **GET** `{server}/api/v1/business/wallet/transactions` with `X-API-Key` and optional `page`, `limit`.




## OpenAPI

````yaml /openapi-business.yaml get /api/v1/business/wallet/transactions
openapi: 3.1.0
info:
  title: UGiftMe REST API
  description: >
    REST API for B2B integrations under `/api/v1/business`.


    **Authentication**

    - All documented endpoints require `X-API-Key` (and respect IP whitelisting
    when configured on the key).


    **Async orders**

    When enabled, `POST /orders` may return **202** with `orderRequestId` and
    `status: queued`. Poll `GET /orders/order-requests/{id}`.


    For narrative guides see the **API Guide** documentation page.


    **Error responses**

    Failures return JSON with at least an `error` string. Many endpoints add
    optional fields such as

    `message`, `reason`, `validEvents`, or `details` depending on context. There
    is no global

    `success` / `action` / `code` / `timestamp` envelope on business API routes.

    **`403 Forbidden`** is returned for IP allow-list blocks, incomplete
    business profiles on `/auth`,

    or when the authenticated account cannot access the requested resource.
  version: 1.0.0
  contact:
    name: UGiftMe Developer Support
    email: support@ugift.me
servers:
  - url: https://api-stage.ugift.me
    description: Sandbox
  - url: https://api.ugift.me
    description: Production
security:
  - ApiKeyAuth: []
tags:
  - name: Authentication
    description: API key validation
  - name: Product Catalog
    description: Catalog (API key)
  - name: Orders & Dispatch
    description: Create and list orders (API key)
  - name: Financials
    description: Balances and transactions (API key)
  - name: Webhooks
    description: Outbound webhook registration (API key)
paths:
  /api/v1/business/wallet/transactions:
    get:
      tags:
        - Financials
      summary: Transaction Ledger
      description: >
        Paginated wallet transaction history.


        **How to call** — **GET** `{server}/api/v1/business/wallet/transactions`
        with `X-API-Key` and optional `page`, `limit`.
      operationId: getWalletTransactions
      parameters:
        - $ref: '#/components/parameters/Page'
        - name: limit
          in: query
          schema:
            type: integer
        - name: currency
          in: query
          description: Optional filter — must be one of GBP, USD, EUR, NGN
          schema:
            type: string
            enum:
              - GBP
              - USD
              - EUR
              - NGN
      responses:
        '200':
          description: Transaction history
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WalletTransactionsResponse'
        '400':
          $ref: '#/components/responses/ValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'
components:
  parameters:
    Page:
      name: page
      in: query
      schema:
        type: integer
        minimum: 1
        default: 1
  schemas:
    WalletTransactionsResponse:
      type: object
      required:
        - transactions
        - pagination
      properties:
        transactions:
          type: array
          items:
            $ref: '#/components/schemas/WalletTransactionEntry'
        pagination:
          type: object
          required:
            - currentPage
            - totalPages
            - totalTransactions
            - limit
          properties:
            currentPage:
              type: integer
              example: 1
            totalPages:
              type: integer
              example: 1
            totalTransactions:
              type: integer
              example: 12
            limit:
              type: integer
              example: 50
      example:
        transactions:
          - transactionType: purchase
            transactionValue: 50
            timestamp: '2025-04-12T14:22:10.000Z'
            orderID: 65b0d1e2f3a4b56789012345
            currency: GBP
            details:
              type: single
              currency: GBP
        pagination:
          currentPage: 1
          totalPages: 1
          totalTransactions: 12
          limit: 50
    WalletTransactionEntry:
      type: object
      properties:
        transactionType:
          type: string
          enum:
            - funding
            - withdrawal
            - purchase
            - external_payment
          example: purchase
        transactionValue:
          type: number
          example: 50
        timestamp:
          type: string
          format: date-time
          example: '2025-04-12T14:22:10.000Z'
        orderID:
          description: Associated order id(s), if any.
          oneOf:
            - type: string
            - type: array
              items:
                type: string
          example: 65b0d1e2f3a4b56789012345
        details:
          type: object
          additionalProperties: true
          example:
            type: single
            recipients: 1
            currency: GBP
            description: Received voucher from account
        currency:
          type: string
          description: >-
            Set when merging transactions across wallets in the account listing
            endpoint.
          example: GBP
      example:
        transactionType: purchase
        transactionValue: 50
        timestamp: '2025-04-12T14:22:10.000Z'
        orderID: 65b0d1e2f3a4b56789012345
        details:
          type: single
          recipients: 1
          currency: GBP
          description: Account order debit
        currency: GBP
    ValidationErrorBody:
      description: >
        Client or validation failure. Always includes `error`; optional
        `message` and endpoint-specific fields.
      oneOf:
        - $ref: '#/components/schemas/ApiErrorWithMessage'
        - $ref: '#/components/schemas/WebhookValidationError'
    UnauthorizedErrorBody:
      description: Missing or invalid `X-API-Key`.
      oneOf:
        - $ref: '#/components/schemas/UnauthorizedMissingApiKey'
        - $ref: '#/components/schemas/UnauthorizedInvalidApiKey'
    AccessDeniedError:
      type: object
      description: >
        Access denied — IP not on the key allow list, incomplete/unverified
        business profile on GET /auth,

        or insufficient permission to the resource (e.g. webhook owned by
        another account).
      required:
        - error
      properties:
        error:
          type: string
        ip:
          type: string
          description: Caller IP when blocked by the key allow list
        whitelistedIps:
          type: array
          items:
            type: string
        status:
          type: string
          description: Business verification or profile status (`GET /auth`)
        missingFields:
          type: array
          items:
            type: string
        message:
          type: string
      additionalProperties: true
    NotFoundError:
      type: object
      required:
        - error
      properties:
        error:
          type: string
        message:
          type: string
          description: Additional context (when provided)
      example:
        error: Order not found
        message: Order not found or access denied
    RateLimitError:
      type: object
      required:
        - error
      properties:
        error:
          type: string
          description: >
            Rate-limit message depends on the route limiter (products, webhooks,
            wallet, etc.).
      example:
        error: Too many product access attempts, please try again later.
    InternalServerError:
      type: object
      required:
        - error
      properties:
        error:
          type: string
          description: Route-specific failure summary
        message:
          type: string
          description: Additional detail (common on webhook and wallet routes)
        details:
          type: string
          description: Additional detail (used on some product catalog routes)
      example:
        error: An error occurred
        message: Optional server detail
    ApiErrorWithMessage:
      type: object
      description: Validation and client errors often add a `message` with more context.
      required:
        - error
      properties:
        error:
          type: string
        message:
          type: string
          description: Additional detail about the failure
      example:
        error: Some required fields are missing
        message: >-
          All fields are required: productCode, merchant, currency,
          valuePurchased
    WebhookValidationError:
      type: object
      required:
        - error
      properties:
        error:
          type: string
        message:
          type: string
        validEvents:
          type: array
          items:
            type: string
      example:
        error: Invalid event types
        message: events must be a non-empty array
        validEvents:
          - order.queued
          - order.processing
          - order.succeeded
          - order.failed
          - product.updated
          - wallet.updated
    UnauthorizedMissingApiKey:
      type: object
      required:
        - error
      properties:
        error:
          type: string
          example: Missing API key
    UnauthorizedInvalidApiKey:
      type: object
      required:
        - error
      properties:
        error:
          type: string
          example: Invalid API key
        reason:
          type: string
          description: Why the key failed validation (when available)
          example: Key has been revoked
  responses:
    ValidationError:
      description: >
        Validation error — required fields missing, invalid format, or business
        rule failure.

        Always includes `error`; many responses also include `message` and
        endpoint-specific fields.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ValidationErrorBody'
          examples:
            orderMissingFields:
              summary: POST /orders — required body fields
              value:
                error: Some required fields are missing
                message: >-
                  All fields are required: productCode, merchant, currency,
                  valuePurchased
            orderIdempotencyConflict:
              summary: POST /orders — idempotency key reuse
              value:
                error: Some required fields are missing
                message: Idempotency-Key reuse with different payload is not allowed
            orderCurrencyMismatch:
              summary: POST /orders — currency mismatch
              value:
                error: Product currency does not match original order currency
                message: Order currency (USD) does not match product currency (GBP)
            webhookInvalidUrl:
              summary: POST /webhooks — invalid URL
              value:
                error: Invalid webhook URL
            webhookInvalidEvents:
              summary: POST /webhooks — invalid events
              value:
                error: Invalid event types
                message: events must be a non-empty array
                validEvents:
                  - order.queued
                  - order.processing
                  - order.succeeded
                  - order.failed
                  - product.updated
                  - wallet.updated
            walletInvalidCurrency:
              summary: GET /wallet/transactions — invalid currency filter
              value:
                error: Some required fields are missing
                message: 'Currency must be one of: GBP, USD, EUR, NGN'
    Unauthorized:
      description: >
        Authentication failed — missing, invalid, or (for some routes)
        unresolvable API key context.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/UnauthorizedErrorBody'
          examples:
            missingApiKey:
              summary: No X-API-Key header
              value:
                error: Missing API key
            invalidApiKey:
              summary: Key failed validation
              value:
                error: Invalid API key
                reason: Key has been revoked
    AccessDenied:
      description: >
        Access denied (HTTP 403). Common causes: caller IP not on the key allow
        list, business profile incomplete

        or unverified on GET /auth, or the authenticated account cannot access
        the resource

        (e.g. another account's webhook).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/AccessDeniedError'
          example:
            error: IP not whitelisted
            ip: 203.0.113.10
            whitelistedIps:
              - 198.51.100.0/24
          examples:
            ipNotWhitelisted:
              summary: IP allow list (products, wallet, orders, webhooks)
              value:
                error: IP not whitelisted
                ip: 203.0.113.10
                whitelistedIps:
                  - 198.51.100.0/24
            incompleteBusinessProfile:
              summary: GET /auth — profile incomplete
              value:
                error: Incomplete business profile
                status: incomplete
                missingFields:
                  - businessPhoneNumber
                  - registrationNumber
            businessNotVerified:
              summary: GET /auth — verification pending
              value:
                error: Business verification pending
                status: pending
                message: Complete business verification process
            webhookAccessDenied:
              summary: PATCH or DELETE /webhooks/{id} — wrong account
              value:
                error: You are forbidden from accessing this resource
    NotFound:
      description: Resource not found or not accessible to the authenticated account
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/NotFoundError'
          example:
            error: Wallet not found
          examples:
            product:
              summary: POST /orders — product not found
              value:
                error: Product not found
            order:
              summary: GET /orders/{orderId}
              value:
                error: Order not found
                message: Order not found or access denied
            orderRequest:
              summary: GET /orders/order-requests/{id}
              value:
                error: Order request not found or access denied
            webhook:
              summary: PATCH or DELETE /webhooks/{id}
              value:
                error: Webhook not found
            wallet:
              summary: GET /wallet, /wallet/balance, or /wallet/transactions
              value:
                error: Wallet not found
    RateLimited:
      description: >
        Rate limit exceeded for the route's limiter. Response body is `{
        "error": "<message>" }`.

        Standard rate-limit headers are included when the limiter supports them.
      headers:
        retry-after:
          description: Seconds to wait before retrying
          schema:
            type: integer
            example: 60
        RateLimit-Limit:
          description: Maximum requests allowed in the window
          schema:
            type: integer
            example: 100
        RateLimit-Remaining:
          description: Remaining requests in the current window
          schema:
            type: integer
            example: 0
        RateLimit-Reset:
          description: Unix timestamp when the window resets
          schema:
            type: integer
            example: 1713187200
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/RateLimitError'
          examples:
            productCatalog:
              summary: Product catalog limiter
              value:
                error: Too many product access attempts, please try again later.
            webhooks:
              summary: Webhook configuration limiter
              value:
                error: >-
                  Too many webhook configuration attempts, please try again
                  later.
            wallet:
              summary: Wallet / sensitive-operation limiter
              value:
                error: Too many sensitive operations, please try again later.
    InternalError:
      description: >
        Unexpected server error. Usually `{ "error": "An error occurred" }` from
        the business router,

        or a route-specific failure message with optional `message` / `details`.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/InternalServerError'
          examples:
            generic:
              summary: Business router fallback
              value:
                error: An error occurred
                message: An error occurred
            products:
              summary: GET /products failure
              value:
                error: Failed to fetch one or more products
                message: Connection timeout
            productFilters:
              summary: GET /products/filters failure
              value:
                error: Failed to fetch filters
                details: Connection timeout
            webhooks:
              summary: POST /webhooks failure
              value:
                error: Failed to register webhook
                message: Database error
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
      description: |
        Your UGiftMe API key for authentication.

        **Format**: Secure API key (e.g., `<your-api-key>`)

        **Required**: All endpoints require this header

        Example: `X-API-Key: <your-api-key>`

````