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

# List transactions with filters

> List transactions with filters.

Results are ordered newest-first (by createdAt desc, id desc). `limit`
defaults to 50 and is capped at 100.

Date filters `createdAfter` and `createdBefore` are **inclusive**
(treated as `>=` and `<=` against `createdAt`).

Pagination returns opaque `nextCursor` / `previousCursor` tokens in the
response whenever the page is non-empty: use `startingAfter=nextCursor`
to fetch the next page, or `endingBefore=previousCursor` to page
backward. `hasMore` tells the client whether more rows exist in the
current direction of travel; an empty response in the other direction
signals the start of the list.



## OpenAPI

````yaml /api-reference/openapi.yaml get /transactions
openapi: 3.0.3
info:
  title: Polygon OMS Public API
  version: v26.05.28-0001
  description: >-
    Unified API for moving money between crypto and fiat. Three ways to move
    money: Transactions (instant, wallet or card funded, including Cash-In for
    in-person cash deposits), Deposit Addresses (reusable crypto deposit
    configurations), and Virtual Accounts (dedicated bank accounts that
    auto-convert fiat to crypto). Standard transactions follow a two-step flow:
    create a Quote (pricing), then create a Transaction (execution). Cash-in
    codes generate a one-time deposit code for in-person cash deposits at retail
    locations.
  contact:
    name: Polygon OMS
    url: https://oms.polygon.technology
servers:
  - url: https://sandbox-api.polygon.technology/v0.13
    description: Sandbox
  - url: https://api.polygon.technology/v0.13
    description: Production
security:
  - BearerAuth: []
tags:
  - name: Auth
    description: Authentication via FrontEgg
  - name: Customers
    description: Customer management and KYC
  - name: Customer
  - name: Wallet
  - name: Quote
  - name: Transaction
  - name: CashIns
  - name: CashLocation
  - name: Sandbox
  - name: VirtualAccount
  - name: Counterparty
  - name: ExternalAccount
  - name: Reference
  - name: DepositAddress
paths:
  /transactions:
    get:
      tags:
        - Transaction
      summary: List transactions with filters
      description: |-
        List transactions with filters.

        Results are ordered newest-first (by createdAt desc, id desc). `limit`
        defaults to 50 and is capped at 100.

        Date filters `createdAfter` and `createdBefore` are **inclusive**
        (treated as `>=` and `<=` against `createdAt`).

        Pagination returns opaque `nextCursor` / `previousCursor` tokens in the
        response whenever the page is non-empty: use `startingAfter=nextCursor`
        to fetch the next page, or `endingBefore=previousCursor` to page
        backward. `hasMore` tells the client whether more rows exist in the
        current direction of travel; an empty response in the other direction
        signals the start of the list.
      operationId: listTransactions
      parameters:
        - $ref: '#/components/parameters/PaginationParams.limit'
        - $ref: '#/components/parameters/PaginationParams.startingAfter'
        - $ref: '#/components/parameters/PaginationParams.endingBefore'
        - name: status
          in: query
          required: false
          description: Filter by status.
          schema:
            type: array
            items:
              $ref: '#/components/schemas/TransactionStatus'
        - name: sourceToDestination
          in: query
          required: false
          description: Filter by corridor (source/destination category composite).
          schema:
            type: array
            items:
              $ref: '#/components/schemas/SourceToDestination'
        - name: customerId
          in: query
          required: false
          description: >-
            Scope to a customer. Matches rows where the customer is on either
            side

            — the sender (quote owner) or the recipient. Replaces the retired

            `GET /customers/{id}/transactions`. `cst_` prefix.
          schema:
            type: string
        - name: walletId
          in: query
          required: false
          description: >-
            Filter to transactions where this wallet is the source or
            destination

            instrument. Accepts a crypto wallet (`wlt_` prefix; legacy `acc_`
            also

            accepted) or a fiat wallet (`wlt_fiat_` prefix).
          schema:
            type: string
        - name: virtualAccountId
          in: query
          required: false
          description: >-
            Filter to the transaction's originating virtual account. `va_`
            prefix.
          schema:
            type: string
        - name: depositAddressId
          in: query
          required: false
          description: >-
            Filter to the transaction's originating deposit address. `da_`
            prefix.
          schema:
            type: string
        - name: cashInId
          in: query
          required: false
          description: Filter to the transaction's originating cash-in. `ci_` prefix.
          schema:
            type: string
        - name: precursorType
          in: query
          required: false
          description: >-
            Filter by the kind of precursor that originated the transaction.

            Matches transactions where ANY leg carries a precursor of this type

            (consistent with the id filters above). This may differ from the
            single

            `precursor` object rendered on the transaction: when a leg has
            several

            precursor sources, the rendered `precursor` reports one winner by
            fixed

            precedence (depositAddress > virtualAccount > cashIn > quote), so a

            transaction can match e.g. `precursorType=quote` while its rendered

            `precursor.type` is `depositAddress`. `manual` matches a transaction

            with no known origin resource — this includes both a genuine

            out-of-band arrival (rendered `precursor: null`) and a future

            operator-initiated transaction (rendered `{type: manual}`), since

            today's actual data only ever produces the former.

            `reversal` is deferred until reversal automation lands.
          schema:
            $ref: '#/components/schemas/TransactionPrecursorType'
        - name: createdAfter
          in: query
          required: false
          description: Inclusive lower bound on `createdAt`.
          schema:
            type: string
            format: date-time
        - name: createdBefore
          in: query
          required: false
          description: Inclusive upper bound on `createdAt`.
          schema:
            type: string
            format: date-time
        - name: search
          in: query
          required: false
          description: >-
            Free-text search. Matches transaction id, customer id, or customer
            email.
          schema:
            type: string
        - name: q
          in: query
          required: false
          description: Alias for `search`.
          schema:
            type: string
        - name: legStatus
          in: query
          required: false
          description: >-
            Filters to payments where ANY leg's underlying status is in the
            given

            set (e.g. `failed` surfaces outbound-failed-funds-held payments
            whose

            derived overall `status` is still `processing`). Values are
            leg-level

            statuses, a superset of `TransactionStatus`. Only applied under the

            grouped read model; ignored otherwise.
          schema:
            type: array
            items:
              type: string
      responses:
        '200':
          description: The request has succeeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TransactionList'
components:
  parameters:
    PaginationParams.limit:
      name: limit
      in: query
      required: false
      description: >-
        Page size, supported range 1-100. The default and maximum are
        per-resource

        (see each endpoint's description; most endpoints default to

        50) and are resolved at runtime from configuration. Values outside the
        range

        are clamped to the nearest bound rather than rejected. The range is
        published

        machine-readably via the `x-minimum`/`x-maximum` OpenAPI extensions
        below —

        deliberately NOT via `@minValue`/`@maxValue`, which emit JSON-Schema

        `minimum`/`maximum` and make the generated SDK (Zod) reject values the
        server

        accepts and clamps. See `PaginatedList.limit` for the effective value
        applied.
      schema:
        type: integer
        format: int32
      x-maximum: 100
      x-minimum: 1
    PaginationParams.startingAfter:
      name: startingAfter
      in: query
      required: false
      schema:
        type: string
    PaginationParams.endingBefore:
      name: endingBefore
      in: query
      required: false
      schema:
        type: string
  schemas:
    TransactionStatus:
      type: string
      enum:
        - processing
        - awaitingAction
        - completed
        - failed
      description: >-
        Lifecycle of a transaction. processing: funds in motion. awaitingAction:

        non-terminal, blocked on developer/upstream/compliance (see `hold`);
        returns

        to processing once cleared. completed: delivered. failed: terminal
        failure.
    SourceToDestination:
      type: string
      enum:
        - cryptoToCrypto
        - cryptoToCash
        - cryptoToFiatAccount
        - cashToCrypto
        - fiatAccountToCrypto
        - fiatAccountToFiatAccount
      description: >-
        Composite of source and destination instrument categories, inferred

        from each side. The cash corridors

        (`cryptoToCash`, `cashToCrypto`) are derived from a cash-pickup
        destination /

        cash-in source respectively; the rest map straight from the internal
        corridor type.
    TransactionPrecursorType:
      type: string
      enum:
        - quote
        - depositAddress
        - virtualAccount
        - cashIn
        - manual
      description: |-
        The kind of precursor resource that originated a transaction. `reversal`
        is deliberately absent until reversal automation lands (#2141). `manual`
        matches a transaction with no known origin resource — filter parity with
        `precursor: null`/`{type: manual}` on the rendered Transaction (#2660
        second review).
    TransactionList:
      type: object
      properties:
        object:
          type: string
          description: Resource type discriminator.
        limit:
          type: integer
          format: int32
          description: |-
            The effective page size applied to this response, after clamping an
            out-of-range or unset requested `limit` into the supported bound.
        hasMore:
          type: boolean
          description: >-
            True when more rows exist beyond this page in the direction of
            travel (forward by default, backward when `endingBefore` was
            supplied).
        nextCursor:
          type: string
          description: |-
            Opaque cursor pointing at the last item in this page. Present when
            `data` is non-empty. Pass as `startingAfter` to fetch the next page;
            `hasMore=false` signals no more pages forward.
        previousCursor:
          type: string
          description: >-
            Opaque cursor pointing at the first item in this page. Present when

            `data` is non-empty. Pass as `endingBefore` to page backward; when

            this yields an empty response the client is at the start of the
            list.
        data:
          type: array
          items:
            $ref: '#/components/schemas/Transaction'
          description: The page of results.
      description: A paginated list of transactions.
    Transaction:
      type: object
      required:
        - id
        - object
        - status
        - subStatus
        - customerId
        - precursor
        - source
        - destination
        - pricing
      properties:
        id:
          allOf:
            - $ref: '#/components/schemas/typeId'
          description: Transaction ID (`txn_` prefix).
        object:
          type: string
          enum:
            - transaction
          description: Resource type discriminator. Always "transaction".
        sourceToDestination:
          allOf:
            - $ref: '#/components/schemas/SourceToDestination'
          description: Corridor composite derived from the two sides.
        status:
          allOf:
            - $ref: '#/components/schemas/TransactionStatus'
          description: Current lifecycle status. See `subStatus` for finer granularity.
        subStatus:
          allOf:
            - $ref: '#/components/schemas/TransactionSubStatus'
          description: >-
            Status-scoped sub-state (e.g. `processing.fundsPulled`). Always
            present: each

            status carries a default member (e.g. `processing.initiated`) when
            no more

            specific value applies.
        customerId:
          allOf:
            - $ref: '#/components/schemas/typeId'
          description: The owning (sender) customer. OMSX customer TypeID (cst_…).
        customer:
          allOf:
            - $ref: '#/components/schemas/CustomerSummary'
          description: |-
            Resolved id + display name of the owning customer, so list/detail
            rendering needs no follow-up customer fetch (v0.12, #2665).
        precursor:
          type: object
          allOf:
            - $ref: '#/components/schemas/Precursor'
          nullable: true
          description: >-
            What created this transaction, as a uniform `{type, id}` reference —

            dereference the resource by `id` for its full record. `null` for a

            genuine out-of-band arrival with no originating OMS resource at all

            (e.g. funds pushed directly to a wallet from outside OMS); the

            `manual` arm (`id: null`) is reserved for a future
            operator-initiated

            transaction, distinct from an out-of-band arrival.
        source:
          allOf:
            - $ref: '#/components/schemas/TransactionSide'
          description: 'The funding side: a typed instrument carrying identity and detail.'
        destination:
          allOf:
            - $ref: '#/components/schemas/TransactionDestination'
          description: 'The receiving side: a typed instrument plus `payoutOrigin`.'
        pricing:
          allOf:
            - $ref: '#/components/schemas/Pricing'
          description: Consolidated economics.
        estimatedArrival:
          type: string
          format: date-time
          description: >-
            Estimated completion time. Present when the destination rail has a
            predictable

            settlement time (e.g. bank payouts and some crypto legs); null
            otherwise.
        error:
          allOf:
            - $ref: '#/components/schemas/SettlementError'
          description: >-
            Failure detail. Set when the transaction fails; includes refund or
            recovery state

            where applicable.
        hold:
          allOf:
            - $ref: '#/components/schemas/Hold'
          description: >-
            Present while status is `awaitingAction`; explains the hold +
            deadline.

            Populated when the hold model is wired.
        metadata:
          type: object
          additionalProperties:
            type: string
          description: Free-form key-value pairs supplied at creation or update.
        createdAt:
          type: string
          format: date-time
          description: When the transaction was created.
        updatedAt:
          type: string
          format: date-time
          description: When the transaction was last updated.
        expiresAt:
          type: string
          format: date-time
          description: >-
            Expiry of the transaction's actionable window: present on
            auto-created transactions

            and on cash payouts (the pickup-code expiry), and retained after
            completion for audit.

            Null for other quote-initiated transactions.
        projectId:
          allOf:
            - $ref: '#/components/schemas/omsxProjectId'
          description: >-
            The owning project. Populated only on the cross-project admin
            endpoints (e.g. GET /admin/transactions/redrivable) so operators can
            tell which project a stranded transaction belongs to. Omitted on
            partner endpoints, where the project is implicit from the auth
            token.
      description: >-
        A single movement of money from a source to a destination. Created by
        accepting a quote, or generated automatically by a deposit address,
        virtual account, or cash-in. Track its progress with status.
    typeId:
      type: string
      pattern: >-
        ^[a-z]+_([0-9a-hjkmnp-tv-z]{26}|[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$
      description: >-
        Public TypeID, e.g. `txn_01h455vb4pex5vsknk084sn02q`; legacy UUID
        suffixes are accepted until non-v7 rows are retired.
      x-go-type: string
    TransactionSubStatus:
      type: string
      enum:
        - processing.fundsPulled
        - processing.cashPickupReady
        - processing.underReview
        - completed.cashPickupCollected
        - completed.cashPickupExpired
        - awaitingAction.awaitingSenderAttribution
        - awaitingAction.depositAddressFrozen
        - awaitingAction.depositAddressInactive
        - failed.attributionTimeout
        - failed.depositAddressFrozenTimeout
        - failed.depositAddressInactiveTimeout
        - failed.depositAddressClosed
        - processing.awaitingCryptoOut
        - processing.cryptoOut
        - processing.awaitingFiatOut
        - processing.fiatOut
        - processing.inboundPending
        - processing.inboundProcessing
        - failed.inboundFailed
        - failed.returnPending
        - failed.returnStarted
        - failed.returnComplete
        - failed.returnFailed
        - processing.initiated
        - awaitingAction.held
        - completed.settled
        - failed.unspecified
        - failed.expired
        - failed.outboundFailed
      description: >-
        Finer-grained, status-scoped sub-state of a transaction (v0.10). Each
        member is

        namespaced by its parent `status` (e.g. `processing.cashPickupReady`).
        Required and

        never absent (#2662): every status carries a default member (e.g.

        `processing.initiated`), matching the never-null contract on the
        `Transaction.subStatus`

        field's own doc comment. The enum is documented as OPEN in the contract
        — new members

        may be added without an API version bump — even though the server's
        emitted set (29

        members as of #2662) is closed per release; a client that receives an
        unrecognized

        value should fall back to the `status` prefix before the dot (e.g. an
        unrecognized

        `processing.someFutureThing` still means `processing`). The inbound-leg
        lifecycle

        values (`processing.inboundPending`, `processing.inboundProcessing`,

        `failed.inboundFailed`) are deliberate BPN extensions mirroring the
        already-exposed

        outbound states, while the `failed.return*` family conforms to the spec.


        (2026-07-17, product-agreed vocabulary): `failed.returned` is RETIRED —
        its

        meaning is absorbed by `failed.returnComplete`, which now covers both
        the

        OPS-triggered crypto send-back lane and the vendor-side ACH/WIRE bounce
        + clawback

        lane (isReturnedProviderStatus) under one wire value.
        `failed.refundPending` is

        DELIBERATELY NOT added — product agreed to collapse the
        OMS-wallet-refund and

        crypto-return status families into one (this `failed.return*` set); a
        committed OMS

        spec snapshot still lists `failed.refundPending` separately, which is a
        documented

        divergence pending that spec's revision.
    CustomerSummary:
      type: object
      required:
        - id
        - name
      properties:
        id:
          allOf:
            - $ref: '#/components/schemas/typeId'
          description: The OMS customer id (`cst_` prefix).
        name:
          type: string
          description: Customer display name.
      description: >-
        A minimal, resolved reference to the owning OMS customer — id plus
        display

        name, for list/detail rendering without a follow-up customer fetch

        (v0.12 list enrichment, #2665). Distinct from `Party`: this is always
        the

        record's OWNING customer (Transaction.customerId /
        VirtualAccount.customerId

        / DepositAddress.customerId), not whichever side a party sits on.
    Precursor:
      type: object
      required:
        - type
        - id
      properties:
        type:
          type: string
          enum:
            - quote
            - depositAddress
            - virtualAccount
            - cashIn
            - manual
        id:
          type: string
          allOf:
            - $ref: '#/components/schemas/typeId'
          nullable: true
          description: '`qt_` / `da_` / `va_` / `ci_`. Null only for `manual`.'
      description: >-
        What created this transaction, as a uniform `{type, id}` reference.

        Dereference the resource by `id` for its full record — deposit

        instructions live on the Virtual Account / Deposit Address / Cash-In,
        not

        here. `id` is null only for `manual` (operator-initiated, no origin

        resource). The `precursor` field on Transaction is itself nullable

        separately, for out-of-band arrivals with no originating OMS resource.
    TransactionSide:
      type: object
      oneOf:
        - $ref: '#/components/schemas/WalletCryptoInstrument'
        - $ref: '#/components/schemas/WalletExternalInstrument'
        - $ref: '#/components/schemas/WalletFiatInstrument'
        - $ref: '#/components/schemas/BankUsInstrument'
        - $ref: '#/components/schemas/BankIbanInstrument'
        - $ref: '#/components/schemas/BankCanadaInstrument'
        - $ref: '#/components/schemas/CardInstrument'
        - $ref: '#/components/schemas/CashInstrument'
      discriminator:
        propertyName: type
        mapping:
          walletCrypto:
            $ref: '#/components/schemas/WalletCryptoInstrument'
          walletExternal:
            $ref: '#/components/schemas/WalletExternalInstrument'
          walletFiat:
            $ref: '#/components/schemas/WalletFiatInstrument'
          bankUs:
            $ref: '#/components/schemas/BankUsInstrument'
          bankIban:
            $ref: '#/components/schemas/BankIbanInstrument'
          bankCanada:
            $ref: '#/components/schemas/BankCanadaInstrument'
          card:
            $ref: '#/components/schemas/CardInstrument'
          cash:
            $ref: '#/components/schemas/CashInstrument'
      description: >-
        The source side of a transaction/quote (v0.10): a typed instrument
        carrying

        identity (`party`) and instrument detail. Amounts live only in
        `pricing`.
    TransactionDestination:
      type: object
      oneOf:
        - $ref: '#/components/schemas/WalletCryptoDestination'
        - $ref: '#/components/schemas/WalletExternalDestination'
        - $ref: '#/components/schemas/WalletFiatDestination'
        - $ref: '#/components/schemas/BankUsDestination'
        - $ref: '#/components/schemas/BankIbanDestination'
        - $ref: '#/components/schemas/BankCanadaDestination'
        - $ref: '#/components/schemas/CardDestination'
        - $ref: '#/components/schemas/CashDestination'
      discriminator:
        propertyName: type
        mapping:
          walletCrypto:
            $ref: '#/components/schemas/WalletCryptoDestination'
          walletExternal:
            $ref: '#/components/schemas/WalletExternalDestination'
          walletFiat:
            $ref: '#/components/schemas/WalletFiatDestination'
          bankUs:
            $ref: '#/components/schemas/BankUsDestination'
          bankIban:
            $ref: '#/components/schemas/BankIbanDestination'
          bankCanada:
            $ref: '#/components/schemas/BankCanadaDestination'
          card:
            $ref: '#/components/schemas/CardDestination'
          cash:
            $ref: '#/components/schemas/CashDestination'
      description: >-
        The destination side of a transaction/quote (v0.10): a typed instrument
        plus

        `payoutOrigin`. Amounts live only in `pricing`.
    Pricing:
      type: object
      properties:
        source:
          allOf:
            - $ref: '#/components/schemas/PricingSide'
          description: Economics for the source side, denominated in the source asset.
        destination:
          allOf:
            - $ref: '#/components/schemas/PricingSide'
          description: >-
            Economics for the destination side, denominated in the destination
            asset.
        pair:
          type: string
          description: Asset pair, e.g. "usdc/usd".
        exchangeRate:
          type: string
          description: >-
            Mid-market rate between source and destination assets. Identity:
            source.amountNet

            × exchangeRate = destination.amountGross.
        effectiveRate:
          type: string
          description: >-
            All-in rate including all fees. Identity: source.amountGross ×
            effectiveRate =

            destination.amountNet.
        fixedAmountSide:
          type: string
          enum:
            - source
            - destination
          description: >-
            The side you set `amount` on when creating the quote. OMS calculated
            the other side.
        sponsorGas:
          type: boolean
          description: >-
            When true, OMS absorbs the destination gas cost. Currently always
            true.
        sponsorGasCost:
          type: string
          description: >-
            Gas absorbed by the developer when sponsorGas is true. Currently
            always `0.00`.
      description: |-
        Consolidated economics for a quote/transaction: per-side amounts + fees,
        the rate pair, and gas sponsorship, all in one place.
    SettlementError:
      type: object
      required:
        - code
        - message
        - occurredAt
        - recoverable
      properties:
        code:
          type: string
          description: Machine-readable code.
        message:
          type: string
          description: Human-readable detail.
        occurredAt:
          type: string
          format: date-time
          description: When the error occurred.
        recoverable:
          type: boolean
          description: Whether the failure can be recovered.
        manualRecovery:
          allOf:
            - $ref: '#/components/schemas/ManualRecovery'
          description: >-
            Populated only for terminal failures with no resolved refund/return
            path (v0.11).
      description: >-
        Details of an asynchronous settlement failure on a transaction (e.g. a
        downstream payout that failed after the initial request succeeded).
        Present only once a failure has occurred.
    Hold:
      type: object
      oneOf:
        - $ref: '#/components/schemas/HoldSenderAttribution'
        - $ref: '#/components/schemas/HoldDepositAddressFrozen'
        - $ref: '#/components/schemas/HoldDepositAddressInactive'
      discriminator:
        propertyName: type
        mapping:
          senderAttribution:
            $ref: '#/components/schemas/HoldSenderAttribution'
          depositAddressFrozen:
            $ref: '#/components/schemas/HoldDepositAddressFrozen'
          depositAddressInactive:
            $ref: '#/components/schemas/HoldDepositAddressInactive'
      description: >-
        Why an `awaitingAction` transaction is held, and the deadline to
        resolve.

        Discriminated by `type`; each arm carries the fields that apply.
    omsxProjectId:
      type: string
      pattern: ^prj_.+$
      description: Opaque OMSX project ID, e.g. `prj_01kpxxa7esk9a`.
      x-go-type: string
    WalletCryptoInstrument:
      type: object
      required:
        - type
        - category
        - id
        - asset
        - network
        - displayName
      properties:
        party:
          allOf:
            - $ref: '#/components/schemas/Party'
          description: Structured identity of who is on this side.
        memo:
          type: string
          description: Free-text message travelling with the transfer on this side's rail.
        type:
          type: string
          enum:
            - walletCrypto
          description: Type discriminator.
        category:
          type: string
          enum:
            - crypto
          description: >-
            High-level grouping: `fiatAccount` for bank or card accounts,
            `crypto` for wallets.
        id:
          type: string
          allOf:
            - $ref: '#/components/schemas/typeId'
          nullable: true
          description: >-
            OMS wallet ID (`wlt_` prefix).


            DEVIATION from the ratified OMS v0.12 contract
            (docs/specs/2026-08-05-oms-v0.12-openapi.yaml,

            WalletCryptoInstrument): the ratified shape has `id` required and
            non-nullable. A row

            can classify as this arm (destination_type=walletCrypto/legacy
            walletOms, per #2528)

            before the wallet FK has actually resolved — the "in-flight deposit"
            window

            destInstrumentKind's own doc comment describes — so `id` is nullable
            rather than

            emitting an empty string that fails the `typeId` scalar's pattern.
            Not recorded in

            the upstream snapshot's §4 errata (that section is for defects IN
            the ratified

            snapshot, not BPN's own accepted deviations from it) — flagged here
            and in the PR

            description instead, same class as the
            CardInstrument.id/WalletFiatInstrument.id/

            BankUsInstrument.network deviations elsewhere in this same change.
        asset:
          type: string
          description: Canonical asset identifier.
        network:
          type: string
          description: Network identifier.
        displayName:
          type: string
          description: >-
            Opaque, render-only summary for list/detail display. Never a full
            account number/IBAN/PAN.
      description: >-
        OMS-custodied crypto wallet instrument — a uniform reference.
        Dereference

        `GET /wallets/{id}` for the wallet record (on-chain address, custody

        type, balances).
      title: OMS wallet
    WalletExternalInstrument:
      type: object
      required:
        - type
        - category
        - id
        - asset
        - network
        - displayName
      properties:
        party:
          allOf:
            - $ref: '#/components/schemas/Party'
          description: Structured identity of who is on this side.
        memo:
          type: string
          description: Free-text message travelling with the transfer on this side's rail.
        type:
          type: string
          enum:
            - walletExternal
          description: Type discriminator.
        category:
          type: string
          enum:
            - crypto
          description: >-
            High-level grouping: `fiatAccount` for bank or card accounts,
            `crypto` for wallets.
        id:
          type: string
          allOf:
            - $ref: '#/components/schemas/typeId'
          nullable: true
          description: External Account ID (`ext_` prefix). Null when externalUnregistered.
        asset:
          type: string
          description: Canonical asset identifier.
        network:
          type: string
          description: Network identifier.
        displayName:
          type: string
          description: >-
            Opaque, render-only summary for list/detail display. Never a full
            account number/IBAN/PAN.
        details:
          type: object
          properties:
            blockchainAddress:
              type: string
              description: On-chain sender address.
          required:
            - blockchainAddress
          nullable: true
          description: >-
            Populated only when `id` is null (unregistered external sender);
            null for registered instruments.
      description: >-
        Externally-custodied crypto wallet instrument — a uniform reference.
        When

        registered, dereference the external account by `id`; when the sender is

        unregistered, `id` is null and `details.blockchainAddress` carries the

        minimal identifying fact.
      title: External wallet
    WalletFiatInstrument:
      type: object
      required:
        - type
        - category
        - id
        - asset
        - displayName
      properties:
        party:
          allOf:
            - $ref: '#/components/schemas/Party'
          description: Structured identity of who is on this side.
        memo:
          type: string
          description: Free-text message travelling with the transfer on this side's rail.
        type:
          type: string
          enum:
            - walletFiat
          description: Type discriminator.
        category:
          type: string
          enum:
            - fiatAccount
          description: >-
            High-level grouping: `fiatAccount` for bank or card accounts,
            `crypto` for wallets.
        id:
          type: string
          nullable: true
          description: >-
            OMS fiat wallet ID (`wlt_fiat_` prefix). Look up via `GET /wallets`.

            Plain string, not the `typeId` scalar: `wlt_fiat_` is a two-token

            prefix, which the single-underscore `typeId` pattern cannot
            validate.

            Null on a #2504 book-transfer destination leg's pre-outbound window:

            the wallet FK isn't committed until the outbound leg stamps its

            routing snapshot (a repoint can still change which wallet is
            credited

            until then), so there is genuinely no id to dereference yet — a

            deliberate BPN deviation from the ratified OMS v0.12 contract, which

            types this field required and non-nullable.
        asset:
          type: string
          enum:
            - usd
          description: Fiat currency of the balance. Only `usd` today.
        network:
          type: string
          enum:
            - bookTransfer
          description: |-
            `bookTransfer` when this walletFiat is the destination of a Virtual
            Account / Deposit Address book-transfer credit — an internal ledger
            movement at the partner bank, no external rail. Absent when the
            walletFiat is a funding source.
        displayName:
          type: string
          description: >-
            Opaque, render-only summary for list/detail display. Never a full
            account number/IBAN/PAN.
      description: >-
        Fiat balance wallet instrument — a USD balance held at a partner bank

        (e.g. Erebor Bank, N.A.). No on-chain address; an internal ledger
        balance —

        always OMS-owned, no unregistered case. Dereference `GET /wallets/{id}`

        for the wallet record.
      title: Fiat wallet
    BankUsInstrument:
      type: object
      required:
        - type
        - category
        - id
        - asset
        - network
        - displayName
      properties:
        party:
          allOf:
            - $ref: '#/components/schemas/Party'
          description: Structured identity of who is on this side.
        memo:
          type: string
          description: Free-text message travelling with the transfer on this side's rail.
        type:
          type: string
          enum:
            - bankUs
          description: Type discriminator.
        category:
          type: string
          enum:
            - fiatAccount
          description: >-
            High-level grouping: `fiatAccount` for bank or card accounts,
            `crypto` for wallets.
        id:
          type: string
          allOf:
            - $ref: '#/components/schemas/typeId'
          nullable: true
          description: >-
            External Account ID (`ext_` prefix). Null when externalUnregistered
            (e.g. an incoming wire from an unregistered sender).
        asset:
          type: string
          enum:
            - usd
          description: Canonical asset identifier.
        network:
          type: string
          enum:
            - ach
            - achSameDay
            - wire
          nullable: true
          description: >-
            Network identifier.


            DEVIATION from the ratified OMS v0.12 contract
            (docs/specs/2026-08-05-oms-v0.12-openapi.yaml,

            BankUsInstrument): the ratified shape has `network` required and
            non-nullable

            (no `null` option, unlike `id` on this same schema). Real
            legacy/#2528-era

            contamination means a bankUs row can carry a stored rail (`swift`,

            `international_wire`, `rtp`) that is not one of this enum's three
            members —

            rendering that as the Go zero value (`""`) reverses what #2528/#2666
            were

            built to fix: a real generated client (this repo's own npm/zod
            package

            included) fails `z.enum([...]).parse()` on an empty string just as
            hard as

            on the raw invalid token, rejecting the whole response instead of
            one

            field. Making the field nullable lets a degraded row render
            `network: null`

            — schema-valid for a nullable field, same posture as the
            dropped/absent

            field a pre-#2660 client would have seen. Not recorded in the
            upstream

            snapshot's §4 errata (that section is for defects IN the ratified
            snapshot,

            not BPN's own accepted deviations from it) — flagged here and in the
            PR

            description instead.
        secCode:
          allOf:
            - $ref: '#/components/schemas/SecCode'
          description: >-
            ACH SEC code (populated only on ach/achSameDay). Server-derived from
            the

            destination owner's and the source customer's entityType, read
            directly

            from the DB/Customer record — not from this wire-facing instrument.
        displayName:
          type: string
          description: >-
            Opaque, render-only summary for list/detail display. Never a full
            account number/IBAN/PAN.
        details:
          type: object
          properties:
            accountNumberLast4:
              type: string
              description: Last four digits of the account number.
            bankName:
              type: string
              nullable: true
              description: Bank display name.
          required:
            - accountNumberLast4
            - bankName
          nullable: true
          description: >-
            Populated only when `id` is null (unregistered external sender);
            null for registered instruments.
      description: |-
        US bank account instrument — a uniform reference. Dereference the
        external account by `id` for routing number, account type, and full
        account number.
      title: US bank account
    BankIbanInstrument:
      type: object
      required:
        - type
        - category
        - id
        - asset
        - network
        - displayName
      properties:
        party:
          allOf:
            - $ref: '#/components/schemas/Party'
          description: Structured identity of who is on this side.
        memo:
          type: string
          description: Free-text message travelling with the transfer on this side's rail.
        type:
          type: string
          enum:
            - bankIban
          description: Type discriminator.
        category:
          type: string
          enum:
            - fiatAccount
          description: >-
            High-level grouping: `fiatAccount` for bank or card accounts,
            `crypto` for wallets.
        id:
          type: string
          allOf:
            - $ref: '#/components/schemas/typeId'
          nullable: true
          description: External Account ID (`ext_` prefix). Null when externalUnregistered.
        asset:
          type: string
          description: Canonical asset identifier.
        network:
          type: string
          enum:
            - swift
          description: Network identifier.
        displayName:
          type: string
          description: >-
            Opaque, render-only summary for list/detail display. Never a full
            account number/IBAN/PAN.
        details:
          type: object
          properties:
            accountNumberLast4:
              type: string
              description: Last four characters of the IBAN.
            bankName:
              type: string
              nullable: true
              description: Bank display name.
          required:
            - accountNumberLast4
            - bankName
          nullable: true
          description: >-
            Populated only when `id` is null (unregistered external sender);
            null for registered instruments.

            `accountNumberLast4` carries the last 4 of the IBAN — no separate
            `ibanLast4` key on this slim shape.
      description: |-
        IBAN bank account instrument — a uniform reference. Dereference the
        external account by `id` for the BIC and bank address.
      title: IBAN bank account
    BankCanadaInstrument:
      type: object
      required:
        - type
        - category
        - id
        - asset
        - network
        - displayName
      properties:
        party:
          allOf:
            - $ref: '#/components/schemas/Party'
          description: Structured identity of who is on this side.
        memo:
          type: string
          description: Free-text message travelling with the transfer on this side's rail.
        type:
          type: string
          enum:
            - bankCanada
          description: Type discriminator.
        category:
          type: string
          enum:
            - fiatAccount
          description: >-
            High-level grouping: `fiatAccount` for bank or card accounts,
            `crypto` for wallets.
        id:
          type: string
          allOf:
            - $ref: '#/components/schemas/typeId'
          nullable: true
          description: External Account ID (`ext_` prefix). Null when externalUnregistered.
        asset:
          type: string
          enum:
            - usd
            - cad
          description: Canonical asset identifier.
        network:
          type: string
          enum:
            - swift
            - local
          description: USD uses `swift`; CAD uses `local`.
        displayName:
          type: string
          description: >-
            Opaque, render-only summary for list/detail display. Never a full
            account number/IBAN/PAN.
        details:
          type: object
          properties:
            accountNumberLast4:
              type: string
              description: Last four digits of the account number.
            bankName:
              type: string
              nullable: true
              description: Bank display name.
          required:
            - accountNumberLast4
            - bankName
          nullable: true
          description: >-
            Populated only when `id` is null (unregistered external sender);
            null for registered instruments.
      description: >-
        Canadian bank account instrument — a uniform reference. USD routes over

        SWIFT, CAD over local rails. Dereference the external account by `id`
        for

        institution/transit coordinates.
      title: Canadian bank account
    CardInstrument:
      type: object
      required:
        - type
        - category
        - id
        - asset
        - network
        - displayName
      properties:
        party:
          allOf:
            - $ref: '#/components/schemas/Party'
          description: Structured identity of who is on this side.
        memo:
          type: string
          description: Free-text message travelling with the transfer on this side's rail.
        type:
          type: string
          enum:
            - card
          description: Type discriminator.
        category:
          type: string
          enum:
            - fiatAccount
          description: >-
            High-level grouping: `fiatAccount` for bank or card accounts,
            `crypto` for wallets.
        id:
          type: string
          allOf:
            - $ref: '#/components/schemas/typeId'
          nullable: true
          description: >-
            Card External Account ID (`ext_` prefix). Null for a
            pre-#1917-migration

            card-sell row, whose external account id column was added nullable

            without a backfill.


            DEVIATION from the ratified OMS v0.12 contract
            (docs/specs/2026-08-05-oms-v0.12-openapi.yaml,

            CardInstrument): the ratified shape has `id` required and
            non-nullable,

            documented as "Always registered". BPN's own historical data
            contradicts

            that — the pre-#1917 legacy rows genuinely have no id — so this
            field is

            deliberately nullable rather than emitting an empty string that
            fails the

            `typeId` scalar's pattern. Not recorded in the upstream snapshot's
            §4

            errata (that section is for defects IN the ratified snapshot, not
            BPN's

            own accepted deviations from it) — flagged here and in the PR
            description

            instead. Follow-up: either backfill the pre-#1917 quote rows so `id`
            is

            always resolvable, or get this nullability formally signed off with
            OMS

            product as a permanent BPN deviation.
        asset:
          type: string
          enum:
            - usd
          description: Canonical asset identifier.
        network:
          type: string
          enum:
            - card
          description: Network identifier.
        displayName:
          type: string
          description: >-
            Opaque, render-only summary for list/detail display. Never a full
            account number/IBAN/PAN.
      description: >-
        Card instrument — a uniform reference. Usually registered: dereference
        the

        external account by `id` for the card brand, last 4, and expiry.
      title: Card
    CashInstrument:
      type: object
      required:
        - type
        - category
        - asset
        - displayName
      properties:
        party:
          allOf:
            - $ref: '#/components/schemas/Party'
          description: Structured identity of who is on this side.
        memo:
          type: string
          description: Free-text message travelling with the transfer on this side's rail.
        type:
          type: string
          enum:
            - cash
          description: Type discriminator.
        category:
          type: string
          enum:
            - cash
          description: 'High-level grouping: always `cash` for cash pickups and drops.'
        asset:
          type: string
          description: Canonical asset identifier.
        cashLocationId:
          type: string
          description: Cash location ID from `GET /cash-locations`.
        displayName:
          type: string
          description: >-
            Opaque, render-only summary for list/detail display. Never a full
            account number/IBAN/PAN.
      description: |-
        Cash pickup/drop instrument — a uniform reference. Dereference the cash
        location by `cashLocationId` for its address.
      title: Cash
    WalletCryptoDestination:
      type: object
      required:
        - type
        - category
        - id
        - asset
        - network
        - displayName
      properties:
        party:
          allOf:
            - $ref: '#/components/schemas/Party'
          description: Structured identity of who is on this side.
        memo:
          type: string
          description: Free-text message travelling with the transfer on this side's rail.
        type:
          type: string
          enum:
            - walletCrypto
          description: Type discriminator.
        category:
          type: string
          enum:
            - crypto
          description: >-
            High-level grouping: `fiatAccount` for bank or card accounts,
            `crypto` for wallets.
        id:
          type: string
          allOf:
            - $ref: '#/components/schemas/typeId'
          nullable: true
          description: >-
            OMS wallet ID (`wlt_` prefix).


            DEVIATION from the ratified OMS v0.12 contract
            (docs/specs/2026-08-05-oms-v0.12-openapi.yaml,

            WalletCryptoInstrument): the ratified shape has `id` required and
            non-nullable. A row

            can classify as this arm (destination_type=walletCrypto/legacy
            walletOms, per #2528)

            before the wallet FK has actually resolved — the "in-flight deposit"
            window

            destInstrumentKind's own doc comment describes — so `id` is nullable
            rather than

            emitting an empty string that fails the `typeId` scalar's pattern.
            Not recorded in

            the upstream snapshot's §4 errata (that section is for defects IN
            the ratified

            snapshot, not BPN's own accepted deviations from it) — flagged here
            and in the PR

            description instead, same class as the
            CardInstrument.id/WalletFiatInstrument.id/

            BankUsInstrument.network deviations elsewhere in this same change.
        asset:
          type: string
          description: Canonical asset identifier.
        network:
          type: string
          description: Network identifier.
        displayName:
          type: string
          description: >-
            Opaque, render-only summary for list/detail display. Never a full
            account number/IBAN/PAN.
        payoutOrigin:
          $ref: '#/components/schemas/PayoutOrigin'
        companyDiscretionaryData:
          type: string
          description: >-
            Echo of the ACH companyDiscretionaryData supplied on the originating
            request.

            Null/absent on non-ACH destinations or when not supplied.
      title: OMS wallet
    WalletExternalDestination:
      type: object
      required:
        - type
        - category
        - id
        - asset
        - network
        - displayName
      properties:
        party:
          allOf:
            - $ref: '#/components/schemas/Party'
          description: Structured identity of who is on this side.
        memo:
          type: string
          description: Free-text message travelling with the transfer on this side's rail.
        type:
          type: string
          enum:
            - walletExternal
          description: Type discriminator.
        category:
          type: string
          enum:
            - crypto
          description: >-
            High-level grouping: `fiatAccount` for bank or card accounts,
            `crypto` for wallets.
        id:
          type: string
          allOf:
            - $ref: '#/components/schemas/typeId'
          nullable: true
          description: External Account ID (`ext_` prefix). Null when externalUnregistered.
        asset:
          type: string
          description: Canonical asset identifier.
        network:
          type: string
          description: Network identifier.
        displayName:
          type: string
          description: >-
            Opaque, render-only summary for list/detail display. Never a full
            account number/IBAN/PAN.
        details:
          type: object
          properties:
            blockchainAddress:
              type: string
              description: On-chain sender address.
          required:
            - blockchainAddress
          nullable: true
          description: >-
            Populated only when `id` is null (unregistered external sender);
            null for registered instruments.
        payoutOrigin:
          $ref: '#/components/schemas/PayoutOrigin'
        companyDiscretionaryData:
          type: string
          description: >-
            Echo of the ACH companyDiscretionaryData supplied on the originating
            request.

            Null/absent on non-ACH destinations or when not supplied.
      title: External wallet
    WalletFiatDestination:
      type: object
      required:
        - type
        - category
        - id
        - asset
        - displayName
      properties:
        party:
          allOf:
            - $ref: '#/components/schemas/Party'
          description: Structured identity of who is on this side.
        memo:
          type: string
          description: Free-text message travelling with the transfer on this side's rail.
        type:
          type: string
          enum:
            - walletFiat
          description: Type discriminator.
        category:
          type: string
          enum:
            - fiatAccount
          description: >-
            High-level grouping: `fiatAccount` for bank or card accounts,
            `crypto` for wallets.
        id:
          type: string
          nullable: true
          description: >-
            OMS fiat wallet ID (`wlt_fiat_` prefix). Look up via `GET /wallets`.

            Plain string, not the `typeId` scalar: `wlt_fiat_` is a two-token

            prefix, which the single-underscore `typeId` pattern cannot
            validate.

            Null on a #2504 book-transfer destination leg's pre-outbound window:

            the wallet FK isn't committed until the outbound leg stamps its

            routing snapshot (a repoint can still change which wallet is
            credited

            until then), so there is genuinely no id to dereference yet — a

            deliberate BPN deviation from the ratified OMS v0.12 contract, which

            types this field required and non-nullable.
        asset:
          type: string
          enum:
            - usd
          description: Fiat currency of the balance. Only `usd` today.
        network:
          type: string
          enum:
            - bookTransfer
          description: |-
            `bookTransfer` when this walletFiat is the destination of a Virtual
            Account / Deposit Address book-transfer credit — an internal ledger
            movement at the partner bank, no external rail. Absent when the
            walletFiat is a funding source.
        displayName:
          type: string
          description: >-
            Opaque, render-only summary for list/detail display. Never a full
            account number/IBAN/PAN.
        payoutOrigin:
          $ref: '#/components/schemas/PayoutOrigin'
        companyDiscretionaryData:
          type: string
          description: >-
            Echo of the ACH companyDiscretionaryData supplied on the originating
            request.

            Null/absent on non-ACH destinations or when not supplied.
      description: >-
        Fiat balance wallet destination — the wallet-as-destination projection
        used to

        render an inbound fiat-wallet deposit (design §4.2/§16, #2363).
        RENDERING

        OUTPUT ONLY: this arm exists so a settled deposit into a customer's USD
        fiat

        wallet renders `destination.walletFiat`. It does NOT re-open walletFiat
        as a

        user-SPECIFIABLE input destination — that input deferral (crediting
        VA/DA

        deposits into a wallet, design §16) still holds; only the output shape
        is

        restored here. Over-cut from Task 1 (#2340); returned for Task 10.
      title: Fiat wallet
    BankUsDestination:
      type: object
      required:
        - type
        - category
        - id
        - asset
        - network
        - displayName
      properties:
        party:
          allOf:
            - $ref: '#/components/schemas/Party'
          description: Structured identity of who is on this side.
        memo:
          type: string
          description: Free-text message travelling with the transfer on this side's rail.
        type:
          type: string
          enum:
            - bankUs
          description: Type discriminator.
        category:
          type: string
          enum:
            - fiatAccount
          description: >-
            High-level grouping: `fiatAccount` for bank or card accounts,
            `crypto` for wallets.
        id:
          type: string
          allOf:
            - $ref: '#/components/schemas/typeId'
          nullable: true
          description: >-
            External Account ID (`ext_` prefix). Null when externalUnregistered
            (e.g. an incoming wire from an unregistered sender).
        asset:
          type: string
          enum:
            - usd
          description: Canonical asset identifier.
        network:
          type: string
          enum:
            - ach
            - achSameDay
            - wire
          nullable: true
          description: >-
            Network identifier.


            DEVIATION from the ratified OMS v0.12 contract
            (docs/specs/2026-08-05-oms-v0.12-openapi.yaml,

            BankUsInstrument): the ratified shape has `network` required and
            non-nullable

            (no `null` option, unlike `id` on this same schema). Real
            legacy/#2528-era

            contamination means a bankUs row can carry a stored rail (`swift`,

            `international_wire`, `rtp`) that is not one of this enum's three
            members —

            rendering that as the Go zero value (`""`) reverses what #2528/#2666
            were

            built to fix: a real generated client (this repo's own npm/zod
            package

            included) fails `z.enum([...]).parse()` on an empty string just as
            hard as

            on the raw invalid token, rejecting the whole response instead of
            one

            field. Making the field nullable lets a degraded row render
            `network: null`

            — schema-valid for a nullable field, same posture as the
            dropped/absent

            field a pre-#2660 client would have seen. Not recorded in the
            upstream

            snapshot's §4 errata (that section is for defects IN the ratified
            snapshot,

            not BPN's own accepted deviations from it) — flagged here and in the
            PR

            description instead.
        secCode:
          allOf:
            - $ref: '#/components/schemas/SecCode'
          description: >-
            ACH SEC code (populated only on ach/achSameDay). Server-derived from
            the

            destination owner's and the source customer's entityType, read
            directly

            from the DB/Customer record — not from this wire-facing instrument.
        displayName:
          type: string
          description: >-
            Opaque, render-only summary for list/detail display. Never a full
            account number/IBAN/PAN.
        details:
          type: object
          properties:
            accountNumberLast4:
              type: string
              description: Last four digits of the account number.
            bankName:
              type: string
              nullable: true
              description: Bank display name.
          required:
            - accountNumberLast4
            - bankName
          nullable: true
          description: >-
            Populated only when `id` is null (unregistered external sender);
            null for registered instruments.
        payoutOrigin:
          $ref: '#/components/schemas/PayoutOrigin'
        companyDiscretionaryData:
          type: string
          description: >-
            Echo of the ACH companyDiscretionaryData supplied on the originating
            request.

            Null/absent on non-ACH destinations or when not supplied.
      title: US bank account
    BankIbanDestination:
      type: object
      required:
        - type
        - category
        - id
        - asset
        - network
        - displayName
      properties:
        party:
          allOf:
            - $ref: '#/components/schemas/Party'
          description: Structured identity of who is on this side.
        memo:
          type: string
          description: Free-text message travelling with the transfer on this side's rail.
        type:
          type: string
          enum:
            - bankIban
          description: Type discriminator.
        category:
          type: string
          enum:
            - fiatAccount
          description: >-
            High-level grouping: `fiatAccount` for bank or card accounts,
            `crypto` for wallets.
        id:
          type: string
          allOf:
            - $ref: '#/components/schemas/typeId'
          nullable: true
          description: External Account ID (`ext_` prefix). Null when externalUnregistered.
        asset:
          type: string
          description: Canonical asset identifier.
        network:
          type: string
          enum:
            - swift
          description: Network identifier.
        displayName:
          type: string
          description: >-
            Opaque, render-only summary for list/detail display. Never a full
            account number/IBAN/PAN.
        details:
          type: object
          properties:
            accountNumberLast4:
              type: string
              description: Last four characters of the IBAN.
            bankName:
              type: string
              nullable: true
              description: Bank display name.
          required:
            - accountNumberLast4
            - bankName
          nullable: true
          description: >-
            Populated only when `id` is null (unregistered external sender);
            null for registered instruments.

            `accountNumberLast4` carries the last 4 of the IBAN — no separate
            `ibanLast4` key on this slim shape.
        payoutOrigin:
          $ref: '#/components/schemas/PayoutOrigin'
        companyDiscretionaryData:
          type: string
          description: >-
            Echo of the ACH companyDiscretionaryData supplied on the originating
            request.

            Null/absent on non-ACH destinations or when not supplied.
      title: IBAN bank account
    BankCanadaDestination:
      type: object
      required:
        - type
        - category
        - id
        - asset
        - network
        - displayName
      properties:
        party:
          allOf:
            - $ref: '#/components/schemas/Party'
          description: Structured identity of who is on this side.
        memo:
          type: string
          description: Free-text message travelling with the transfer on this side's rail.
        type:
          type: string
          enum:
            - bankCanada
          description: Type discriminator.
        category:
          type: string
          enum:
            - fiatAccount
          description: >-
            High-level grouping: `fiatAccount` for bank or card accounts,
            `crypto` for wallets.
        id:
          type: string
          allOf:
            - $ref: '#/components/schemas/typeId'
          nullable: true
          description: External Account ID (`ext_` prefix). Null when externalUnregistered.
        asset:
          type: string
          enum:
            - usd
            - cad
          description: Canonical asset identifier.
        network:
          type: string
          enum:
            - swift
            - local
          description: USD uses `swift`; CAD uses `local`.
        displayName:
          type: string
          description: >-
            Opaque, render-only summary for list/detail display. Never a full
            account number/IBAN/PAN.
        details:
          type: object
          properties:
            accountNumberLast4:
              type: string
              description: Last four digits of the account number.
            bankName:
              type: string
              nullable: true
              description: Bank display name.
          required:
            - accountNumberLast4
            - bankName
          nullable: true
          description: >-
            Populated only when `id` is null (unregistered external sender);
            null for registered instruments.
        payoutOrigin:
          $ref: '#/components/schemas/PayoutOrigin'
        companyDiscretionaryData:
          type: string
          description: >-
            Echo of the ACH companyDiscretionaryData supplied on the originating
            request.

            Null/absent on non-ACH destinations or when not supplied.
      title: Canadian bank account
    CardDestination:
      type: object
      required:
        - type
        - category
        - id
        - asset
        - network
        - displayName
      properties:
        party:
          allOf:
            - $ref: '#/components/schemas/Party'
          description: Structured identity of who is on this side.
        memo:
          type: string
          description: Free-text message travelling with the transfer on this side's rail.
        type:
          type: string
          enum:
            - card
          description: Type discriminator.
        category:
          type: string
          enum:
            - fiatAccount
          description: >-
            High-level grouping: `fiatAccount` for bank or card accounts,
            `crypto` for wallets.
        id:
          type: string
          allOf:
            - $ref: '#/components/schemas/typeId'
          nullable: true
          description: >-
            Card External Account ID (`ext_` prefix). Null for a
            pre-#1917-migration

            card-sell row, whose external account id column was added nullable

            without a backfill.


            DEVIATION from the ratified OMS v0.12 contract
            (docs/specs/2026-08-05-oms-v0.12-openapi.yaml,

            CardInstrument): the ratified shape has `id` required and
            non-nullable,

            documented as "Always registered". BPN's own historical data
            contradicts

            that — the pre-#1917 legacy rows genuinely have no id — so this
            field is

            deliberately nullable rather than emitting an empty string that
            fails the

            `typeId` scalar's pattern. Not recorded in the upstream snapshot's
            §4

            errata (that section is for defects IN the ratified snapshot, not
            BPN's

            own accepted deviations from it) — flagged here and in the PR
            description

            instead. Follow-up: either backfill the pre-#1917 quote rows so `id`
            is

            always resolvable, or get this nullability formally signed off with
            OMS

            product as a permanent BPN deviation.
        asset:
          type: string
          enum:
            - usd
          description: Canonical asset identifier.
        network:
          type: string
          enum:
            - card
          description: Network identifier.
        displayName:
          type: string
          description: >-
            Opaque, render-only summary for list/detail display. Never a full
            account number/IBAN/PAN.
        payoutOrigin:
          $ref: '#/components/schemas/PayoutOrigin'
        companyDiscretionaryData:
          type: string
          description: >-
            Echo of the ACH companyDiscretionaryData supplied on the originating
            request.

            Null/absent on non-ACH destinations or when not supplied.
      title: Card
    CashDestination:
      type: object
      required:
        - type
        - category
        - asset
        - displayName
      properties:
        party:
          allOf:
            - $ref: '#/components/schemas/Party'
          description: Structured identity of who is on this side.
        memo:
          type: string
          description: Free-text message travelling with the transfer on this side's rail.
        type:
          type: string
          enum:
            - cash
          description: Type discriminator.
        category:
          type: string
          enum:
            - cash
          description: 'High-level grouping: always `cash` for cash pickups and drops.'
        asset:
          type: string
          description: Canonical asset identifier.
        cashLocationId:
          type: string
          description: Cash location ID from `GET /cash-locations`.
        displayName:
          type: string
          description: >-
            Opaque, render-only summary for list/detail display. Never a full
            account number/IBAN/PAN.
        payoutOrigin:
          $ref: '#/components/schemas/PayoutOrigin'
        pickupCode:
          type: string
          description: >-
            Retail pickup code for a cash payout. Populated only on cash-out
            (pickup) destinations.
        companyDiscretionaryData:
          type: string
          description: >-
            Echo of the ACH companyDiscretionaryData supplied on the originating
            request.

            Null/absent on non-ACH destinations or when not supplied.
      title: Cash
    PricingSide:
      type: object
      properties:
        asset:
          type: string
          description: >-
            Currency these amounts are in. Same as the side's instrument asset,
            repeated here

            so pricing is self-contained.
        amountGross:
          type: string
          description: Amount on this side before fees are applied.
        amountNet:
          type: string
          description: >-
            Amount after fees: what is actually pulled from a source, or
            delivered to a destination.
        feesDeducted:
          allOf:
            - $ref: '#/components/schemas/FeesDeducted'
          description: Itemized fees deducted on this side.
      description: |-
        Per-side economics for the `pricing` object: the side carries identity,
        the amounts and fees live here.
    ManualRecovery:
      type: object
      properties:
        type:
          type: string
          enum:
            - manualRecovery
        custodian:
          $ref: '#/components/schemas/DestinationCustodian'
        instructions:
          type: string
        referenceFields:
          $ref: '#/components/schemas/RecoveryReferenceFields'
      description: v0.11 manual-recovery detail (renamed from Recovery/operatorRecovery).
    HoldSenderAttribution:
      type: object
      required:
        - type
      properties:
        required:
          type: boolean
          description: Whether the hold is still blocking; false once resolved.
        since:
          type: string
          format: date-time
          description: When the hold started.
        deadline:
          type: string
          format: date-time
          description: Deadline to resolve before timeout.
        resolvedAt:
          type: string
          format: date-time
          description: When the hold was resolved; null while outstanding.
        type:
          type: string
          enum:
            - senderAttribution
          description: Type discriminator.
        matchableExternalAccountCriteria:
          allOf:
            - $ref: '#/components/schemas/MatchableExternalAccountCriteria'
          description: Registering a matching walletExternal EA releases this hold.
      description: DA received crypto from an address not linked to a counterparty.
      title: Sender attribution
    HoldDepositAddressFrozen:
      type: object
      required:
        - type
      properties:
        required:
          type: boolean
          description: Whether the hold is still blocking; false once resolved.
        since:
          type: string
          format: date-time
          description: When the hold started.
        deadline:
          type: string
          format: date-time
          description: Deadline to resolve before timeout.
        resolvedAt:
          type: string
          format: date-time
          description: When the hold was resolved; null while outstanding.
        type:
          type: string
          enum:
            - depositAddressFrozen
          description: Type discriminator.
      description: The parent deposit address is in a compliance freeze.
      title: Deposit address frozen
    HoldDepositAddressInactive:
      type: object
      required:
        - type
      properties:
        required:
          type: boolean
          description: Whether the hold is still blocking; false once resolved.
        since:
          type: string
          format: date-time
          description: When the hold started.
        deadline:
          type: string
          format: date-time
          description: Deadline to resolve before timeout.
        resolvedAt:
          type: string
          format: date-time
          description: When the hold was resolved; null while outstanding.
        type:
          type: string
          enum:
            - depositAddressInactive
          description: Type discriminator.
        cause:
          $ref: '#/components/schemas/HoldInactiveCause'
      description: The destination external account went deleted/invalid.
      title: Deposit address inactive
    Party:
      type: object
      required:
        - relationship
        - id
        - name
      properties:
        relationship:
          type: string
          enum:
            - customer
            - otherCustomer
            - externalRegistered
            - externalUnregistered
          description: Which kind of party this is.
        id:
          type: string
          allOf:
            - $ref: '#/components/schemas/typeId'
          nullable: true
          description: >-
            `cst_` for customer/otherCustomer; `ctp_` for externalRegistered;
            null for externalUnregistered.
        name:
          type: string
          nullable: true
          description: >-
            Display name. Null only when genuinely unknown (an unattributed
            external sender).
      description: >-
        Response-only identity of who is on one side of a transaction — a
        uniform

        `{relationship, id, name}` reference. `id` is the Customer (`cst_`) for

        `customer`/`otherCustomer`, the Counterparty (`ctp_`) for

        `externalRegistered`, and null for `externalUnregistered`. Entity type
        and

        address live on the dereferenced Customer/Counterparty resource, not
        here.

        `name` is populated for every relationship except a genuinely-unknown

        external sender.
    SecCode:
      type: string
      enum:
        - ccd
        - ppd
        - web
      description: >-
        ACH SEC code. Populated only when the destination bank network is

        `ach`/`achSameDay`; null otherwise. Server-derived from the destination
        owner's

        and the source customer's `entityType`.
    PayoutOrigin:
      type: object
      required:
        - type
        - id
      properties:
        type:
          type: string
          enum:
            - bank
            - blockchain
        id:
          type: string
          allOf:
            - $ref: '#/components/schemas/typeId'
          nullable: true
      description: |-
        Where last-mile delivery is sent *from*, as a uniform `{type, id}`
        reference — response-only. `id` is the Virtual Account (`va_`) or OMS
        wallet (`wlt_`) funding the leg; null before execution (Quote / Deposit
        Address echo the choice only) or when the origin has no partner-visible
        resource. Rail identifiers for the last-mile transfer live in the
        top-level `tracking` array with `leg: destination` — not here.
    FeesDeducted:
      type: object
      required:
        - total
        - developer
        - oms
        - gas
      properties:
        total:
          type: string
        developer:
          type: string
          description: |-
            Per-side aggregated developer fee total in this side's asset.
            Always "0" in alpha - alpha invariant, mirrors the gas line.
        oms:
          type: string
        gas:
          type: string
      description: |-
        Per-side breakdown of fees deducted in-line from the transaction.
        End-of-month billable fees will be reported separately in the future
        (planned `feesInvoice` sibling). Denominated in that side's asset.
    DestinationCustodian:
      type: string
      enum:
        - ANCHORAGE_SG
        - ANCHORAGE_US
        - AQUANOW_CA
        - B2C2_UK
        - B2C2_US
        - BITGO_SG
        - BITGO_US
        - BITSTAMP_US
        - BVNK_US
        - CIRCLE_FR
        - CIRCLE_US
        - CITIBANK_US
        - COINBASE_US
        - COINSMART_CA
        - COPPER_CH
        - COPPER_UK
        - CUMBERLAND_DRW_LLC_US
        - CUMBERLAND_SG
        - EREBOR_BANK_US
        - FALCONX_US
        - FIDELITY_UK
        - FIDELITY_US
        - FIREBLOCKS_APAC
        - FIREBLOCKS_US
        - GALAXY_KY
        - GEMINI_US
        - KRAKEN_BVI
        - KRAKEN_EU_IE
        - KRAKEN_UK
        - KRAKEN_US
        - NUBANK_BR
        - PAXOS_US
        - RAMP_NETWORK_US
        - ROBINHOOD_US
        - WINTERMUTE_GB
        - SELF_HOSTED
        - OTHER
    RecoveryReferenceFields:
      type: object
      properties:
        transactionId:
          allOf:
            - $ref: '#/components/schemas/typeId'
          description: Transaction ID (`txn_` prefix).
        sourceTxHash:
          type: string
          description: Transaction hash of the originating inbound transfer.
      description: Reference identifiers for an operator-driven recovery.
    MatchableExternalAccountCriteria:
      type: object
      properties:
        type:
          type: string
          enum:
            - walletExternal
          description: Always `walletExternal` — the EA type that resolves the hold.
        blockchainAddress:
          type: string
          description: On-chain address.
        networkFamily:
          type: string
          description: Network family (e.g. evm).
      description: >-
        The wallet criteria a held inbound matches against to release:
        registering a

        walletExternal external account with this (customer, address,
        networkFamily)

        clears the sender-attribution hold.
    HoldInactiveCause:
      type: object
      properties:
        type:
          type: string
          enum:
            - destinationExternalAccount
          description: Always `destinationExternalAccount`.
        externalAccountId:
          allOf:
            - $ref: '#/components/schemas/typeId'
          description: External Account ID (`ext_` prefix).
        externalAccountStatus:
          $ref: '#/components/schemas/ExternalAccountStatusReason'
        invalidReason:
          allOf:
            - $ref: '#/components/schemas/ExternalAccountInvalidReason'
          description: Machine-readable reason the destination became invalid.
      description: >-
        Why a depositAddressInactive hold's destination external account went
        unusable.
    ExternalAccountStatusReason:
      type: string
      enum:
        - deleted
        - invalid
    ExternalAccountInvalidReason:
      type: string
      enum:
        - accountClosed
        - accountFrozenByBank
        - routingOrAccountNumberInvalid
        - accountHolderDeceased
        - accountDoesNotSupportTransfers
        - payeeNameMismatch
        - walletUnreachableOnNetwork
        - billingAddressMismatch
        - cardExpired
        - cardClosedOrLostStolen
        - pushToCardUnsupported
        - cardDeclinedByIssuer
      description: |-
        Closed enum stamped on an External Account when `status = invalid`,
        derived from a payout return. Bank rails populate values from the
        payout return code; card rails populate values from the issuer's
        response.
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: Token from POST /auth/token

````