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.11'
    description: Sandbox
  - url: 'https://api.polygon.technology/v0.11'
    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:
  /auth/token:
    post:
      tags:
        - Auth
      operationId: authorize
      summary: Get bearer token
      description: >-
        Exchanges an OMS API key + secret for a bearer token valid for 60
        minutes. The token is signed by the OMS issuer and must be presented as
        `Authorization Bearer <token>` on every other endpoint.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AuthorizeRequest'
      responses:
        '200':
          description: Token issued
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AuthorizeResponse'
        '400':
          description: Malformed request body
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Invalid or revoked credentials
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          description: >-
            Too many requests from this client IP. Retry after the interval in
            the `Retry-After` header.
          headers:
            Retry-After:
              description: Seconds to wait before retrying.
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: Internal error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security: []
  /customers:
    get:
      tags:
        - Customers
      operationId: listCustomers
      summary: List customers
      description: Returns a paginated list of customers under the current Project.
      parameters:
        - name: status
          in: query
          schema:
            type: string
            enum:
              - active
              - inactive
          description: Filter by status. Default returns all.
        - name: email
          in: query
          schema:
            type: string
          description: Filter by exact email match.
        - name: externalId
          in: query
          schema:
            type: string
          description: Filter by externalId.
        - name: createdAfter
          in: query
          schema:
            type: string
            format: date-time
          description: Filter customers created after this timestamp.
        - name: createdBefore
          in: query
          schema:
            type: string
            format: date-time
          description: Filter customers created before this timestamp.
        - name: limit
          in: query
          schema:
            type: integer
            default: 20
            maximum: 100
        - name: cursor
          in: query
          schema:
            type: string
      responses:
        '200':
          description: List of customers
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CustomersList'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
    post:
      tags:
        - Customers
      operationId: createCustomer
      summary: Create a customer
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CustomerRequest'
      responses:
        '201':
          description: Customer created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Customer'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
  '/customers/{customerId}':
    get:
      tags:
        - Customers
      operationId: getCustomer
      summary: Get customer by ID
      description: Returns the customer with their wallets included in the response.
      parameters:
        - name: customerId
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Customer details with wallets
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Customer'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Not Found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
    patch:
      tags:
        - Customers
      operationId: updateCustomer
      summary: Update a customer
      description: >-
        Partial update. Only include fields you want to change.
        Compliance-relevant changes (residentialAddress, lastName,
        identifyingInformation, ipAddress) may trigger endorsement
        re-evaluation. Including endorsement names in the endorsements array
        explicitly triggers re-evaluation.
      parameters:
        - name: customerId
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CustomerUpdate'
      responses:
        '200':
          description: Customer updated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Customer'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Not Found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
    delete:
      tags:
        - Customers
      operationId: deleteCustomer
      summary: Delete a customer
      description: >-
        Soft delete. Sets status to inactive. Inactive customers cannot create
        new transactions but data is retained for compliance purposes.
      parameters:
        - name: customerId
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Customer soft-deleted (status set to inactive)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Customer'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Not Found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
  /webhooks:
    get:
      tags:
        - Webhooks
      operationId: listWebhooks
      summary: List webhooks
      description: >-
        Returns a paginated list of webhooks registered under the current
        Project.
      parameters:
        - name: status
          in: query
          schema:
            $ref: '#/components/schemas/WebhookStatus'
          description: Filter by webhook status.
        - name: limit
          in: query
          schema:
            type: integer
            default: 20
            maximum: 100
        - name: cursor
          in: query
          schema:
            type: string
      responses:
        '200':
          description: List of webhooks
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WebhooksList'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
    post:
      tags:
        - Webhooks
      operationId: createWebhook
      summary: Create a webhook
      description: >-
        Registers an HTTPS endpoint with event subscriptions. The HMAC signing
        key is returned in cleartext once and never again.
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WebhookRequest'
      responses:
        '201':
          description: Webhook created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateWebhookResponse'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
  '/webhooks/{webhookId}':
    get:
      tags:
        - Webhooks
      operationId: getWebhook
      summary: Get webhook by ID
      parameters:
        - name: webhookId
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Webhook details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Webhook'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Not Found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
    patch:
      tags:
        - Webhooks
      operationId: updateWebhook
      summary: Update a webhook
      description: >-
        Partial update of URL, subscriptions, timeout, and notify threshold.
        Lifecycle is managed via enable/disable.
      parameters:
        - name: webhookId
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WebhookUpdate'
      responses:
        '200':
          description: Webhook updated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Webhook'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Not Found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
    delete:
      tags:
        - Webhooks
      operationId: deleteWebhook
      summary: Delete a webhook
      description: >-
        Soft delete. The webhook is hidden from List/Get but delivery history is
        retained for the configured retention window.
      parameters:
        - name: webhookId
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Webhook soft-deleted
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Webhook'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Not Found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
  '/webhooks/{webhookId}/rotate-key':
    post:
      tags:
        - Webhooks
      operationId: rotateWebhookKey
      summary: Rotate the signing key
      description: >-
        Issues a new HMAC signing key for the webhook. The cleartext key is
        returned once.
      parameters:
        - name: webhookId
          in: path
          required: true
          schema:
            type: string
        - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: New signing key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RotateWebhookKeyResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Not Found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
  '/webhooks/{webhookId}/enable':
    post:
      tags:
        - Webhooks
      operationId: enableWebhook
      summary: Enable a webhook
      description: >-
        Reactivates a webhook from any non-enabled state, including suspended.
        Resets the failure/down episode.
      parameters:
        - name: webhookId
          in: path
          required: true
          schema:
            type: string
        - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Webhook enabled
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Webhook'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Not Found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
  '/webhooks/{webhookId}/disable':
    post:
      tags:
        - Webhooks
      operationId: disableWebhook
      summary: Disable a webhook
      description: Stops dispatch and skips the webhook's queued deliveries. Idempotent.
      parameters:
        - name: webhookId
          in: path
          required: true
          schema:
            type: string
        - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Webhook disabled
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Webhook'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Not Found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
  '/webhooks/{webhookId}/test':
    post:
      tags:
        - Webhooks
      operationId: testWebhook
      summary: Send a test delivery
      description: >-
        Synthesizes a test delivery to the registered endpoint so partners can
        verify signature and reachability.
      parameters:
        - name: webhookId
          in: path
          required: true
          schema:
            type: string
        - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Test delivery created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WebhookDelivery'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Not Found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
  '/webhooks/{webhookId}/deliveries':
    get:
      tags:
        - Webhooks
      operationId: listWebhookDeliveries
      summary: List deliveries for a webhook
      description: >-
        Returns a paginated list of deliveries for the webhook. Attempts are not
        included; use get-webhook-delivery to expand a delivery with its
        attempts.
      parameters:
        - name: webhookId
          in: path
          required: true
          schema:
            type: string
        - name: status
          in: query
          schema:
            $ref: '#/components/schemas/DeliveryStatus'
        - name: eventId
          in: query
          schema:
            type: string
        - name: test
          in: query
          schema:
            type: boolean
        - name: createdAfter
          in: query
          schema:
            type: string
            format: date-time
        - name: createdBefore
          in: query
          schema:
            type: string
            format: date-time
        - name: limit
          in: query
          schema:
            type: integer
            default: 20
            maximum: 100
        - name: cursor
          in: query
          schema:
            type: string
      responses:
        '200':
          description: List of deliveries
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DeliveriesList'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
  '/webhooks/{webhookId}/deliveries/{deliveryId}':
    get:
      tags:
        - Webhooks
      operationId: getWebhookDelivery
      summary: Get a delivery with its attempts
      parameters:
        - name: webhookId
          in: path
          required: true
          schema:
            type: string
        - name: deliveryId
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Delivery with attempts
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/GetDeliveryResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Not Found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
  '/webhooks/{webhookId}/deliveries/retry':
    post:
      tags:
        - Webhooks
      operationId: retryWebhookDeliveries
      summary: Retry deliveries
      description: >-
        Re-queues deliveries, resetting failedAttempts to zero. Provide explicit
        deliveryIds, or a status plus a createdAt range to retry all matching
        deliveries. Every retry is audited.
      parameters:
        - name: webhookId
          in: path
          required: true
          schema:
            type: string
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RetryDeliveriesRequest'
      responses:
        '200':
          description: Retry result
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RetryDeliveriesResponse'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Not Found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
  '/customers/{customerId}/wallets/associate':
    post:
      tags:
        - Wallets
      operationId: associateWallet
      summary: Associate an embedded wallet with a customer
      description: >-
        Links an embedded (WaaS) wallet to the customer. The wallet is
        identified by the supplied WaaS idToken — its subject is the wallet id,
        so the wallet id is never passed directly — and the token's audience
        must be the authenticated project.
      parameters:
        - name: customerId
          in: path
          required: true
          schema:
            type: string
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AssociateWalletRequest'
      responses:
        '200':
          description: Wallet associated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Wallet'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Not Found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '409':
          description: >-
            Conflict — the wallet is already associated with a different
            customer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
  /cash-ins:
    get:
      operationId: listCashIns
      summary: List cash-ins
      description: >-
        Returns a paginated list of cash-ins, optionally filtered by customer,

        status, type, date range, or free-text search. Results are ordered

        newest-first. Date filters `createdAfter` and `createdBefore` are
        inclusive,

        matching `GET /transactions`.
      parameters:
        - name: customerId
          in: query
          required: false
          description: Filter to a single customer (`cst_` prefix).
          schema:
            type: string
          explode: false
        - name: status
          in: query
          required: false
          description: Filter by status.
          schema:
            type: string
          explode: false
        - name: type
          in: query
          required: false
          description: Filter by type.
          schema:
            type: array
            items:
              $ref: '#/components/schemas/TransferType'
        - 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 cash-in id, customer id, or customer
            email.
          schema:
            type: string
          explode: false
        - name: q
          in: query
          required: false
          description: Alias for `search`.
          schema:
            type: string
          explode: false
        - name: limit
          in: query
          required: false
          description: Maximum number of results per page.
          schema:
            type: integer
            format: int32
          explode: false
        - name: cursor
          in: query
          required: false
          description: >-
            Opaque pagination cursor from a previous response; omit for the
            first page.
          schema:
            type: string
          explode: false
      responses:
        '200':
          description: The request has succeeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListCashInsResponse'
      tags:
        - CashIns
    post:
      operationId: createCashIn
      summary: Create a cash-in deposit code
      description: >-
        Creates a cash-in: reserves a deposit code the customer presents at a

        physical cash location to deposit fiat, which is then converted to
        crypto

        and credited to the destination wallet. The 201 response includes the

        cash-in and its deposit instructions (the code and its expiry). Pass an

        Idempotency-Key header to safely retry without creating duplicates.
      parameters:
        - $ref: '#/components/parameters/IdempotencyKeyHeader'
      responses:
        '201':
          description: >-
            The request has succeeded and a new resource has been created as a
            result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CashIn'
      tags:
        - CashIns
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateCashInRequest'
  '/cash-ins/{cashInId}':
    get:
      operationId: getCashIn
      summary: Get a cash-in by ID
      description: >-
        Retrieves a single cash-in by ID, including its current status and

        sub-status, source and destination amounts, fees, and deposit
        instructions.
      parameters:
        - name: cashInId
          in: path
          required: true
          description: Cash-in ID (`ci_` prefix).
          schema:
            type: string
      responses:
        '200':
          description: The request has succeeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CashIn'
      tags:
        - CashIns
  '/cash-ins/{cashInId}/refresh':
    post:
      operationId: refreshCashIn
      summary: Refresh a cash-in deposit code
      description: >-
        Regenerates the deposit code for an existing cash-in whose code has
        expired

        or is close to expiring, returning a fresh code and expiry. Pass an

        Idempotency-Key header to safely retry.


        A per-cash-in refresh guard returns 429 when the total-refresh cap is
        hit

        (`refreshLimitReached`) or when refreshed inside the minimum interval

        (`refreshTooFrequent`, with a `Retry-After` header) — protecting the
        upstream

        provider and bounding stored refresh history.
      parameters:
        - name: cashInId
          in: path
          required: true
          description: Cash-in ID (`ci_` prefix).
          schema:
            type: string
        - $ref: '#/components/parameters/IdempotencyKeyHeader'
      responses:
        '200':
          description: The request has succeeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CashIn'
        '429':
          description: >-
            Returned by `POST /cash-ins/{cashInId}/refresh` when a per-cash-in
            refresh

            limit is exceeded: either the total-refresh cap
            (`refreshLimitReached`) or the

            minimum interval between refreshes (`refreshTooFrequent`). The
            `Retry-After`

            header is present for `refreshTooFrequent`, giving the seconds until
            the next

            refresh is permitted.
          headers:
            retry-after:
              required: false
              description: >-
                Present for `refreshTooFrequent`: seconds until the next refresh
                is permitted.
              schema:
                type: integer
                format: int32
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RefreshRateLimitedErrorBody'
      tags:
        - CashIns
  '/cash-ins/{cashInId}/simulate/cancel':
    post:
      operationId: simulateCashInCancel
      summary: Simulate cash-in cancel
      description: >-
        Simulate the customer cancelling the authorization before handing over
        the cash (sandbox only).
      parameters:
        - name: cashInId
          in: path
          required: true
          schema:
            type: string
        - $ref: '#/components/parameters/IdempotencyKeyHeader'
      responses:
        '200':
          description: The request has succeeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SimulateCashInCancelResponse'
      tags:
        - Sandbox
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SimulateCashInCancelRequest'
      x-server-scope: non-prod-live
  '/cash-ins/{cashInId}/simulate/deposit-cash':
    post:
      operationId: simulateCashInDepositCash
      summary: Simulate cash-in deposit cash
      description: >-
        Simulate the customer handing over the cash, completing the authorized
        deposit (sandbox only).
      parameters:
        - name: cashInId
          in: path
          required: true
          schema:
            type: string
        - $ref: '#/components/parameters/IdempotencyKeyHeader'
      responses:
        '200':
          description: The request has succeeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SimulateCashInDepositCashResponse'
      tags:
        - Sandbox
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SimulateCashInDepositCashRequest'
      x-server-scope: non-prod-live
  '/cash-ins/{cashInId}/simulate/present-code':
    post:
      operationId: simulateCashInPresentCode
      summary: Simulate cash-in present code
      description: >-
        Simulate the customer presenting their cash-in code at the register
        (sandbox only).
      parameters:
        - name: cashInId
          in: path
          required: true
          schema:
            type: string
        - $ref: '#/components/parameters/IdempotencyKeyHeader'
      responses:
        '200':
          description: The request has succeeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SimulateCashInPresentCodeResponse'
      tags:
        - Sandbox
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SimulateCashInPresentCodeRequest'
      x-server-scope: non-prod-live
  /cash-locations:
    get:
      operationId: listCashLocations
      summary: List cash locations
      description: >-
        Returns cash pickup and deposit locations for the given provider within

        range of the supplied coordinates, each with its distance from that
        point.

        Use the flow parameter to select the cash-in or cash-out provider

        configuration.
      parameters:
        - name: provider
          in: query
          required: true
          description: Cash provider configuration to query.
          schema:
            type: string
        - name: latitude
          in: query
          required: true
          description: Search-center latitude in decimal degrees.
          schema:
            type: number
            format: double
        - name: longitude
          in: query
          required: true
          description: Search-center longitude in decimal degrees.
          schema:
            type: number
            format: double
        - name: radius
          in: query
          required: false
          description: Search radius around the given coordinates.
          schema:
            type: number
            format: double
        - name: limit
          in: query
          required: false
          description: Maximum number of results per page.
          schema:
            type: integer
            format: int32
        - name: flow
          in: query
          required: false
          description: 'Flow type: determines which provider config to use.'
          schema:
            $ref: '#/components/schemas/CashFlow'
        - name: customerId
          in: query
          required: false
          description: >-
            Optional customer id. When supplied, results are filtered to
            locations

            the customer is eligible to use (matching their KYC country and, for
            US

            customers, their registered state), so ineligible locations are
            never

            offered. Omit to return all locations in range unfiltered.
          schema:
            type: string
      responses:
        '200':
          description: The request has succeeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CashLocationsResponse'
      tags:
        - CashLocation
  /counterparties:
    get:
      operationId: listCounterparties
      summary: List Counterparties
      description: >-
        List Counterparties. `customerId` is an optional filter — omit it to
        list

        all counterparties in the project (still tenant-scoped by project).
      parameters:
        - $ref: '#/components/parameters/PaginationParams.limit'
        - $ref: '#/components/parameters/PaginationParams.startingAfter'
        - $ref: '#/components/parameters/PaginationParams.endingBefore'
        - name: customerId
          in: query
          required: false
          description: Filter to a single customer (`cst_` prefix).
          schema:
            type: string
      responses:
        '200':
          description: The request has succeeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CounterpartyList'
      tags:
        - Counterparty
    post:
      operationId: createCounterparty
      summary: Create a Counterparty
      description: Create a Counterparty.
      parameters:
        - $ref: '#/components/parameters/IdempotencyKeyHeader'
      responses:
        '201':
          description: >-
            The request has succeeded and a new resource has been created as a
            result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Counterparty'
      tags:
        - Counterparty
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CounterpartyCreateRequest'
  '/counterparties/{counterpartyId}':
    delete:
      operationId: deleteCounterparty
      summary: Delete a Counterparty
      description: |-
        Delete a Counterparty (soft delete). Returns 409 when the counterparty
        still owns active or pending External Accounts.
      parameters:
        - name: counterpartyId
          in: path
          required: true
          description: Counterparty ID (`ctp_` prefix).
          schema:
            type: string
      responses:
        '204':
          description: >-
            There is no content to send for this request, but the headers may be
            useful. 
        '409':
          description: The request conflicts with the current state of the server.
          content:
            application/json:
              schema:
                $ref: >-
                  #/components/schemas/CounterpartyHasActiveExternalAccountsErrorBody
      tags:
        - Counterparty
    get:
      operationId: getCounterparty
      summary: Get a Counterparty
      description: Get a Counterparty by id.
      parameters:
        - name: counterpartyId
          in: path
          required: true
          description: Counterparty ID (`ctp_` prefix).
          schema:
            type: string
      responses:
        '200':
          description: The request has succeeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Counterparty'
      tags:
        - Counterparty
    patch:
      operationId: updateCounterparty
      summary: Update a Counterparty
      description: Update a Counterparty (partial; unknown keys 400).
      parameters:
        - name: counterpartyId
          in: path
          required: true
          description: Counterparty ID (`ctp_` prefix).
          schema:
            type: string
      responses:
        '200':
          description: The request has succeeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Counterparty'
      tags:
        - Counterparty
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CounterpartyUpdateRequest'
  '/customers/{id}/balance':
    get:
      operationId: getCustomerBalance
      summary: Get customer balance
      description: Get the aggregated estimated balance across all customer wallets/assets.
      parameters:
        - name: id
          in: path
          required: true
          description: Customer ID (`cst_` prefix).
          schema:
            type: string
        - name: estimatedBalanceCurrencyCode
          in: query
          required: false
          description: ISO 4217 currency for the estimated value. Defaults to USD.
          schema:
            type: string
      responses:
        '200':
          description: The request has succeeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CustomerBalanceAggregate'
        '400':
          description: The server could not understand the request due to invalid syntax.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InvalidCustomerIdErrorBody'
        '401':
          description: Access is unauthorized.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedErrorBody'
        '404':
          description: The server cannot find the requested resource.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CustomerNotFoundErrorBody'
        '422':
          description: Client error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProviderUserAccountNotFoundErrorBody'
        '502':
          description: Server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProviderErrorBody'
        '503':
          description: Service unavailable.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProviderUnreachableErrorBody'
      tags:
        - Customer
  '/customers/{id}/wallets':
    get:
      operationId: listCustomerWallets
      summary: List customer wallets
      description: >-
        Lists the crypto wallets provisioned for a customer (one per
        asset/chain),

        with cursor-based pagination. Returns an empty list if none have been

        provisioned yet.
      parameters:
        - name: id
          in: path
          required: true
          description: Customer ID (`cst_` prefix).
          schema:
            type: string
        - name: limit
          in: query
          required: false
          description: Maximum number of results per page.
          schema:
            type: integer
            format: int32
        - name: startingAfter
          in: query
          required: false
          description: Return results after this ID (cursor pagination).
          schema:
            type: string
        - name: search
          in: query
          required: false
          description: Free-text search. Matches wallet id or on-chain address.
          schema:
            type: string
        - name: q
          in: query
          required: false
          description: Alias for `search`.
          schema:
            type: string
      responses:
        '200':
          description: The request has succeeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WalletList'
      tags:
        - Wallet
    post:
      operationId: createCustomerWallet
      summary: Create a new wallet asset for a customer
      description: |-
        Provisions a crypto wallet for a customer for the requested asset and
        chain, returning the created wallet. Pass an Idempotency-Key header to
        safely retry without provisioning duplicates.
      parameters:
        - name: id
          in: path
          required: true
          description: Customer ID (`cst_` prefix).
          schema:
            type: string
        - $ref: '#/components/parameters/IdempotencyKeyHeader'
      responses:
        '201':
          description: >-
            The request has succeeded and a new resource has been created as a
            result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BpnWallet'
      tags:
        - Wallet
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WalletCreateRequest'
  /deposit-addresses:
    get:
      operationId: listDepositAddresses
      summary: List all Deposit Addresses
      description: >-
        List all Deposit Addresses across the organization. Spans every customer

        in the caller's organization; optionally filter by status and/or
        customer.
      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:
            $ref: '#/components/schemas/DepositAddressStatus'
        - name: customerId
          in: query
          required: false
          description: Filter to a single customer (`cst_` prefix).
          schema:
            type: string
      responses:
        '200':
          description: The request has succeeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DepositAddressList'
      tags:
        - DepositAddress
    post:
      operationId: createDepositAddress
      summary: Create a Deposit Address
      description: >-
        Create a Deposit Address. Requires deposit addresses to be enabled for
        your

        project and the customer to be provisioned with the banking provider.
        The

        address starts `pending` and becomes `active` once the inbound on-chain

        address is assigned.


        A destination the project is not permitted to deliver to is rejected
        with

        `403 destinationRailNotAllowed` before any address is provisioned: the

        project's outgoing-rail allow-list denies the bank rail, or the routes

        table has no permitted/enabled route for the requested crypto network.
        The

        error body carries `details: { network }` — the denied bank rail (e.g.

        `wire`) or crypto network (e.g. `polygon`). (Not modeled as a typed
        error

        arm here so the other 403 codes on this operation — e.g.

        `vendorConfigMissing`, `ereborConfigMissing` — keep their shape.)
      parameters:
        - $ref: '#/components/parameters/IdempotencyKeyHeader'
      responses:
        '201':
          description: >-
            The request has succeeded and a new resource has been created as a
            result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DepositAddress'
              example:
                id: da_jts3wrvsp6dz04fntj1v4g3hyy
                object: depositAddress
                customerId: cst_vfa0nxw6zvyws9g237jrxn4y7k
                status: pending
                expectedSourceAsset: usdc
                expectedSourceNetwork: ethereum
                destination:
                  party:
                    relationship: customer
                    customerId: cst_vfa0nxw6zvyws9g237jrxn4y7k
                    entityType: individual
                  type: bankUs
                  category: fiatAccount
                  details:
                    id: ext_cc35pa5vgrq1tpsqm4bxy2dkrg
                    asset: usd
                    network: ach
                    accountNumberLast4: '1234'
                    routingNumber: '021000021'
                    bankName: Chase
                    accountType: checking
                  payoutOrigin:
                    type: bank
                    details:
                      accountHolder: customer
                      accountHolderName: Jane Smith
                label: Alice deposit address
                createdAt: '2026-05-14T10:00:00Z'
                updatedAt: '2026-05-14T10:00:00Z'
        '422':
          description: >-
            Returned by the Virtual Account / Deposit Address create when the
            provider terminally rejects the provisioning call. No resource is
            created — provisioning happens before any row is inserted.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EreborValidationFailedErrorBody'
      tags:
        - DepositAddress
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DepositAddressCreateRequest'
  '/deposit-addresses/{depositAddressId}':
    get:
      operationId: getDepositAddress
      summary: Get a Deposit Address
      description: Fetch a Deposit Address by ID.
      parameters:
        - name: depositAddressId
          in: path
          required: true
          description: Deposit Address ID (`da_` prefix).
          schema:
            type: string
      responses:
        '200':
          description: The request has succeeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DepositAddress'
              examples:
                Active deposit address delivering to a US bank account:
                  summary: Active deposit address delivering to a US bank account
                  value:
                    id: da_n1m2ff68sd8ykvt4xswtq7e015
                    object: depositAddress
                    customerId: cst_vfa0nxw6zvyws9g237jrxn4y7k
                    status: active
                    expectedSourceAsset: usdc
                    expectedSourceNetwork: polygon
                    destination:
                      party:
                        relationship: customer
                        customerId: cst_vfa0nxw6zvyws9g237jrxn4y7k
                        entityType: individual
                      type: bankUs
                      category: fiatAccount
                      details:
                        id: ext_cc35pa5vgrq1tpsqm4bxy2dkrg
                        asset: usd
                        network: ach
                        accountNumberLast4: '1234'
                        routingNumber: '021000021'
                        bankName: Chase
                        accountType: checking
                      payoutOrigin:
                        type: bank
                        details:
                          accountHolder: customer
                          accountHolderName: Jane Smith
                    depositInstructions:
                      asset: usdc
                      network: ethereum
                      address: '0x7B3A9F2C4D1eA8bf6390cE5D2b7fA104c8e3D9B1'
                    label: Alice USD payouts
                    createdAt: '2026-03-14T19:00:00Z'
                    updatedAt: '2026-03-14T19:00:00Z'
      tags:
        - DepositAddress
    patch:
      operationId: updateDepositAddress
      summary: Update a Deposit Address
      description: >-
        Update a Deposit Address. The patchable fields are `destination`

        (re-point to a different bank-type External Account),
        `returnDestination`,

        `label`, and `metadata`; any other JSON key in the body is rejected with
        400.

        Re-pointing `destination` to a healthy bank External Account recovers a
        DA

        from `inactiveActionRequired` back to `active`.
      parameters:
        - name: depositAddressId
          in: path
          required: true
          description: Deposit Address ID (`da_` prefix).
          schema:
            type: string
      responses:
        '200':
          description: The request has succeeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DepositAddress'
      tags:
        - DepositAddress
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DepositAddressUpdateRequest'
  '/deposit-addresses/{depositAddressId}/transactions':
    get:
      operationId: listDepositAddressTransactions
      summary: List Deposit Address transactions
      description: >-
        Returns the payment transactions that originated from this Deposit

        Address, most recent first, with cursor-based pagination. Uses the same

        grouped payment read model as `GET /transactions`, pinned to this
        deposit

        address (equivalent to `GET /transactions?depositAddressId=`).


        This is a collection filter: it always returns `200` with the matching

        transactions. An unknown, deleted, or other-tenant `depositAddressId`

        simply matches no rows and yields an empty list — it is not a `404`. Use

        `GET /deposit-addresses/{depositAddressId}` to assert
        existence/ownership.
      parameters:
        - name: depositAddressId
          in: path
          required: true
          description: Deposit Address ID (`da_` prefix).
          schema:
            type: string
        - $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 (sender or recipient). `cst_` prefix.
          schema:
            type: string
        - 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.
          schema:
            type: array
            items:
              type: string
      responses:
        '200':
          description: The request has succeeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TransactionList'
      tags:
        - DepositAddress
  /external-accounts:
    get:
      operationId: listExternalAccounts
      summary: List External Accounts
      description: >-
        List External Accounts. Both `customerId` and `counterpartyId` are
        optional

        filters — omit both to list all external accounts in the project (still

        tenant-scoped by project).
      parameters:
        - $ref: '#/components/parameters/PaginationParams.limit'
        - $ref: '#/components/parameters/PaginationParams.startingAfter'
        - $ref: '#/components/parameters/PaginationParams.endingBefore'
        - name: customerId
          in: query
          required: false
          description: Filter to a single customer (`cst_` prefix).
          schema:
            type: string
        - name: counterpartyId
          in: query
          required: false
          description: Counterparty ID (`ctp_` prefix).
          schema:
            type: string
      responses:
        '200':
          description: The request has succeeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ExternalAccountList'
      tags:
        - ExternalAccount
    post:
      operationId: createExternalAccount
      summary: Create an External Account
      description: >-
        Create an External Account (saved payment destination). Provisions

        synchronously against the configured payment provider; the account
        starts

        `pending` and flips to `active` or `failed`. Exactly one per-type detail

        object must match `type`. The owner discriminator determines whether
        this

        account belongs to a customer directly or to one of the customer's

        counterparties.
      parameters:
        - $ref: '#/components/parameters/IdempotencyKeyHeader'
      responses:
        '201':
          description: >-
            The request has succeeded and a new resource has been created as a
            result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ExternalAccount'
              examples:
                'walletExternal, registration resolved a held inbound':
                  summary: 'walletExternal, registration resolved a held inbound'
                  value:
                    id: ext_95863ktcdhw27ze8hxgybb24n9
                    object: externalAccount
                    type: walletExternal
                    category: crypto
                    owner:
                      kind: counterparty
                      counterpartyId: ctp_yp5z8m7n22svc0vh6edqgcfdat
                    status: active
                    resolvedTransactions:
                      - txn_x9waqqeg1ng6v32c5142zfp89d
                    label: Acme deposits inbound
                    createdAt: '2026-05-15T18:01:12Z'
                    updatedAt: '2026-05-15T18:01:12Z'
                    walletExternal:
                      blockchainAddress: '0xeB3eCfb244E94a407bfb1EEcFEDe27D920cc00F5'
                      custodian: COINBASE_US
                      networkFamily: evm
                'Canadian bank account, customer-owned':
                  summary: 'Canadian bank account, customer-owned'
                  value:
                    id: ext_p4m9c2v7k1n5q8r3s6t0w2x4yz
                    object: externalAccount
                    type: bankCanada
                    category: fiatAccount
                    owner:
                      kind: customer
                      customerId: cst_vfa0nxw6zvyws9g237jrxn4y7k
                    status: pending
                    label: Bob CAD payouts
                    createdAt: '2026-05-14T10:05:00Z'
                    updatedAt: '2026-05-14T10:05:00Z'
                    bankCanada:
                      institutionNumber: '003'
                      transitNumber: '12345'
                      accountNumberLast4: '4567'
                      bankName: Royal Bank of Canada
                'US bank account, customer-owned':
                  summary: 'US bank account, customer-owned'
                  value:
                    id: ext_cc35pa5vgrq1tpsqm4bxy2dkrg
                    object: externalAccount
                    type: bankUs
                    category: fiatAccount
                    owner:
                      kind: customer
                      customerId: cst_vfa0nxw6zvyws9g237jrxn4y7k
                    status: pending
                    createdAt: '2026-05-14T10:00:00Z'
                    updatedAt: '2026-05-14T10:00:00Z'
                    bankUs:
                      accountNumberLast4: '3210'
                      routingNumber: '021000021'
                      accountType: checking
                      bankName: Chase
        '422':
          description: >-
            Returned by `POST /external-accounts` when the provider terminally
            rejects the provisioning call. The External Account IS persisted as
            `status = failed` carrying the same detail as `failureDetail`, so a
            follow-up GET returns it.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ExternalAccountRejectedErrorBody'
      tags:
        - ExternalAccount
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ExternalAccountCreateRequest'
            examples:
              External wallet owned by a counterparty:
                summary: External wallet owned by a counterparty
                value:
                  label: Acme deposits
                  owner:
                    kind: counterparty
                    counterpartyId: ctp_1x0yvbj459mtzq609n8p33twd1
                  type: walletExternal
                  walletExternal:
                    blockchainAddress: '0xbEeF4A2C891d56e72B67a3f21d0cF94f1D7c5911'
                    networkFamily: evm
                    custodian: COINBASE_US
              'Canadian bank account, customer-owned':
                summary: 'Canadian bank account, customer-owned'
                value:
                  label: Bob CAD payouts
                  owner:
                    kind: customer
                    customerId: cst_vfa0nxw6zvyws9g237jrxn4y7k
                  type: bankCanada
                  bankCanada:
                    institutionNumber: '003'
                    transitNumber: '12345'
                    accountNumber: '1234567'
                    bankName: Royal Bank of Canada
              'US bank account, customer-owned':
                summary: 'US bank account, customer-owned'
                value:
                  label: Alice payouts to Chase
                  owner:
                    kind: customer
                    customerId: cst_vfa0nxw6zvyws9g237jrxn4y7k
                  type: bankUs
                  bankUs:
                    accountNumber: '9876543210'
                    routingNumber: '021000021'
                    accountType: checking
                    bankName: Chase
  '/external-accounts/{externalAccountId}':
    delete:
      operationId: deleteExternalAccount
      summary: Delete an External Account
      description: Delete an External Account (soft delete).
      parameters:
        - name: externalAccountId
          in: path
          required: true
          description: External Account ID (`ext_` prefix).
          schema:
            type: string
      responses:
        '204':
          description: >-
            There is no content to send for this request, but the headers may be
            useful. 
      tags:
        - ExternalAccount
    get:
      operationId: getExternalAccount
      summary: Get an External Account
      description: Get an External Account by id.
      parameters:
        - name: externalAccountId
          in: path
          required: true
          description: External Account ID (`ext_` prefix).
          schema:
            type: string
      responses:
        '200':
          description: The request has succeeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ExternalAccount'
      tags:
        - ExternalAccount
    patch:
      operationId: updateExternalAccount
      summary: Update an External Account
      description: |-
        Update an External Account. Only `label` and `metadata` are mutable; any
        other JSON key in the body is rejected with 400.
      parameters:
        - name: externalAccountId
          in: path
          required: true
          description: External Account ID (`ext_` prefix).
          schema:
            type: string
      responses:
        '200':
          description: The request has succeeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ExternalAccount'
      tags:
        - ExternalAccount
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ExternalAccountUpdateRequest'
  /networks:
    get:
      operationId: listNetworks
      summary: List supported networks
      description: >-
        Lists every network BPN supports, with its identifiers, available
        assets,

        and which OMS resources can use it in which direction. Availability is

        derived from live route configuration, so a network absent from this
        list

        is not routable. Fiat-rail availability reflects the calling project's
        own

        configuration; crypto networks are global.


        "Network" here means any rail, not only a blockchain: `category`

        (`crypto` | `fiatAccount` | `cash`) and `type` (`blockchain` |
        `bankRail` |

        `card` | `physical`) are what distinguish them, and `chainId` /

        `networkFamily` are absent on everything that is not a blockchain.


        Declared here, beside the other Reference operations, to match the

        ratified OMS v0.12 contract — which tags `/networks`, `/assets` and

        `/reference/account-type-requirements` alike. The handler lives in

        `services/platform`; tag and Go package are independent, exactly as

        `getAccountTypeRequirements` above is served from

        `services/externalaccount`.
      parameters: []
      responses:
        '200':
          description: The request has succeeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NetworkListResponse'
      tags:
        - Reference
  /quotes:
    post:
      operationId: createQuote
      summary: Create a payment quote
      description: >-
        Creates a payment quote with a locked exchange rate and fee breakdown
        for a

        prospective transfer. Quotes expire after a short window; reference the

        returned quote ID when executing the transaction. Pass an
        Idempotency-Key

        header to safely retry.


        A disallowed source→destination instrument pair is rejected with

        `422 unsupportedInstrumentCombination` before any quote is created; the

        error body carries a `details` object of

        `{ source, destination, supportedDestinations }`. (Not modeled as a
        typed

        error arm here so the other 422 codes on this operation keep their
        shape.)
      parameters:
        - $ref: '#/components/parameters/IdempotencyKeyHeader'
      responses:
        '201':
          description: >-
            The request has succeeded and a new resource has been created as a
            result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Quote'
      tags:
        - Quote
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/QuoteCreateRequest'
  '/quotes/{quoteId}':
    get:
      operationId: getQuote
      summary: Get quote by ID
      description: |-
        Retrieves a previously created quote by ID, including its locked rate,
        fee breakdown, and expiry.
      parameters:
        - name: quoteId
          in: path
          required: true
          description: Quote ID (`qt_` prefix).
          schema:
            type: string
      responses:
        '200':
          description: The request has succeeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Quote'
      tags:
        - Quote
  /transactions:
    get:
      operationId: listTransactions
      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.
      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 the transaction's originating OMS wallet (the precursor's
            source wallet). `wlt_` prefix (legacy `acc_` also accepted).
          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`.

            `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'
      tags:
        - Transaction
    post:
      operationId: createTransaction
      summary: Execute a transaction (send)
      description: >-
        Executes a transfer by accepting an open quote. Reference the quote by
        its

        ID; OMS pulls funds from the quote's source and delivers them to its

        destination. Pass an Idempotency-Key header to safely retry without
        sending

        twice.
      parameters:
        - $ref: '#/components/parameters/IdempotencyKeyHeader'
      responses:
        '201':
          description: >-
            The request has succeeded and a new resource has been created as a
            result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Transaction'
              examples:
                'Just created from a quote, funds pulled, settling':
                  summary: 'Just created from a quote, funds pulled, settling'
                  value:
                    id: txn_hdgebv2mns4af7pgs5r6kkacxh
                    object: transaction
                    sourceToDestination: cryptoToFiatAccount
                    status: processing
                    subStatus: processing.fundsPulled
                    customerId: cst_vfa0nxw6zvyws9g237jrxn4y7k
                    precursor:
                      type: quote
                      details:
                        quoteId: qt_0gq9aesz4wb5etdv88z1j61qcm
                    source:
                      party:
                        relationship: customer
                        customerId: cst_vfa0nxw6zvyws9g237jrxn4y7k
                        entityType: individual
                      type: walletOms
                      category: crypto
                      details:
                        id: wlt_5h4jzzpr9xre3bamd9ca7qyghn
                        asset: usdc
                        network: polygon
                        blockchainAddress: '0x7B3A9F2C4D1eA8bf6390cE5D2b7fA104c8e3D9B1'
                        txHash: '0x8a3b7c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b'
                        custodyType: custodial
                    destination:
                      party:
                        relationship: externalRegistered
                        counterpartyId: ctp_yp5z8m7n22svc0vh6edqgcfdat
                        entityType: individual
                        name: Alice Smith
                        address:
                          line1: 500 Market St
                          city: San Francisco
                          state: CA
                          country: US
                          zipCode: '94105'
                      type: bankUs
                      category: fiatAccount
                      details:
                        id: ext_fky491gakzj0dd46qb6whsr2vq
                        asset: usd
                        network: ach
                        secCode: web
                        accountNumberLast4: '1234'
                        routingNumber: '021000021'
                        bankName: Chase
                        accountType: checking
                      payoutOrigin:
                        type: bank
                        details:
                          accountHolder: customer
                          accountHolderName: Jane Smith
                          accountNumber: '9876543210'
                          routingNumber: '125109161'
                          virtualAccountId: va_e6nfr4q5jj9bwgb1pyx70wzxta
                    pricing:
                      source:
                        asset: usdc
                        amountGross: '100.00'
                        amountNet: '100.00'
                        feesDeducted:
                          total: '0.00'
                          developer: '0.00'
                          oms: '0.00'
                          gas: '0.00'
                      destination:
                        asset: usd
                        amountGross: '100.00'
                        amountNet: '100.00'
                        feesDeducted:
                          total: '0.00'
                          developer: '0.00'
                          oms: '0.00'
                          gas: '0.00'
                      pair: usdc/usd
                      exchangeRate: '1.0000'
                      effectiveRate: '1.0000'
                      fixedAmountSide: source
                      sponsorGas: true
                      sponsorGasCost: '0.00'
                    estimatedArrival: '2026-03-14T19:30:00Z'
                    metadata:
                      orderId: order_12345
                    createdAt: '2026-03-14T19:00:00Z'
                    updatedAt: '2026-03-14T19:00:20Z'
        '502':
          description: Server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Transaction'
      tags:
        - Transaction
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TransactionCreateRequest'
  '/transactions/{transactionId}':
    get:
      operationId: getTransaction
      summary: Get transaction by ID
      description: Retrieves a single transaction by ID.
      parameters:
        - name: transactionId
          in: path
          required: true
          description: Transaction ID (`txn_` prefix).
          schema:
            type: string
      responses:
        '200':
          description: The request has succeeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Transaction'
              examples:
                'Failed transfer, inbound returned to the registered wallet':
                  summary: 'Failed transfer, inbound returned to the registered wallet'
                  value:
                    id: txn_mmbdyjd3r0z92y1zwck56anv0r
                    object: transaction
                    sourceToDestination: cryptoToCrypto
                    status: failed
                    subStatus: failed.returnComplete
                    customerId: cst_vfa0nxw6zvyws9g237jrxn4y7k
                    precursor:
                      type: quote
                      details:
                        quoteId: qt_6yd7gwfxaa13m83sepnzrmqnj2
                    source:
                      party:
                        relationship: customer
                        customerId: cst_vfa0nxw6zvyws9g237jrxn4y7k
                        entityType: individual
                      type: walletOms
                      category: crypto
                      details:
                        id: wlt_5h4jzzpr9xre3bamd9ca7qyghn
                        asset: usdc
                        network: polygon
                        blockchainAddress: '0x7B3A9F2C4D1eA8bf6390cE5D2b7fA104c8e3D9B1'
                        txHash: '0x8a3b7c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b'
                        custodyType: custodial
                    destination:
                      party:
                        relationship: externalRegistered
                        counterpartyId: ctp_yp5z8m7n22svc0vh6edqgcfdat
                        entityType: individual
                        name: Alice Smith
                        address:
                          line1: 500 Market St
                          city: San Francisco
                          state: CA
                          country: US
                          zipCode: '94105'
                      type: walletExternal
                      category: crypto
                      details:
                        id: ext_95863ktcdhw27ze8hxgybb24n9
                        asset: usdc
                        network: base
                        blockchainAddress: '0xbEeF4A2C891d56e72B67a3f21d0cF94f1D7c5911'
                        custodian: COINBASE_US
                      payoutOrigin:
                        type: blockchain
                        blockchainAddress: '0x7B3A9F2C4D1eA8bf6390cE5D2b7fA104c8e3D9B1'
                        network: base
                    pricing:
                      source:
                        asset: usdc
                        amountGross: '100.00'
                        amountNet: '100.00'
                        feesDeducted:
                          total: '0.00'
                          developer: '0.00'
                          oms: '0.00'
                          gas: '0.00'
                      destination:
                        asset: usdc
                        amountGross: '100.00'
                        amountNet: '100.00'
                        feesDeducted:
                          total: '0.00'
                          developer: '0.00'
                          oms: '0.00'
                          gas: '0.00'
                      pair: usdc/usdc
                      exchangeRate: '1.0000'
                      effectiveRate: '1.0000'
                      fixedAmountSide: source
                      sponsorGas: true
                      sponsorGasCost: '0.00'
                    error:
                      code: bridgeTimeout
                      message: Bridge transaction timed out after 30 minutes.
                      occurredAt: '2026-03-14T19:35:00Z'
                      recoverable: false
                    createdAt: '2026-03-14T19:00:00Z'
                    updatedAt: '2026-03-14T19:35:00Z'
                'Deposit-address inbound from an unrecognized sender, awaiting attribution':
                  summary: >-
                    Deposit-address inbound from an unrecognized sender,
                    awaiting attribution
                  value:
                    id: txn_x9waqqeg1ng6v32c5142zfp89d
                    object: transaction
                    sourceToDestination: cryptoToFiatAccount
                    status: awaitingAction
                    subStatus: awaitingAction.awaitingSenderAttribution
                    customerId: cst_vfa0nxw6zvyws9g237jrxn4y7k
                    precursor:
                      type: depositAddress
                      details:
                        depositAddressId: da_r8f126hqwm3x6j5k00qsaysf4c
                        depositInstructions:
                          asset: usdc
                          network: polygon
                          address: '0x7B3A9F2C4D1eA8bf6390cE5D2b7fA104c8e3D9B1'
                    source:
                      party:
                        relationship: externalUnregistered
                      type: walletExternal
                      category: crypto
                      details:
                        asset: usdc
                        network: polygon
                        blockchainAddress: '0xeB3eCfb244E94a407bfb1EEcFEDe27D920cc00F5'
                        txHash: '0x98cd34db5e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b'
                    destination:
                      party:
                        relationship: customer
                        customerId: cst_vfa0nxw6zvyws9g237jrxn4y7k
                        entityType: individual
                      type: bankUs
                      category: fiatAccount
                      details:
                        id: ext_cc35pa5vgrq1tpsqm4bxy2dkrg
                        asset: usd
                        network: ach
                        secCode: web
                        accountNumberLast4: '1234'
                        routingNumber: '021000021'
                        bankName: Chase
                        accountType: checking
                    pricing:
                      source:
                        asset: usdc
                        amountGross: '250.00'
                        amountNet: '250.00'
                        feesDeducted:
                          total: '0.00'
                          developer: '0.00'
                          oms: '0.00'
                          gas: '0.00'
                      destination:
                        asset: usd
                        amountGross: '250.00'
                        amountNet: '250.00'
                        feesDeducted:
                          total: '0.00'
                          developer: '0.00'
                          oms: '0.00'
                          gas: '0.00'
                      pair: usdc/usd
                      exchangeRate: '1.0000'
                      effectiveRate: '1.0000'
                      fixedAmountSide: source
                      sponsorGas: true
                      sponsorGasCost: '0.00'
                    hold:
                      type: senderAttribution
                      required: true
                      since: '2026-05-15T17:32:48Z'
                      deadline: '2026-06-14T17:32:48Z'
                      txHash: '0x98cd34db5e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b'
                      matchableExternalAccountCriteria:
                        type: walletExternal
                        customerId: cst_vfa0nxw6zvyws9g237jrxn4y7k
                        blockchainAddress: '0xeB3eCfb244E94a407bfb1EEcFEDe27D920cc00F5'
                        networkFamily: evm
                    createdAt: '2026-05-15T17:32:48Z'
                    updatedAt: '2026-05-15T17:32:48Z'
                Cash payout with a pickup code ready at a retail location:
                  summary: Cash payout with a pickup code ready at a retail location
                  value:
                    id: txn_t21b4031yen78cqx2t93crbs66
                    object: transaction
                    sourceToDestination: cryptoToCash
                    status: processing
                    subStatus: processing.cashPickupReady
                    customerId: cst_vfa0nxw6zvyws9g237jrxn4y7k
                    precursor:
                      type: quote
                      details:
                        quoteId: qt_3qj8x54e73641hrabft05xc6fv
                    source:
                      party:
                        relationship: customer
                        customerId: cst_vfa0nxw6zvyws9g237jrxn4y7k
                        entityType: individual
                      type: walletOms
                      category: crypto
                      details:
                        id: wlt_5h4jzzpr9xre3bamd9ca7qyghn
                        asset: usdc
                        network: polygon
                        blockchainAddress: '0x7B3A9F2C4D1eA8bf6390cE5D2b7fA104c8e3D9B1'
                        txHash: '0x8a3b7c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b'
                        custodyType: custodial
                    destination:
                      party:
                        relationship: customer
                        customerId: cst_vfa0nxw6zvyws9g237jrxn4y7k
                        entityType: individual
                      type: cash
                      category: cash
                      details:
                        asset: usd
                        cashLocationId: loc_01H9Xd
                        cashLocationReference: QUxMUE9JTlQtNzc4OA==
                        expiresAt: '2026-03-14T21:00:00Z'
                        locationName: 'Walmart #2517'
                        locationAddress: '700 NW 8th Ave, Bentonville, AR 72712'
                    pricing:
                      source:
                        asset: usdc
                        amountGross: '100.00'
                        amountNet: '100.00'
                        feesDeducted:
                          total: '0.00'
                          developer: '0.00'
                          oms: '0.00'
                          gas: '0.00'
                      destination:
                        asset: usd
                        amountGross: '100.00'
                        amountNet: '100.00'
                        feesDeducted:
                          total: '0.00'
                          developer: '0.00'
                          oms: '0.00'
                          gas: '0.00'
                      pair: usdc/usd
                      exchangeRate: '1.0000'
                      effectiveRate: '1.0000'
                      fixedAmountSide: destination
                      sponsorGas: true
                      sponsorGasCost: '0.00'
                    createdAt: '2026-03-14T20:00:00Z'
                    updatedAt: '2026-03-14T20:00:30Z'
                    expiresAt: '2026-03-14T21:00:00Z'
                Completed payout from an OMS wallet to a US bank account:
                  summary: Completed payout from an OMS wallet to a US bank account
                  value:
                    id: txn_qv6ch9rjv7t8nncezke4s10a3z
                    object: transaction
                    sourceToDestination: cryptoToFiatAccount
                    status: completed
                    customerId: cst_vfa0nxw6zvyws9g237jrxn4y7k
                    precursor:
                      type: quote
                      details:
                        quoteId: qt_0gq9aesz4wb5etdv88z1j61qcm
                    source:
                      party:
                        relationship: customer
                        customerId: cst_vfa0nxw6zvyws9g237jrxn4y7k
                        entityType: individual
                      type: walletOms
                      category: crypto
                      details:
                        id: wlt_5h4jzzpr9xre3bamd9ca7qyghn
                        asset: usdc
                        network: polygon
                        blockchainAddress: '0x7B3A9F2C4D1eA8bf6390cE5D2b7fA104c8e3D9B1'
                        txHash: '0x8a3b7c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b'
                        custodyType: custodial
                    destination:
                      party:
                        relationship: externalRegistered
                        counterpartyId: ctp_yp5z8m7n22svc0vh6edqgcfdat
                        entityType: individual
                        name: Alice Smith
                        address:
                          line1: 500 Market St
                          city: San Francisco
                          state: CA
                          country: US
                          zipCode: '94105'
                      type: bankUs
                      category: fiatAccount
                      details:
                        id: ext_fky491gakzj0dd46qb6whsr2vq
                        asset: usd
                        network: ach
                        secCode: web
                        accountNumberLast4: '1234'
                        routingNumber: '021000021'
                        bankName: Chase
                        accountType: checking
                      payoutOrigin:
                        type: bank
                        details:
                          accountHolder: customer
                          accountHolderName: Jane Smith
                          accountNumber: '9876543210'
                          routingNumber: '125109161'
                          virtualAccountId: va_e6nfr4q5jj9bwgb1pyx70wzxta
                    pricing:
                      source:
                        asset: usdc
                        amountGross: '100.00'
                        amountNet: '100.00'
                        feesDeducted:
                          total: '0.00'
                          developer: '0.00'
                          oms: '0.00'
                          gas: '0.00'
                      destination:
                        asset: usd
                        amountGross: '100.00'
                        amountNet: '100.00'
                        feesDeducted:
                          total: '0.00'
                          developer: '0.00'
                          oms: '0.00'
                          gas: '0.00'
                      pair: usdc/usd
                      exchangeRate: '1.0000'
                      effectiveRate: '1.0000'
                      fixedAmountSide: source
                      sponsorGas: true
                      sponsorGasCost: '0.00'
                    estimatedArrival: '2026-03-14T19:30:00Z'
                    metadata:
                      orderId: order_12345
                    createdAt: '2026-03-14T19:00:00Z'
                    updatedAt: '2026-03-14T19:05:00Z'
      tags:
        - Transaction
  /virtual-accounts:
    get:
      operationId: listVirtualAccounts
      summary: List all Virtual Accounts
      description: >-
        List all Virtual Accounts across the organization. Spans every customer

        in the caller's organization; optionally filter by status and/or
        customer.
      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:
            $ref: '#/components/schemas/VirtualAccountStatus'
        - name: customerId
          in: query
          required: false
          description: Filter to a single customer (`cst_` prefix).
          schema:
            type: string
      responses:
        '200':
          description: The request has succeeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VirtualAccountList'
      tags:
        - VirtualAccount
    post:
      operationId: createVirtualAccount
      summary: Create a Virtual Account
      description: >-
        Create a Virtual Account for a customer. Partner must have
        virtual_account_provider configured.
      parameters:
        - $ref: '#/components/parameters/IdempotencyKeyHeader'
      responses:
        '201':
          description: >-
            The request has succeeded and a new resource has been created as a
            result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VirtualAccount'
              example:
                id: va_8rzhjp17c4kdp2n3gg79te9zmw
                object: virtualAccount
                customerId: cst_vfa0nxw6zvyws9g237jrxn4y7k
                status: pending
                destination:
                  party:
                    relationship: customer
                    customerId: cst_vfa0nxw6zvyws9g237jrxn4y7k
                    entityType: individual
                  type: walletExternal
                  category: crypto
                  details:
                    id: ext_fky491gakzj0dd46qb6whsr2vq
                    asset: usdc
                    network: ethereum
                    blockchainAddress: '0x7B3A9F2C4D1eA8bf6390cE5D2b7fA104c8e3D9B1'
                    custodian: SELF_HOSTED
                label: Alice USD deposit account
                createdAt: '2026-05-14T10:00:00Z'
                updatedAt: '2026-05-14T10:00:00Z'
        '422':
          description: >-
            Returned by the Virtual Account / Deposit Address create when the
            provider terminally rejects the provisioning call. No resource is
            created — provisioning happens before any row is inserted.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EreborValidationFailedErrorBody'
      tags:
        - VirtualAccount
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/VirtualAccountCreateRequest'
  '/virtual-accounts/{virtualAccountId}':
    delete:
      operationId: deleteVirtualAccount
      summary: Delete a Virtual Account
      description: >-
        Delete a customer's Virtual Account. Initiates the close flow against

        the underlying Erebor DDA; the VA enters the delete-pending window

        (status remains as-is, `deletionRequestedAt` set) and finalizes to

        `deleted` on the subsequent `DEPOSIT_ACCOUNT.CLOSED` webhook.


        Returns `503 virtualAccountCloseUnavailable` when the underlying Erebor

        close primitive is not yet available for this account — the VA is not

        deleted and remains active/deletable, and the request can be retried
        later.
      parameters:
        - name: virtualAccountId
          in: path
          required: true
          description: Virtual Account ID (`va_` prefix).
          schema:
            type: string
      responses:
        '204':
          description: >-
            There is no content to send for this request, but the headers may be
            useful. 
        '503':
          description: |-
            Returned by `DELETE /virtual-accounts/{virtualAccountId}` when the
            underlying Erebor account-close primitive is not yet available. The
            `Retry-After` header gives the seconds the caller should wait before
            retrying; the virtual account is not deleted and remains active (no
            delete-pending marker persists).
          headers:
            retry-after:
              required: true
              description: Seconds until a retry may succeed.
              schema:
                type: integer
                format: int32
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VirtualAccountCloseUnavailableErrorBody'
      tags:
        - VirtualAccount
    get:
      operationId: getVirtualAccount
      summary: Get a Virtual Account
      description: Fetch a Virtual Account by ID.
      parameters:
        - name: virtualAccountId
          in: path
          required: true
          description: Virtual Account ID (`va_` prefix).
          schema:
            type: string
      responses:
        '200':
          description: The request has succeeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VirtualAccount'
              examples:
                Active virtual account with US bank routing details:
                  summary: Active virtual account with US bank routing details
                  value:
                    id: va_bztg5dcpfbec9s0jkq28d5meq3
                    object: virtualAccount
                    customerId: cst_vfa0nxw6zvyws9g237jrxn4y7k
                    status: active
                    destination:
                      party:
                        relationship: customer
                        customerId: cst_vfa0nxw6zvyws9g237jrxn4y7k
                        entityType: individual
                      type: walletExternal
                      category: crypto
                      details:
                        id: ext_fky491gakzj0dd46qb6whsr2vq
                        asset: usdc
                        network: ethereum
                        blockchainAddress: '0x7B3A9F2C4D1eA8bf6390cE5D2b7fA104c8e3D9B1'
                        custodian: SELF_HOSTED
                    label: Alice USD deposit account
                    createdAt: '2026-03-14T19:00:00Z'
                    updatedAt: '2026-03-14T19:00:00Z'
      tags:
        - VirtualAccount
    patch:
      operationId: updateVirtualAccount
      summary: Update a Virtual Account
      description: |-
        Update a Virtual Account. Patchable fields: `destination` (re-point),
        `sponsorGas`, `label`, `metadata`; any other JSON key is rejected with
        400. Re-pointing `destination` to a healthy External Account recovers a
        VA from `inactiveActionRequired` back to `active`.
      parameters:
        - name: virtualAccountId
          in: path
          required: true
          description: Virtual Account ID (`va_` prefix).
          schema:
            type: string
      responses:
        '200':
          description: The request has succeeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VirtualAccount'
      tags:
        - VirtualAccount
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/VirtualAccountUpdateRequest'
  '/virtual-accounts/{virtualAccountId}/simulate/inbound-transfer':
    post:
      operationId: simulateVirtualAccountInboundTransfer
      summary: Simulate inbound transfer on a Virtual Account
      description: |-
        Simulate an inbound fiat transfer against a Virtual Account, for testing
        webhook and reconciliation flows. Sandbox / non-production only; returns
        404 in production-live. Set the `type` field in the request body to
        choose the transfer rail: `bankUs` (network `ach` or `wire`) or
        `bankIban` (network `swift`).
      parameters:
        - name: virtualAccountId
          in: path
          required: true
          schema:
            type: string
        - $ref: '#/components/parameters/IdempotencyKeyHeader'
      responses:
        '200':
          description: The request has succeeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SimulateVaInboundTransferResponse'
              examples:
                International SWIFT inbound (settles asynchronously):
                  summary: International SWIFT inbound (settles asynchronously)
                  value:
                    virtualAccountId: va_bztg5dcpfbec9s0jkq28d5meq3
                    type: bankIban
                    network: swift
                    asset: usd
                    amount: '500.00'
                    status: pending
                    submittedAt: '2026-07-13T19:05:00Z'
                    referenceId: intl_wire_in_9f3c2a7b8d1e4056
                US domestic ACH inbound (settles synchronously):
                  summary: US domestic ACH inbound (settles synchronously)
                  value:
                    virtualAccountId: va_bztg5dcpfbec9s0jkq28d5meq3
                    type: bankUs
                    network: ach
                    asset: usd
                    amount: '250.00'
                    status: submitted
                    submittedAt: '2026-07-13T19:00:00Z'
                    referenceId: null
      tags:
        - Sandbox
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SimulateVaInboundTransferRequest'
            examples:
              International SWIFT inbound (settles asynchronously):
                summary: International SWIFT inbound (settles asynchronously)
                value:
                  type: bankIban
                  network: swift
                  asset: usd
                  amount: '500.00'
              US domestic ACH inbound (settles synchronously):
                summary: US domestic ACH inbound (settles synchronously)
                value:
                  type: bankUs
                  network: ach
                  asset: usd
                  amount: '250.00'
      x-server-scope: non-prod-live
  '/virtual-accounts/{virtualAccountId}/transactions':
    get:
      operationId: listVirtualAccountTransactions
      summary: List Virtual Account transactions
      description: >-
        Returns the payment transactions that originated from this Virtual

        Account, most recent first, with cursor-based pagination. Uses the same

        grouped payment read model as `GET /transactions`, pinned to this
        virtual

        account (equivalent to `GET /transactions?virtualAccountId=`).


        This is a collection filter: it always returns `200` with the matching

        transactions. An unknown, deleted, or other-tenant `virtualAccountId`

        simply matches no rows and yields an empty list — it is not a `404`. Use

        `GET /virtual-accounts/{virtualAccountId}` to assert
        existence/ownership.
      parameters:
        - name: virtualAccountId
          in: path
          required: true
          description: Virtual Account ID (`va_` prefix).
          schema:
            type: string
        - $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 (sender or recipient). `cst_` prefix.
          schema:
            type: string
        - 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.
          schema:
            type: array
            items:
              type: string
      responses:
        '200':
          description: The request has succeeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TransactionList'
      tags:
        - VirtualAccount
  '/wallets/{id}/balance':
    get:
      operationId: getWalletBalance
      summary: Get current balance of a specific wallet
      description: |-
        Returns the current balance of a specific wallet, including the display
        balance and its estimated value in the currency requested via
        `estimatedBalanceCurrencyCode` (defaults to USD).
      parameters:
        - name: id
          in: path
          required: true
          description: Wallet ID.
          schema:
            type: string
        - name: estimatedBalanceCurrencyCode
          in: query
          required: false
          description: ISO 4217 currency for the estimated value. Defaults to USD.
          schema:
            type: string
      responses:
        '200':
          description: The request has succeeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WalletBalance'
      tags:
        - Wallet
  '/wallets/{id}/transactions':
    get:
      operationId: listWalletTransactions
      summary: List wallet transactions
      description: >-
        Returns the transaction history for the specified wallet, most recent

        first, with cursor-based pagination and optional type/date filters. Each

        entry is a single account-ledger movement (credit, debit, hold, or

        release), covering both inbound and outbound activity on the wallet.
        Each

        carries a `balanceAfter` snapshot taken when the entry was written — see

        that field; it is not a guaranteed running total.
      parameters:
        - name: id
          in: path
          required: true
          description: Wallet ID (`wlt_` prefix; legacy `acc_` also accepted).
          schema:
            type: string
        - $ref: '#/components/parameters/PaginationParams.limit'
        - $ref: '#/components/parameters/PaginationParams.startingAfter'
        - $ref: '#/components/parameters/PaginationParams.endingBefore'
        - name: transactionType
          in: query
          required: false
          description: Filter by ledger entry type.
          schema:
            $ref: '#/components/schemas/TransactionType'
        - name: since
          in: query
          required: false
          description: Inclusive start of the date range.
          schema:
            type: string
        - name: until
          in: query
          required: false
          description: Inclusive end of the date range.
          schema:
            type: string
      responses:
        '200':
          description: The request has succeeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AccountTransactionList'
      tags:
        - Wallet
components:
  schemas:
    AuthorizeRequest:
      type: object
      required:
        - apiKey
        - apiSecret
      properties:
        apiKey:
          type: string
          description: |
            Secret API key identifier. Prefix encodes (mode, env): `sk_live_…` /
            `sk_sdbx_…` on prod; non-prod envs add an env infix
            (`sk_dev_sdbx_…`, `sk_stg_live_…`, …). The matching apiSecret is
            shown once at key creation and stored only as an HMAC hash.
          example: sk_live_abc123...
        apiSecret:
          type: string
          description: Opaque secret revealed once at key creation; not a typeid.
          example: opaque-bearer-secret...
    AuthorizeResponse:
      type: object
      required:
        - accessToken
        - tokenType
        - expiresIn
        - expiresAt
      properties:
        accessToken:
          type: string
          example: eyJhbGciOiJSUzI1NiIs...
        tokenType:
          type: string
          enum:
            - bearer
        expiresIn:
          type: integer
          example: 3600
        expiresAt:
          type: string
          format: date-time
    AssociateWalletRequest:
      type: object
      required:
        - idToken
      properties:
        idToken:
          type: string
          description: >-
            WaaS-issued idToken (ES256 JWT). Its subject is the wallet id and
            its audience must be the authenticated project.
          example: eyJhbGciOiJFUzI1NiIs...
    Wallet:
      type: object
      description: Embedded wallet linked to a customer.
      properties:
        id:
          type: string
          x-go-type-skip-optional-pointer: true
          example: wlt_01H9Xa8F5dN6mP3q
        object:
          type: string
          x-go-type-skip-optional-pointer: true
          example: wallet
        customer:
          type: string
          x-go-type-skip-optional-pointer: true
          nullable: true
          example: cst_01H9Xa8F5dN6mP3q
        custodyType:
          type: string
          x-go-type-skip-optional-pointer: true
          enum:
            - custodial
            - embedded
          example: embedded
        blockchainAddress:
          type: string
          x-go-type-skip-optional-pointer: true
          nullable: true
          example: '0x1234567890abcdef1234567890abcdef12345678'
        networkFamily:
          type: string
          x-go-type-skip-optional-pointer: true
          nullable: true
          example: evm
        status:
          type: string
          x-go-type-skip-optional-pointer: true
          nullable: true
          enum:
            - preallocated
            - active
            - suspended
          example: active
        createdAt:
          type: string
          format: date-time
          x-go-type-skip-optional-pointer: true
          nullable: true
        updatedAt:
          type: string
          format: date-time
          x-go-type-skip-optional-pointer: true
          nullable: true
    Customer:
      type: object
      description: >-
        Customer response object. PII fields (birthDate, residentialAddress,
        ipAddress, identifyingInformation) are write-only — accepted in
        POST/PATCH but never returned in responses.
      properties:
        id:
          type: string
          x-go-type-skip-optional-pointer: true
          example: cst_01H9Xa8F5dN6mP3q
        object:
          type: string
          x-go-type-skip-optional-pointer: true
          example: customer
        type:
          type: string
          x-go-type-skip-optional-pointer: true
          enum:
            - individual
          description: Customer type. Only individual is supported for MVP.
          example: individual
        firstName:
          type: string
          x-go-type-skip-optional-pointer: true
          nullable: true
          example: Jane
        middleName:
          type: string
          x-go-type-skip-optional-pointer: true
          nullable: true
          example: null
        lastName:
          type: string
          x-go-type-skip-optional-pointer: true
          nullable: true
          example: Smith
        email:
          type: string
          x-go-type-skip-optional-pointer: true
          nullable: true
          example: jane@example.com
        phone:
          type: string
          x-go-type-skip-optional-pointer: true
          nullable: true
          description: Primary phone in E.164 format.
          example: '+12125551234'
        nationality:
          type: string
          x-go-type-skip-optional-pointer: true
          nullable: true
          description: ISO 3166-1 alpha-2 country code.
          example: US
        externalId:
          type: string
          x-go-type-skip-optional-pointer: true
          nullable: true
          description: Developer's own user ID for cross-referencing.
          example: usr_12345
        status:
          type: string
          x-go-type-skip-optional-pointer: true
          enum:
            - active
            - inactive
          description: >-
            active or inactive. Inactive customers cannot create new
            transactions. No intermediate states — all granularity lives in
            endorsement statuses.
          example: active
        signedAgreement:
          type: boolean
          x-go-type-skip-optional-pointer: true
          description: Whether the customer has accepted OMS terms of service.
          example: true
        signedAgreementAt:
          type: string
          format: date-time
          nullable: true
          description: >-
            Timestamp when signedAgreement was set to true. Null if not yet
            signed.
          example: '2026-03-20T14:15:22Z'
        wallets:
          type: array
          description: >-
            Simplified flat view: one entry per wallet-asset combination. Use
            GET /wallets/{id} for the full representation.
          items:
            type: object
            properties:
              id:
                type: string
                example: wlt_01H9Xb3K7nM2pQ4r
              type:
                type: string
                example: custodial
              address:
                type: string
                example: '0x7B3a9F2c4D1eA8bF6390cE5d2B7fA104C8e3D9b1'
              network:
                type: string
                example: polygon
              asset:
                type: string
                example: usdc
              balance:
                type: string
                example: '1234.56'
              estimatedValueUsd:
                type: string
                example: '1234.56'
              createdAt:
                type: string
                format: date-time
        endorsements:
          type: array
          description: >-
            Endorsements track KYC/compliance status. Types: basic,
            cryptoCustody, usd. Statuses use SCREAMING_CASE: INACTIVE, PENDING,
            ISSUES, ACTIVE, REJECTED, REVOKED_ISSUES, OFFBOARDED.
          items:
            type: object
            properties:
              name:
                type: string
                enum:
                  - basic
                  - cryptoCustody
                  - usd
              status:
                type: string
                enum:
                  - INACTIVE
                  - PENDING
                  - ISSUES
                  - ACTIVE
                  - REJECTED
                  - REVOKED_ISSUES
                  - OFFBOARDED
              rejectionReasons:
                type: array
                items:
                  type: object
                  properties:
                    developerReason:
                      type: string
                    reason:
                      type: string
              requirements:
                type: object
                description: >-
                  Tracks what is complete, pending, missing, or has issues for
                  this endorsement.
                properties:
                  complete:
                    type: array
                    items:
                      type: string
                  pending:
                    type: array
                    items:
                      type: string
                  missing:
                    type: array
                    nullable: true
                    items:
                      type: string
                  issues:
                    type: array
                    items:
                      type: string
        metadata:
          type: object
          nullable: true
          additionalProperties:
            type: string
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
    CustomerRequest:
      type: object
      required:
        - type
      description: >-
        Create a new individual customer. Almost all fields are optional — only
        type is required. PII fields (birthDate, residentialAddress, ipAddress,
        identifyingInformation) are write-only and never returned in responses.
      properties:
        type:
          type: string
          enum:
            - individual
          description: Must be "individual". Only valid option for MVP.
          example: individual
        firstName:
          type: string
          description: Customer's legal first name.
          example: Jane
        middleName:
          type: string
          description: Customer's middle name.
        lastName:
          type: string
          description: Customer's legal last name.
          example: Smith
        email:
          type: string
          format: email
          example: jane@example.com
        phone:
          type: string
          description: Primary phone in E.164 format.
          example: '+12125551234'
        birthDate:
          type: string
          description: Date of birth in YYYY-MM-DD format. Write-only.
          example: '1990-05-15'
          writeOnly: true
        nationality:
          type: string
          description: ISO 3166-1 alpha-2 country code.
          example: US
        ipAddress:
          type: string
          description: >-
            End-user's IP address. Used for geo-based compliance checks on the
            basic endorsement. Write-only.
          writeOnly: true
        externalId:
          type: string
          description: Developer's own user ID for cross-referencing.
          example: usr_12345
        signedAgreement:
          type: boolean
          description: >-
            Whether the customer has accepted OMS terms of service. Default
            false.
          default: false
        residentialAddress:
          description: Customer's residential address. Write-only.
          writeOnly: true
          allOf:
            - $ref: '#/components/schemas/ResidentialAddress'
        identifyingInformation:
          type: array
          description: >-
            Array of ID documents. Write-only. Supported types: ssn, itin,
            driversLicense, passport.
          writeOnly: true
          items:
            $ref: '#/components/schemas/IdentificationDocument'
        endorsements:
          type: array
          description: >-
            Endorsements to request: basic, cryptoCustody, usd. If omitted, OMS
            defaults to cryptoCustody and usd (which auto-includes basic).
          items:
            type: string
            enum:
              - basic
              - cryptoCustody
              - usd
        metadata:
          type: object
          nullable: true
          additionalProperties:
            type: string
          maxProperties: 20
    CustomerUpdate:
      type: object
      description: >-
        Partial update — only send the fields you want to change. All optional
        fields from CustomerRequest can be updated (including ipAddress). PII
        fields are write-only.
      properties:
        firstName:
          type: string
        middleName:
          type: string
        lastName:
          type: string
        email:
          type: string
        phone:
          type: string
        birthDate:
          type: string
          writeOnly: true
        nationality:
          type: string
        ipAddress:
          type: string
          writeOnly: true
        externalId:
          type: string
        signedAgreement:
          type: boolean
          description: One-way operation — cannot be set back to false.
        residentialAddress:
          writeOnly: true
          allOf:
            - $ref: '#/components/schemas/ResidentialAddress'
        identifyingInformation:
          type: array
          writeOnly: true
          description: >-
            Appends to existing array. To replace an entry, submit the same type
            with updated fields.
          items:
            $ref: '#/components/schemas/IdentificationDocument'
        endorsements:
          type: array
          description: >-
            Request additional endorsements. New endorsements are added;
            existing ones are not removed. Including endorsement names triggers
            re-evaluation.
          items:
            type: string
            enum:
              - basic
              - cryptoCustody
              - usd
        metadata:
          type: object
          additionalProperties:
            type: string
    ResidentialAddress:
      type: object
      description: Customer's residential address.
      properties:
        line1:
          type: string
          example: 123 Main St
        line2:
          type: string
        city:
          type: string
          example: New York
        state:
          type: string
          example: NY
        country:
          type: string
          description: ISO 3166-1 alpha-2 country code.
          example: US
        zipCode:
          type: string
          example: '10001'
    IdentificationDocument:
      type: object
      required:
        - type
        - issuingCountry
        - number
      properties:
        type:
          type: string
          enum:
            - ssn
            - itin
            - driversLicense
            - passport
          example: ssn
        issuingCountry:
          type: string
          description: ISO 3166-1 alpha-2 country code.
          example: US
        number:
          type: string
          description: The identification number.
          example: '123456789'
    CustomersList:
      type: object
      required:
        - data
        - hasMore
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/Customer'
        hasMore:
          type: boolean
        cursor:
          type: string
          x-go-type-skip-optional-pointer: true
          description: >-
            Opaque pagination cursor — pass back as the `cursor` query param to
            fetch the next page. Absent on the last page.
    WebhookStatus:
      type: string
      enum:
        - enabled
        - disabled
        - suspended
      description: >-
        Webhook lifecycle state. `suspended` is set only by the service when the
        endpoint is unhealthy.
    DeliveryStatus:
      type: string
      enum:
        - queued
        - inProgress
        - delivered
        - failed
        - skipped
      description: >-
        Delivery lifecycle state. `skipped` is recorded but not dispatched
        (suspended/disabled webhook).
    WebhookMode:
      type: string
      enum:
        - live
        - sandbox
    Webhook:
      type: object
      description: >-
        A partner-configured webhook endpoint. The signing key is never
        serialized back; it is returned in cleartext only from
        create/rotate-key.
      properties:
        id:
          type: string
          x-go-type-skip-optional-pointer: true
          example: whk_01H9Xa8F5dN6mP3q
        object:
          type: string
          x-go-type-skip-optional-pointer: true
          example: webhook
        url:
          type: string
          x-go-type-skip-optional-pointer: true
          example: 'https://partner.example/webhooks'
        status:
          $ref: '#/components/schemas/WebhookStatus'
        statusReason:
          type: string
          x-go-type-skip-optional-pointer: true
          nullable: true
          description: Set on transition to suspended; describes the down/suspend cause.
        subscriptions:
          type: array
          x-go-type-skip-optional-pointer: true
          items:
            type: string
          example:
            - transaction.settled
            - '*'
        timeoutMs:
          type: integer
          x-go-type-skip-optional-pointer: true
          description: 'Per-webhook HTTP timeout. Default 5000, hard cap 10000.'
          example: 5000
        notifyThresholdSecs:
          type: integer
          x-go-type-skip-optional-pointer: true
          nullable: true
          description: Down-notification threshold (10 min – 1 day; default 1 h).
        successCount:
          type: integer
          x-go-type-skip-optional-pointer: true
          format: int64
        failureCount:
          type: integer
          x-go-type-skip-optional-pointer: true
          format: int64
        mode:
          $ref: '#/components/schemas/WebhookMode'
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
    WebhookRequest:
      type: object
      required:
        - url
        - subscriptions
      properties:
        url:
          type: string
          example: 'https://partner.example/webhooks'
        subscriptions:
          type: array
          items:
            type: string
          example:
            - transaction.settled
            - '*'
        timeoutMs:
          type: integer
          description: >-
            Per-webhook HTTP timeout in milliseconds. Default 5000, hard cap
            10000.
        notifyThresholdSecs:
          type: integer
          description: Down-notification threshold in seconds (600 – 86400; default 3600).
    WebhookUpdate:
      type: object
      description: Partial update. Only include fields you want to change.
      properties:
        url:
          type: string
        subscriptions:
          type: array
          items:
            type: string
        timeoutMs:
          type: integer
        notifyThresholdSecs:
          type: integer
    CreateWebhookResponse:
      type: object
      required:
        - webhook
        - signingKey
      properties:
        webhook:
          $ref: '#/components/schemas/Webhook'
        signingKey:
          type: string
          description: >-
            Cleartext HMAC signing key. Shown once — store it immediately; it is
            never returned again.
    RotateWebhookKeyResponse:
      type: object
      required:
        - signingKey
      properties:
        signingKey:
          type: string
          description: New cleartext HMAC signing key. Shown once.
    DeliverySummary:
      type: object
      properties:
        eventType:
          type: string
        status:
          $ref: '#/components/schemas/DeliveryStatus'
        createdAt:
          type: string
          format: date-time
    WebhookListItem:
      type: object
      properties:
        webhook:
          $ref: '#/components/schemas/Webhook'
        deliveryCount:
          type: integer
          format: int64
        successCount:
          type: integer
          format: int64
        failureCount:
          type: integer
          format: int64
        failureRate:
          type: integer
          description: >-
            Failure rate in basis points (0..10000); 250 = 2.50%. 0 when
            deliveryCount is 0.
        lastDelivery:
          $ref: '#/components/schemas/DeliverySummary'
    WebhooksList:
      type: object
      required:
        - data
        - hasMore
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/WebhookListItem'
        hasMore:
          type: boolean
        cursor:
          type: string
          x-go-type-skip-optional-pointer: true
          description: >-
            Opaque pagination cursor — pass back as the `cursor` query param to
            fetch the next page. Absent on the last page.
    WebhookDelivery:
      type: object
      description: >-
        One delivery of one event to one webhook. The id is the partner-facing
        envelope id and dedup key, stable across retries.
      properties:
        id:
          type: string
          x-go-type-skip-optional-pointer: true
          example: whd_01H9Xa8F5dN6mP3q
        object:
          type: string
          x-go-type-skip-optional-pointer: true
          example: webhookDelivery
        webhookId:
          type: string
          x-go-type-skip-optional-pointer: true
          example: whk_01H9Xa8F5dN6mP3q
        eventType:
          type: string
          x-go-type-skip-optional-pointer: true
          example: transaction.settled
        eventId:
          type: string
          x-go-type-skip-optional-pointer: true
          example: evt_01H9Xa8F5dN6mP3q
        resourceType:
          type: string
          x-go-type-skip-optional-pointer: true
          nullable: true
        resourceId:
          type: string
          x-go-type-skip-optional-pointer: true
          nullable: true
        sequence:
          type: integer
          x-go-type-skip-optional-pointer: true
          format: int64
          nullable: true
          description: >-
            Per-resource monotonic counter for consumer-side reordering/gap
            detection.
        status:
          $ref: '#/components/schemas/DeliveryStatus'
        statusReason:
          type: string
          x-go-type-skip-optional-pointer: true
          nullable: true
        sendAt:
          type: string
          format: date-time
        deliveredAt:
          type: string
          format: date-time
          nullable: true
        occurredAt:
          type: string
          format: date-time
          nullable: true
        failedAttempts:
          type: integer
          x-go-type-skip-optional-pointer: true
        payload:
          type: object
          x-go-type-skip-optional-pointer: true
          description: 'Domain payload of the event, before envelope wrap.'
        test:
          type: boolean
          x-go-type-skip-optional-pointer: true
          description: True for a synthesized test delivery.
        createdAt:
          type: string
          format: date-time
    DeliveryAttempt:
      type: object
      description: >-
        One HTTP attempt within a delivery. Sensitive header/body fields are
        redacted before storage.
      properties:
        attemptNumber:
          type: integer
          x-go-type-skip-optional-pointer: true
        statusCode:
          type: integer
          x-go-type-skip-optional-pointer: true
          nullable: true
        error:
          type: string
          x-go-type-skip-optional-pointer: true
          nullable: true
        durationMs:
          type: integer
          x-go-type-skip-optional-pointer: true
          nullable: true
        createdAt:
          type: string
          format: date-time
        targetUrl:
          type: string
          x-go-type-skip-optional-pointer: true
          nullable: true
          description: >-
            Target URL with userinfo stripped and credential-bearing query
            params redacted.
        requestMethod:
          type: string
          x-go-type-skip-optional-pointer: true
          nullable: true
        requestHeaders:
          type: object
          x-go-type-skip-optional-pointer: true
          nullable: true
          additionalProperties:
            type: string
          description: Stored as a JSON map; sensitive header names redacted.
        requestBody:
          type: string
          x-go-type-skip-optional-pointer: true
          nullable: true
          description: Immutable snapshot of the partner envelope we POST.
        requestBodyTruncated:
          type: boolean
          x-go-type-skip-optional-pointer: true
          nullable: true
        responseHeaders:
          type: object
          x-go-type-skip-optional-pointer: true
          nullable: true
          additionalProperties:
            type: string
        responseBody:
          type: string
          x-go-type-skip-optional-pointer: true
          nullable: true
          description: Up to 64 KiB stored; sensitive JSON field names redacted.
        responseBodyTruncated:
          type: boolean
          x-go-type-skip-optional-pointer: true
          nullable: true
    DeliveriesList:
      type: object
      required:
        - data
        - hasMore
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/WebhookDelivery'
        hasMore:
          type: boolean
        cursor:
          type: string
          x-go-type-skip-optional-pointer: true
          description: Opaque pagination cursor. Absent on the last page.
    GetDeliveryResponse:
      type: object
      required:
        - delivery
        - attempts
      properties:
        delivery:
          $ref: '#/components/schemas/WebhookDelivery'
        attempts:
          type: array
          items:
            $ref: '#/components/schemas/DeliveryAttempt'
    RetryDeliveriesRequest:
      type: object
      description: >-
        Provide explicit deliveryIds, or a status plus a createdAt range to
        retry all matching deliveries. At least one anchor is required.
      properties:
        deliveryIds:
          type: array
          items:
            type: string
        status:
          $ref: '#/components/schemas/DeliveryStatus'
        createdAfter:
          type: string
          format: date-time
        createdBefore:
          type: string
          format: date-time
    RetryDeliveriesResponse:
      type: object
      required:
        - retried
      properties:
        retried:
          type: integer
          description: Number of deliveries re-queued.
    ErrorResponse:
      type: object
      required:
        - error
        - code
        - msg
        - status
      description: >-
        Canonical OMSX error envelope, matching the webrpc shape every OMSX
        service emits. Names and numeric codes are stable identifiers defined in
        `schema/omsx/errors.ridl`.
      properties:
        error:
          type: string
          description: Stable error name from schema/omsx/errors.ridl
          example: Unauthorized
        code:
          type: integer
          description: Stable numeric code from schema/omsx/errors.ridl
          example: 1000
        msg:
          type: string
          description: Human-readable message (kept stable across releases)
          example: unauthorized access
        cause:
          type: string
          description: >-
            Optional internal cause for operator triage; filtered before
            reaching end customers
          example: signature
        status:
          type: integer
          description: HTTP status mirrored in the body for client convenience
          example: 401
    AccountHolder:
      type: string
      enum:
        - customer
      description: >-
        Who holds the payout bank account (OMS closed enum). `customer` is the
        only

        valid value.
    AccountTransaction:
      type: object
      properties:
        id:
          allOf:
            - $ref: '#/components/schemas/typeId'
          description: Unique identifier.
        object:
          type: string
          enum:
            - accountTransaction
          description: Resource type discriminator. Always "accountTransaction".
        accountId:
          allOf:
            - $ref: '#/components/schemas/typeId'
          description: Wallet/account ID.
        type:
          $ref: '#/components/schemas/TransactionType'
        status:
          type: string
          description: Current lifecycle status.
        amount:
          type: string
          description: Amount as a decimal string.
        currency:
          type: string
          description: ISO 4217 currency code.
        creditCurrencyAmount:
          type: string
          description: 'Amount credited, in `creditCurrencyCode`.'
        creditCurrencyCode:
          type: string
          description: Currency credited.
        debitCurrencyAmount:
          type: string
          description: 'Amount debited, in `debitCurrencyCode`.'
        debitCurrencyCode:
          type: string
          description: Currency debited.
        exchangeRate:
          type: string
          description: Units of destination asset per 1 unit of source asset.
        totalFees:
          type: string
          description: Total fees for this entry.
        feeCurrencyCode:
          type: string
          description: Currency the fees are denominated in.
        orderType:
          type: string
          description: Order type of the underlying trade.
        providerTransactionRef:
          type: string
          description: Upstream provider's transaction reference.
        blockchainTransactionId:
          type: string
          description: On-chain transaction identifier.
        fromWalletAddress:
          type: string
          description: Sending wallet address.
        toWalletAddress:
          type: string
          description: Receiving wallet address.
        balanceAfter:
          type: string
          description: >-
            Account balance recorded when this entry was written. A
            point-in-time

            value, not a guaranteed running total: consecutive entries need not
            differ

            by their amounts, and entries are immutable so the value is never
            revised.

            For fiat-wallet entries it is read from the balance mirrored from
            the

            upstream provider — which is authoritative and already reflects the

            movement by the time it reports it — and is adjusted by this entry's
            amount

            only where the ordering guarantees the mirror predates the movement.
            Use

            the wallet balance endpoint for the current balance.
        sourceType:
          type: string
          description: Type of the originating resource.
        sourceId:
          type: string
          description: >-
            Polymorphic source correlation key. Transaction sources are rendered
            as txn_ TypeIDs; non-resource reconciliation/request keys remain
            raw.
        description:
          type: string
          description: Human-readable description.
        createdAt:
          type: string
          format: date-time
          description: When the resource was created.
      description: >-
        A single ledger entry on an account: a credit, debit, hold, or release,
        along with the resulting balance.
    AccountTransactionList:
      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/AccountTransaction'
          description: The page of results.
      description: A paginated list of account ledger entries.
    Address:
      type: object
      properties:
        line1:
          type: string
          description: 'Street address, line 1.'
        line2:
          type: string
          description: 'Street address, line 2.'
        city:
          type: string
          description: City.
        state:
          type: string
          description: State / province / region.
        country:
          type: string
          description: ISO 3166-1 alpha-2
        zipCode:
          type: string
          description: ZIP / postal code.
      description: A postal address. country is an ISO 3166-1 alpha-2 country code.
    AmountObject:
      type: object
      required:
        - value
        - currency
        - display
      properties:
        value:
          allOf:
            - $ref: '#/components/schemas/int64String'
          description: Amount in fiat minor units (e.g. cents).
        currency:
          type: string
          description: ISO 4217 currency code.
        display:
          type: string
          description: Human-readable rendering (e.g. "12.34 USD").
      description: >-
        Single-amount snapshot - value in minor units, plus the currency code
        and

        a human-readable display string. Used wherever the API exposes a
        one-shot

        amount (e.g. virtualAccount.finalBalance), as distinct from balance
        shapes

        with available/pending/reserved components.
    AssetNetworkPair:
      type: object
      required:
        - asset
        - network
      properties:
        asset:
          type: string
        network:
          type: string
      description: 'One (asset, network) tuple — e.g. `{ asset: "usd", network: "ach" }`.'
    BankAccountType:
      type: string
      enum:
        - checking
        - savings
      description: Bank account sub-type for US accounts.
    BankCanadaDestination:
      type: object
      required:
        - type
        - category
        - details
      properties:
        party:
          $ref: '#/components/schemas/Party'
        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.
        details:
          $ref: '#/components/schemas/BankCanadaDetails'
        payoutOrigin:
          $ref: '#/components/schemas/PayoutOrigin'
      title: Canadian bank account
    BankCanadaDetails:
      type: object
      properties:
        id:
          allOf:
            - $ref: '#/components/schemas/typeId'
          description: Unique identifier.
        asset:
          type: string
          enum:
            - usd
            - cad
          description: Canonical asset identifier.
        network:
          type: string
          enum:
            - swift
            - local
          description: Network identifier.
        institutionNumber:
          type: string
          description: Canadian 3-digit institution number.
        transitNumber:
          type: string
          description: Canadian 5-digit transit number.
        accountNumberLast4:
          type: string
          description: Last four digits of the account number.
        bankName:
          type: string
          description: Bank display name.
        memo:
          type: string
          description: Payment memo.
      description: Canadian bank account instrument details.
    BankCanadaInstrument:
      type: object
      required:
        - type
        - category
        - details
      properties:
        party:
          $ref: '#/components/schemas/Party'
        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.
        details:
          $ref: '#/components/schemas/BankCanadaDetails'
      description: Canadian bank account instrument.
      title: Canadian bank account
    BankCanadaSideDetails:
      type: object
      required:
        - id
        - asset
        - network
        - accountHolder
      properties:
        id:
          type: string
          description: Canadian bank ExternalAccount ID (ext_bankCa_ prefix).
        asset:
          type: string
          enum:
            - usd
            - cad
          description: Canonical asset identifier.
        network:
          type: string
          enum:
            - swift
            - local
          description: USD uses `swift`; CAD uses `local`. Always explicit.
        accountHolder:
          $ref: '#/components/schemas/AccountHolder'
    BankCanadaSideRequest:
      type: object
      required:
        - type
        - details
      properties:
        type:
          type: string
          enum:
            - bankCanada
          description: Type discriminator.
        details:
          $ref: '#/components/schemas/BankCanadaSideDetails'
        amount:
          $ref: '#/components/schemas/decimalString'
      description: >-
        Deliver to a Canadian bank account. USD routes over SWIFT; CAD over
        local rails.
      title: Canadian bank account
    BankIbanDestination:
      type: object
      required:
        - type
        - category
        - details
      properties:
        party:
          $ref: '#/components/schemas/Party'
        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.
        details:
          $ref: '#/components/schemas/BankIbanDetails'
        payoutOrigin:
          $ref: '#/components/schemas/PayoutOrigin'
      title: IBAN bank account
    BankIbanDetails:
      type: object
      properties:
        id:
          allOf:
            - $ref: '#/components/schemas/typeId'
          description: Unique identifier.
        asset:
          type: string
          description: Canonical asset identifier.
        network:
          type: string
          enum:
            - swift
          description: Network identifier.
        ibanLast4:
          type: string
          description: Last four characters of the IBAN.
        BIC:
          type: string
          description: SWIFT BIC.
        bankAddress:
          $ref: '#/components/schemas/Address'
        countryCode:
          type: string
          description: ISO 3166-1 alpha-2 country code.
        memo:
          type: string
          description: Payment memo.
      description: IBAN bank account instrument details.
    BankIbanInstrument:
      type: object
      required:
        - type
        - category
        - details
      properties:
        party:
          $ref: '#/components/schemas/Party'
        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.
        details:
          $ref: '#/components/schemas/BankIbanDetails'
      description: IBAN bank account instrument.
      title: IBAN bank account
    BankIbanSideDetails:
      type: object
      required:
        - id
        - asset
        - accountHolder
      properties:
        id:
          type: string
          description: IBAN ExternalAccount ID (ext_bankIban_ prefix).
        asset:
          type: string
          enum:
            - usd
          description: Canonical asset identifier.
        network:
          type: string
          enum:
            - swift
          description: Network identifier.
          default: swift
        accountHolder:
          $ref: '#/components/schemas/AccountHolder'
    BankIbanSideRequest:
      type: object
      required:
        - type
        - details
      properties:
        type:
          type: string
          enum:
            - bankIban
          description: Type discriminator.
        details:
          $ref: '#/components/schemas/BankIbanSideDetails'
        amount:
          $ref: '#/components/schemas/decimalString'
      description: Deliver to an IBAN account over SWIFT (USD).
      title: IBAN bank account
    BankRoutingBlock:
      type: object
      required:
        - bankName
        - bankAddress
        - accountNumber
        - routingNumber
        - accountType
        - BIC
        - beneficiary
        - memo
      properties:
        supportedSources:
          type: array
          items:
            $ref: '#/components/schemas/AssetNetworkPair'
          description: Asset/network pairs this routing block accepts deposits for.
        bankName:
          type: string
        bankAddress:
          type: string
        accountNumber:
          type: string
        routingNumber:
          type: string
          nullable: true
          description: US domestic only; null for SWIFT.
        accountType:
          type: string
          nullable: true
          description: US domestic only; null for SWIFT. Always "checking" when present.
        BIC:
          type: string
          nullable: true
          description: SWIFT only; null for US domestic.
        beneficiary:
          $ref: '#/components/schemas/BankRoutingBlockBeneficiary'
        memo:
          type: string
          nullable: true
          description: |-
            SWIFT only; null for US domestic. OMS-generated:
            "FFC <customerName> <ereborDdaAccountNumber>".
      description: >-
        One bank-routing entry within VirtualAccountInstructions.bankUs.
        US-domestic

        fields (routingNumber, accountType) are null on a SWIFT entry;
        SWIFT-only

        fields (BIC, memo) are null on a domestic entry.
    BankRoutingBlockBeneficiary:
      type: object
      required:
        - name
        - address
      properties:
        name:
          type: string
        address:
          type: string
      description: |-
        Beneficiary on a bank routing block - the entity to which the funds
        are ultimately credited. For SWIFT this is Erebor (the bank);
        for domestic rails this is the customer. Response-only,
        system-synthesised (Erebor entity or customer counterparty). The address
        is a single formatted display line (spec §BankRoutingBlock), e.g.
        "6 Acme Way, Bentonville, AR 72712 US".
    BankUsDestination:
      type: object
      required:
        - type
        - category
        - details
      properties:
        party:
          $ref: '#/components/schemas/Party'
        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.
        details:
          $ref: '#/components/schemas/BankUsDetails'
        payoutOrigin:
          $ref: '#/components/schemas/PayoutOrigin'
      title: US bank account
    BankUsDetails:
      type: object
      properties:
        id:
          allOf:
            - $ref: '#/components/schemas/typeId'
          description: Unique identifier.
        asset:
          type: string
          enum:
            - usd
          description: Canonical asset identifier.
        network:
          type: string
          enum:
            - ach
            - achSameDay
            - wire
            - rtp
          description: Network identifier.
        secCode:
          allOf:
            - $ref: '#/components/schemas/SecCode'
          description: ACH SEC code (populated only on ach/achSameDay).
        accountNumberLast4:
          type: string
          description: Last four digits of the account number.
        routingNumber:
          type: string
          description: US ABA routing number.
        bankName:
          type: string
          description: Bank display name.
        accountType:
          type: string
          enum:
            - checking
            - savings
          description: checking or savings.
        memo:
          type: string
          description: Payment memo.
      description: US bank account instrument details.
    BankUsInstrument:
      type: object
      required:
        - type
        - category
        - details
      properties:
        party:
          $ref: '#/components/schemas/Party'
        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.
        details:
          $ref: '#/components/schemas/BankUsDetails'
      description: US bank account instrument.
      title: US bank account
    BankUsSideDetails:
      type: object
      required:
        - id
        - asset
        - network
        - accountHolder
      properties:
        id:
          type: string
          description: US bank ExternalAccount ID (ext_bankUs_ prefix).
        asset:
          type: string
          enum:
            - usd
          description: Canonical asset identifier.
        network:
          type: string
          enum:
            - ach
            - achSameDay
            - wire
          description: Network identifier.
        accountHolder:
          $ref: '#/components/schemas/AccountHolder'
        memo:
          type: string
          allOf:
            - $ref: '#/components/schemas/paymentMemo'
          nullable: true
          description: >-
            Optional customer-supplied payment memo delivered to the
            beneficiary's bank.


            HONORED TODAY ON: a Deposit Address `bankUs` destination with

            `network: "wire"` (create and update). The stored value replaces —
            it does

            not append to — the memo OMS would otherwise generate for every
            outbound

            Fedwire payout from that deposit address. Send `null` (or omit it on
            an

            update that replaces `destination`) to restore the generated memo.
            Because

            the memo is read when each payout wire is built, an edit affects
            only future

            payouts, never one already in flight.


            REJECTED EVERYWHERE ELSE, with `422 memoNotSupported`: this model is
            shared

            by the Quote and Virtual Account request surfaces (create and
            update), and by

            a deposit-address `bankUs` destination on the `ach` / `achSameDay`
            rails. A

            non-empty memo on any of those is refused rather than accepted and
            dropped —

            a silently ignored field on a money path gives the caller a success
            response

            while the payout carries the generated memo. Sending `null`,
            omitting the

            field, or sending only whitespace is always accepted (it means "no
            override").

            Each rejected surface becomes accepting as its slice ships
            (omsx#2254);

            relaxing a 422 into an accepted value never breaks a caller, so no
            client

            needs to change when that happens.


            The error body's `details.reason` tells apart a temporary gap from a

            permanent one: `"notImplemented"` means this surface/rail will
            accept the

            field once its omsx#2254 slice ships (every current rejection above
            is this

            case); `"unsupportedRail"` would mean the field is not a concept on
            this

            rail and never will be (e.g. the shared model also carries fields
            that are

            rail-specific by design, like ACH's `companyDiscretionaryData` on a
            wire

            destination) — retry the first after a release, never the second.
    BankUsSideRequest:
      type: object
      required:
        - type
        - details
      properties:
        type:
          type: string
          enum:
            - bankUs
          description: Type discriminator.
        details:
          $ref: '#/components/schemas/BankUsSideDetails'
        amount:
          $ref: '#/components/schemas/decimalString'
      description: Deliver to a US bank account.
      title: US bank account
    BillingAddressSource:
      type: string
      enum:
        - provided
        - customerDefault
      description: |-
        Where a card's billing address came from. `provided` = supplied on the
        request; `customerDefault` = filled from the owning customer's address
        because the request omitted it.
    BlockchainAsset:
      type: object
      required:
        - protocol
        - chainId
        - tokenId
      properties:
        protocol:
          $ref: '#/components/schemas/BlockchainProtocol'
        chainId:
          type: string
        tokenId:
          type: string
    BlockchainProtocol:
      type: string
      enum:
        - evm
        - svm
        - sui
    CardBrand:
      type: string
      enum:
        - visa
        - mastercard
        - amex
        - discover
      description: >-
        Card network/brand. Derived server-side from the PAN; never accepted on
        a

        request.
    CardDestination:
      type: object
      required:
        - type
        - category
        - details
      properties:
        party:
          $ref: '#/components/schemas/Party'
        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.
        details:
          $ref: '#/components/schemas/CardDetails'
        payoutOrigin:
          $ref: '#/components/schemas/PayoutOrigin'
      title: Card
    CardDetails:
      type: object
      properties:
        id:
          type: string
          description: Unique identifier.
        asset:
          type: string
          enum:
            - usd
          description: Canonical asset identifier.
        network:
          type: string
          enum:
            - card
          description: Network identifier.
        cardNumberLast4:
          type: string
          description: Last four digits of the card number.
        cardProvider:
          type: string
          description: Card network/provider.
        memo:
          type: string
          description: Payment memo.
      description: Card instrument details.
    CardInstrument:
      type: object
      required:
        - type
        - category
        - details
      properties:
        party:
          $ref: '#/components/schemas/Party'
        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.
        details:
          $ref: '#/components/schemas/CardDetails'
      description: Card instrument.
      title: Card
    CardSideDetails:
      type: object
      required:
        - id
        - asset
      properties:
        id:
          type: string
          description: Card ExternalAccount ID (ext_card_ prefix).
        asset:
          type: string
          enum:
            - usd
          description: Canonical asset identifier.
    CardSideRequest:
      type: object
      required:
        - type
        - details
      properties:
        type:
          type: string
          enum:
            - card
          description: Type discriminator.
        details:
          $ref: '#/components/schemas/CardSideDetails'
        amount:
          $ref: '#/components/schemas/decimalString'
      description: |-
        A registered debit card. Valid as a source (pull-from-card funding) or a
        destination (push-to-card payout). `network` is inferred server-side and
        returned on the response only.
      title: Card
    CardType:
      type: string
      enum:
        - debit
        - credit
        - prepaid
      description: |-
        Card funding type, derived server-side from the PAN. Only `debit` is
        supported today; `credit` and `prepaid` are reserved for future
        push-to-card / pull-from-card support.
    CashDestination:
      type: object
      required:
        - type
        - category
        - details
      properties:
        party:
          $ref: '#/components/schemas/Party'
        type:
          type: string
          enum:
            - cash
          description: Type discriminator.
        category:
          type: string
          enum:
            - cash
          description: 'High-level grouping: always `cash` for cash pickups and drops.'
        details:
          $ref: '#/components/schemas/CashDetails'
        payoutOrigin:
          $ref: '#/components/schemas/PayoutOrigin'
      title: Cash
    CashDetails:
      type: object
      properties:
        asset:
          type: string
          description: Canonical asset identifier.
        cashLocationId:
          type: string
          description: Cash location ID from `GET /cash-locations`.
        cashLocationReference:
          type: string
          description: 'Provider reference for the location, from `GET /cash-locations`.'
        pickupCode:
          type: string
          description: >-
            Retail pickup code for a cash payout. Populated only on the cash-out
            (pickup) side.
        expiresAt:
          type: string
          format: date-time
          description: Pickup-code expiry. Populated only on the cash-out (pickup) side.
        locationName:
          type: string
          description: >-
            Display name of the retail pickup location. Populated only on the
            cash-out (pickup) side.
        locationAddress:
          type: string
          description: >-
            Street address of the retail pickup location. Populated only on the
            cash-out (pickup) side.
      description: Cash pickup/drop instrument details.
    CashFlow:
      type: string
      enum:
        - cash_in
        - cash_out
      description: >-
        Direction of a cash flow. cash_in moves cash to crypto; cash_out moves
        crypto to cash.
    CashIn:
      type: object
      required:
        - id
        - type
        - status
        - customerId
        - source
        - destination
        - cash
        - location
        - createdAt
        - updatedAt
      properties:
        id:
          allOf:
            - $ref: '#/components/schemas/typeId'
          description: Cash-in ID (`ci_` prefix).
        object:
          type: string
          enum:
            - cashIn
          description: Resource type discriminator. Always "cashIn".
        type:
          allOf:
            - $ref: '#/components/schemas/TransferType'
          description: Cash-in flavor.
        status:
          allOf:
            - $ref: '#/components/schemas/CashInStatus'
          description: Current lifecycle status of the cash-in.
        subStatus:
          allOf:
            - $ref: '#/components/schemas/CashInSubStatus'
          description: Granular sub-status adding detail behind `status`.
        customerId:
          allOf:
            - $ref: '#/components/schemas/typeId'
          description: The OMS customer that owns this record (`cst_` prefix).
        fixedAmountSide:
          type: string
          enum:
            - source
            - destination
          description: >-
            The side the amount was fixed on when creating the cash-in. OMS
            calculated the other side.
        source:
          allOf:
            - $ref: '#/components/schemas/CashInSource'
          description: 'Where the customer deposits cash: the provider and location.'
        destination:
          allOf:
            - $ref: '#/components/schemas/CashInDestination'
          description: Crypto instrument the converted funds are delivered to.
        cash:
          allOf:
            - $ref: '#/components/schemas/CashInfo'
          description: The cash amount to be deposited.
        location:
          allOf:
            - $ref: '#/components/schemas/CashInLocation'
          description: Resolved detail of the chosen cash location.
        depositInstructions:
          allOf:
            - $ref: '#/components/schemas/CashInDepositInstructions'
          description: >-
            The deposit code and instructions the customer presents at the
            retail location.
        rates:
          allOf:
            - $ref: '#/components/schemas/Rates'
          description: Exchange and effective rates applied to this cash-in.
        sponsorGasCost:
          type: string
          description: |-
            USD cost of gas absorbed by the developer when sponsoring gas.
            Always "0" in alpha - gas is sponsored. Spec § 4.1.
        omsFeeSchedule:
          allOf:
            - $ref: '#/components/schemas/OmsFeeSchedule'
          description: OMS fee schedule applied to this cash-in.
        transactionId:
          allOf:
            - $ref: '#/components/schemas/typeId'
          description: >-
            The Transaction produced once the cash-in completes. Null while
            pending.
        sponsorGas:
          type: boolean
          description: >-
            When `true`, OMS absorbs the on-chain gas cost for the destination
            delivery. Only `true` is currently supported.
        metadata:
          type: object
          additionalProperties:
            type: string
          description: Free-form key-value pairs supplied at creation or update.
        developerFees:
          type: array
          items:
            $ref: '#/components/schemas/FeeEntry'
          description: >-
            Developer fee entries echoed back from the request.

            Omitted in alpha - request side is stripped per spec § 2. The field

            stays on the schema so it can be reintroduced without a breaking
            change

            when developer fees ship.
        createdAt:
          type: string
          format: date-time
          description: When the cash-in was created.
        updatedAt:
          type: string
          format: date-time
          description: When the cash-in was last updated.
        completedAt:
          type: string
          format: date-time
          description: When the cash-in reached a terminal state. Null while in progress.
        expiresAt:
          type: string
          format: date-time
          description: >-
            When the issued deposit code expires. Single source of truth for
            cash-in

            expiry (#2144); the per-instruction expiresAt was removed in favor
            of this.
      description: >-
        A code-based cash deposit. The customer takes the issued code to a
        retail location and deposits cash, which OMS converts to crypto and
        delivers to the destination. Amounts start as estimates and are
        finalized once the cash is deposited.
      example:
        id: ci_44vxe2xk8gfsjehfcw3npt5bg8
        object: cashIn
        type: fiatToCrypto
        status: pending
        subStatus: order_reserved
        customerId: cst_vfa0nxw6zvyws9g237jrxn4y7k
        source:
          asset: usd
          indicatedAmount: '200.00'
          amountGross: '200.00'
          amountNet: '200.00'
          feesDeducted:
            total: '0.00'
            developer: '0.00'
            oms: '0.00'
            gas: '0.00'
        destination:
          asset: usdc
          network: polygon
          amountGross: '200.00'
          amountNet: '200.00'
          feesDeducted:
            total: '0.00'
            developer: '0.00'
            oms: '0.00'
            gas: '0.00'
          wallet:
            id: wlt_5h4jzzpr9xre3bamd9ca7qyghn
            blockchainAddress: '0x7B3A9F2C4D1eA8bf6390cE5D2b7fA104c8e3D9B1'
        cash:
          locationId: loc_01H9Xd
          locationReference: R1JFRU5ET1QtMjQzNA==
        location:
          name: 'CVS Pharmacy #4521'
          address: '123 Main St, San Francisco, CA 94105'
        rates:
          pair: usd/usdc
          exchangeRate: '1.0000'
          effectiveRate: '1.0000'
        depositInstructions:
          cashInCode: 483 291
          locationName: 'CVS Pharmacy #4521'
          locationAddress: '123 Main St, San Francisco, CA 94105'
        fixedAmountSide: source
        sponsorGas: true
        sponsorGasCost: '0'
        expiresAt: '2026-05-15T18:32:48Z'
        createdAt: '2026-05-15T17:32:48Z'
        updatedAt: '2026-05-15T17:32:48Z'
    CashInDepositInstructions:
      type: object
      required:
        - cashInCode
      properties:
        cashInCode:
          type: string
          description: Machine-readable code the customer presents at the register.
        locationName:
          type: string
          description: Display name of the retail location.
        locationAddress:
          type: string
          description: Street address of the retail location.
      description: >-
        The deposit code and retail location a customer uses to complete a
        cash-in.
    CashInDestination:
      type: object
      properties:
        wallet:
          $ref: '#/components/schemas/CashInDestinationWallet'
        asset:
          type: string
          description: Canonical asset identifier.
        network:
          type: string
          description: Network identifier.
        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:
          $ref: '#/components/schemas/FeesDeducted'
      description: The crypto destination a cash-in is converted to and delivered to.
    CashInDestinationWallet:
      type: object
      properties:
        id:
          allOf:
            - $ref: '#/components/schemas/typeId'
          description: Unique identifier.
        externalAccount:
          type: string
          description: 'Registered External Account receiving the funds, when applicable.'
        blockchainAddress:
          type: string
          description: >-
            On-chain address. For an EVM network the address must be
            all-lowercase,

            all-uppercase, or a valid EIP-55 checksummed form; an inconsistent
            mixed-case

            address is rejected as a likely casing typo, and the zero address is
            rejected.

            Solana/SUI are validated per their own network rules.
      description: The wallet receiving the converted funds.
    CashInLocation:
      type: object
      properties:
        name:
          type: string
          description: Display name.
        address:
          type: string
          description: Postal address.
      description: Resolved retail location detail.
    CashInSource:
      type: object
      required:
        - asset
      properties:
        asset:
          type: string
          description: Canonical asset identifier.
        network:
          type: string
          description: Network identifier.
        email:
          type: string
          description: Email address.
        indicatedAmount:
          type: string
          description: The cash amount the customer indicated they will deposit.
        amount:
          type: string
          description: Amount as a decimal string.
        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:
          $ref: '#/components/schemas/FeesDeducted'
      description: 'Cash side of a cash-in: the fiat asset and amounts.'
    CashInStatus:
      type: string
      enum:
        - pending
        - processing
        - completed
        - failed
        - expired
      description: >-
        Lifecycle of a cash-in. pending: code issued, awaiting deposit.
        processing: cash deposited, conversion underway. completed: converted
        and delivered. failed: the deposit or conversion did not succeed.
        expired: the code expired before any deposit.
    CashInSubStatus:
      type: string
      enum:
        - order_reserved
        - settled
        - cash_deposit_expired
        - cash_deposit_failed
        - provider_order_failed
        - provider_order_template_error
      description: >-
        Granular sub-status for a cash-in. Adds detail behind the coarse status
        field.
    CashInfo:
      type: object
      required:
        - locationId
        - locationReference
      properties:
        locationId:
          type: string
          description: Cash location ID from `GET /cash-locations`.
        locationReference:
          type: string
          description: 'Provider reference for the location, from `GET /cash-locations`.'
      description: >-
        The retail location chosen for the deposit, by ID and provider
        reference.
    CashInstrument:
      type: object
      required:
        - type
        - category
        - details
      properties:
        party:
          $ref: '#/components/schemas/Party'
        type:
          type: string
          enum:
            - cash
          description: Type discriminator.
        category:
          type: string
          enum:
            - cash
          description: 'High-level grouping: always `cash` for cash pickups and drops.'
        details:
          $ref: '#/components/schemas/CashDetails'
      description: Cash instrument.
      title: Cash
    CashLocation:
      type: object
      required:
        - id
        - object
        - cashLocationReference
        - name
        - provider
        - address
        - city
        - state
        - zipCode
        - country
        - coordinates
        - buyAllowed
        - sellAllowed
      properties:
        id:
          type: string
          description: >-
            Resource id: `loc_` + the raw provider location id (e.g.
            `loc_CVS10804`).

            This is a deliberate carveout from the TypeID policy — a cash
            location is a

            provider-catalog entry with no BPN DB row, so the id is a prefixed

            provider-internal identifier, not a generated TypeID, and `loc_` is
            not a

            `database/id.go` prefix. The value is unchanged from v0.10 (only
            renamed

            from `locId`).
        object:
          type: string
          enum:
            - cashLocation
          description: Resource type discriminator. Always "cashLocation".
        cashLocationReference:
          type: string
          description: 'Provider reference for the location, from `GET /cash-locations`.'
        name:
          type: string
          description: Display name.
        provider:
          type: string
          description: Cash provider.
        address:
          type: string
          description: Postal address.
        city:
          type: string
          description: City.
        state:
          type: string
          description: State / province / region.
        zipCode:
          type: string
          description: ZIP / postal code.
        country:
          type: string
          description: ISO 3166-1 alpha-2 country code.
        coordinates:
          $ref: '#/components/schemas/CashLocationCoordinates'
        distance:
          type: number
          format: double
          description: Distance from the search coordinates.
        distanceUnit:
          type: string
          description: 'Unit for `distance` (e.g. mi, km).'
        buyAllowed:
          type: boolean
          description: Whether cash-in (buy) is supported at this location.
        sellAllowed:
          type: boolean
          description: Whether cash-out (sell) is supported at this location.
        hours:
          type: string
          description: Opening hours.
        supportedAssets:
          type: array
          items:
            type: string
          description: Assets supported at this location.
      description: >-
        A retail location where a customer can deposit or pick up cash, with its
        capabilities and distance from the search coordinates.
    CashLocationCoordinates:
      type: object
      required:
        - latitude
        - longitude
      properties:
        latitude:
          type: number
          format: double
          description: Latitude in decimal degrees.
        longitude:
          type: number
          format: double
          description: Longitude in decimal degrees.
      description: Latitude/longitude pair.
    CashLocationsResponse:
      type: object
      required:
        - providers
      properties:
        providers:
          type: array
          items:
            $ref: '#/components/schemas/CashProvider'
          description: Providers with locations in range.
      description: Cash locations grouped by provider.
    CashProvider:
      type: object
      required:
        - provider
        - maxTransaction
        - maxDailyPerCustomer
        - locations
      properties:
        provider:
          type: string
          description: Cash provider.
        maxTransaction:
          type: string
          description: Maximum single-transaction amount.
        maxDailyPerCustomer:
          type: string
          description: Maximum daily total per customer.
        locations:
          type: array
          items:
            $ref: '#/components/schemas/CashLocation'
          description: 'Locations for this provider, nearest first.'
      description: >-
        A cash provider and its nearby locations, with per-transaction and
        per-customer daily limits.
    CashSideDetails:
      type: object
      required:
        - asset
        - cashLocationId
        - cashLocationReference
        - amount
      properties:
        asset:
          type: string
          enum:
            - usd
          description: Canonical asset identifier.
        cashLocationId:
          type: string
          description: Cash location ID from `GET /cash-locations`.
        cashLocationReference:
          type: string
          description: 'Provider reference for the location, from `GET /cash-locations`.'
        amount:
          allOf:
            - $ref: '#/components/schemas/decimalString'
          description: 'Multiple of 20.00, at most 400.00.'
    CashSideRequest:
      type: object
      required:
        - type
        - details
      properties:
        type:
          type: string
          enum:
            - cash
          description: Type discriminator.
        details:
          $ref: '#/components/schemas/CashSideDetails'
      description: >-
        Deliver as a cash pickup at a retail payout location. Amount is required
        in

        `details` and must be a multiple of 20.00, up to a maximum of 400.00 per

        transaction.
      title: Cash
    Counterparty:
      type: object
      required:
        - address
      properties:
        id:
          $ref: '#/components/schemas/typeId'
        object:
          type: string
          enum:
            - counterparty
        customerId:
          $ref: '#/components/schemas/typeId'
        status:
          $ref: '#/components/schemas/CounterpartyStatus'
        rejectionReason:
          type: string
          description: Set when status = `rejected`.
        name:
          type: string
          description: Full legal name or registered business name.
        entityType:
          $ref: '#/components/schemas/CounterpartyEntityType'
        address:
          allOf:
            - $ref: '#/components/schemas/Address'
          description: >-
            Registered address. Required since v0.11 — always present in
            responses.
        email:
          type: string
        phone:
          type: string
        taxId:
          type: string
        dateOfBirth:
          type: string
          format: date
        nationality:
          type: string
          description: ISO 3166-1 alpha-2.
        metadata:
          type: object
          additionalProperties:
            type: string
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
      description: |-
        A third party a customer transacts with — an entry in the customer's
        address book. Counterparties will own External Accounts (registered
        payment destinations) in a later slice.
    CounterpartyCreateRequest:
      type: object
      required:
        - customerId
        - name
        - address
      properties:
        customerId:
          type: string
          description: Owning customer (cst_… TypeID or legacy public id).
        name:
          type: string
          minLength: 1
          maxLength: 140
          description: Full legal name or registered business name. 1..140 chars.
        entityType:
          allOf:
            - $ref: '#/components/schemas/CounterpartyEntityType'
          description: '`individual` or `business`.'
        address:
          allOf:
            - $ref: '#/components/schemas/Address'
          description: |-
            Registered address. Required: must include non-blank line1, city,
            zipCode and a two-letter ISO country (state required for US).
        email:
          type: string
          description: Contact email address.
        phone:
          type: string
          description: Phone in E.164 format.
        taxId:
          type: string
          description: >-
            Tax ID (CPF, CNPJ, SSN, etc.). Required for some external-account
            types.
        dateOfBirth:
          type: string
          format: date
          description: Date of birth (YYYY-MM-DD).
        nationality:
          type: string
          description: ISO 3166-1 alpha-2.
        metadata:
          type: object
          additionalProperties:
            type: string
          description: >-
            Free-form key-value pairs stored on the resource and echoed back on
            reads.
      example:
        customerId: cst_vfa0nxw6zvyws9g237jrxn4y7k
        name: Alice Smith
        entityType: individual
        address:
          line1: 500 Market Street
          city: San Francisco
          state: CA
          country: US
          zipCode: '94105'
        email: alice@example.com
        phone: '+14155550100'
        nationality: US
    CounterpartyEntityType:
      type: string
      enum:
        - individual
        - business
    CounterpartyHasActiveExternalAccountsErrorBody:
      type: object
      required:
        - error
        - code
      properties:
        error:
          type: string
          enum:
            - counterparty still owns active or pending external accounts
          description: Human-readable error identifier.
        code:
          type: string
          enum:
            - counterpartyHasActiveExternalAccounts
          description: Machine-readable code.
        details:
          type: object
          properties:
            counterpartyId:
              allOf:
                - $ref: '#/components/schemas/typeId'
              description: >-
                The counterparty (ctp_…) that still owns active/pending External
                Accounts.
            activeExternalAccountIds:
              type: array
              items:
                $ref: '#/components/schemas/typeId'
              description: Public ids (ext_…) of the External Accounts blocking the delete.
          required:
            - counterpartyId
            - activeExternalAccountIds
          description: >-
            Structured detail identifying the blocking External Accounts and
            their counterparty.
      description: >-
        409 body returned by DELETE /counterparties/{id} when the counterparty
        still

        owns active or pending External Accounts.
        `details.activeExternalAccountIds`

        lists the blocking accounts (which must be deleted before the
        counterparty can

        be removed) and `details.counterpartyId` echoes the affected
        counterparty.
      example:
        error: counterparty still owns active or pending external accounts
        code: counterpartyHasActiveExternalAccounts
        details:
          counterpartyId: ctp_yp5z8m7n22svc0vh6edqgcfdat
          activeExternalAccountIds:
            - ext_fky491gakzj0dd46qb6whsr2vq
            - ext_95863ktcdhw27ze8hxgybb24n9
    CounterpartyList:
      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/Counterparty'
          description: The page of results.
    CounterpartyStatus:
      type: string
      enum:
        - active
        - rejected
        - deleted
      description: |-
        Lifecycle of a counterparty. `rejected` is reserved for create-time
        compliance screening (not yet active); `deleted` marks a soft-deleted
        record that remains readable by id.
    CounterpartyUpdateRequest:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 140
        entityType:
          allOf:
            - $ref: '#/components/schemas/CounterpartyEntityType'
          description: '`individual` or `business`.'
        address:
          allOf:
            - $ref: '#/components/schemas/Address'
          description: The counterparty's postal address.
        email:
          type: string
          description: Contact email address.
        phone:
          type: string
          description: Phone in E.164 format.
        taxId:
          type: string
          description: >-
            Tax ID (CPF, CNPJ, SSN, etc.). Required for some external-account
            types.
        dateOfBirth:
          type: string
          format: date
          description: Date of birth (YYYY-MM-DD).
        nationality:
          type: string
        metadata:
          type: object
          additionalProperties:
            type: string
          description: >-
            Free-form key-value pairs stored on the resource and echoed back on
            reads.
      description: |-
        Partial update — every field optional; omitted fields are unchanged.
        Unknown fields are rejected with 400 (strict decode) by the handler.
    CreateCashInRequest:
      type: object
      required:
        - customerId
        - source
        - destination
        - cash
      properties:
        customerId:
          type: string
          description: The customer depositing cash (`cst_` prefix).
        source:
          allOf:
            - $ref: '#/components/schemas/CashInSource'
          description: Where the customer will deposit cash.
        destination:
          allOf:
            - $ref: '#/components/schemas/CashInDestination'
          description: Crypto instrument to deliver to (walletOms or walletExternal).
        cash:
          allOf:
            - $ref: '#/components/schemas/CashInfo'
          description: The cash amount to deposit.
        sponsorGas:
          type: boolean
          description: >-
            When `true`, OMS absorbs the on-chain gas cost for the destination
            delivery. Only `true` is currently supported.
        metadata:
          type: object
          additionalProperties:
            type: string
          description: >-
            Free-form key-value pairs stored on the resource and echoed back on
            reads.
      description: >-
        Request body for creating a cash-in. Names the customer, the cash source
        location, and the crypto destination.
      example:
        customerId: cst_vfa0nxw6zvyws9g237jrxn4y7k
        source:
          asset: usd
          indicatedAmount: '200.00'
        destination:
          asset: usdc
          network: polygon
          wallet:
            id: wlt_5h4jzzpr9xre3bamd9ca7qyghn
        cash:
          locationId: loc_01H9Xd
          locationReference: R1JFRU5ET1QtMjQzNA==
        sponsorGas: true
        metadata:
          orderId: order_12345
    CryptoNetwork:
      type: string
      enum:
        - ethereum
        - polygon
        - base
        - solana
      description: >-
        Wire vocabulary for a crypto `network` request field: ethereum, polygon,

        base, solana. This is vocabulary, not availability — which of these a
        given

        destination type actually accepts is enforced at runtime per destination

        type against the narrower Erebor-served set, so `polygon` is legal on
        the

        wire but currently rejected wherever Erebor does not serve it. Numeric
        EVM

        chain ids (e.g. "1", "137", "8453") were never accepted by BPN — no

        chain-id-to-name coercion exists, so nothing here deprecates prior

        behavior. Values are lowercase on the wire; the server additionally

        normalizes case and surrounding whitespace on input, so this schema is

        stricter than the server in that one dimension — send lowercase,

        untrimmed-safe values to stay strictly schema-valid.


        A `network` field may be typed `CryptoNetwork` regardless of whether it

        appears on a response, as long as its sole writer is gated by

        `eanetworks.AllServedNetworks()` — a runtime-enforced subset of this
        enum,

        with the containment itself enforced by

        `TestCryptoNetwork_SupersetOfServedNetworks`

        (services/externalaccount/networks/networks_test.go). That guarantee is

        what makes the enum safe there: the value can never leave the enum's

        vocabulary no matter which code path renders it. A `network` field whose

        writer is NOT so gated stays `string` pending #2666's outbound enum
        guard —

        for such a field, a stored value outside the enum would break a strict

        partner client validator (this happened in production: #2528). `chain`

        fields are deliberately excluded too: their vocabulary is wider and

        includes `bitcoin`, which this enum does not carry.
    CryptoReturnDestination:
      type: object
      required:
        - type
        - network
        - id
      properties:
        type:
          type: string
          enum:
            - walletOms
            - walletExternal
        network:
          allOf:
            - $ref: '#/components/schemas/CryptoNetwork'
          description: >-
            Return network. Must equal the DA's expectedSourceNetwork for the
            return to be usable.
        id:
          type: string
          description: >-
            walletOms: OMS wallet id (acc_…). walletExternal: registered
            ExternalAccount id (ext_…).
      description: >-
        Registered crypto return destination for a Deposit Address (v0.11-8):
        where an

        operations-triggered return of a stranded inbound deposit is sent.
        `network` must be one of

        ethereum | base | solana; a custodial (non-multi-asset) walletOms target
        is rejected with

        422 returnDestinationMustBeMultiAsset. `network` is a closed
        `CryptoNetwork` enum even

        though this model also appears on response paths
        (`DepositAddress.returnDestination`,

        `RedrivableTransaction.returnDestination`); that is safe only because
        the sole writer is

        gated by `eanetworks.AllServedNetworks()`, a subset of `CryptoNetwork`,
        and that containment

        is enforced by `TestCryptoNetwork_SupersetOfServedNetworks`

        (services/externalaccount/networks/networks_test.go).
    CustomerBalanceAggregate:
      type: object
      required:
        - data
      properties:
        data:
          type: object
          properties:
            customerId:
              allOf:
                - $ref: '#/components/schemas/typeId'
              description: 'Public OMS customer ID, format `cst_<typeID>`.'
            estimatedBalanceValue:
              allOf:
                - $ref: '#/components/schemas/fixedDecimalString'
              description: >-
                Estimated total balance value across all customer
                wallets/assets, in
                        the currency requested via the `estimatedBalanceCurrencyCode` query
                        param. Defaults to USD when the query param is omitted. Decimal
                        string.
            estimatedBalanceCurrencyCode:
              type: string
              description: Currency code used for `estimatedBalanceValue`.
            updatedAt:
              type: string
              format: date-time
              description: >-
                Most recent provider balance timestamp included in the
                aggregate.
                        Omitted when no provider balance timestamps were available to
                        aggregate.
            totalBalance:
              allOf:
                - $ref: '#/components/schemas/CustomerTotalBalance'
              description: |-
                USD balance rollup (fiat / crypto / total) for OMSX to compose
                        `Customer.totalBalance` (v0.11-8, #2362). Mirrors the OMS
                        `Customer.totalBalance` shape 1:1. Omitted as a whole when the Coinme
                        provider read (or the fiat mirror read) fails — a partial/half total is
                        never returned. `estimatedBalanceValue` above is retained unchanged for
                        back-compat.
          required:
            - customerId
            - estimatedBalanceValue
            - estimatedBalanceCurrencyCode
      description: >-
        A customer's estimated total balance, aggregated across all of their
        wallets and assets.
    CustomerNotFoundErrorBody:
      type: object
      required:
        - error
      properties:
        error:
          type: string
          enum:
            - customer not found
          description: Human-readable error identifier.
    CustomerTotalBalance:
      type: object
      properties:
        totalUsd:
          allOf:
            - $ref: '#/components/schemas/signedFixedDecimalString'
          description: |-
            `fiatUsd + cryptoUsd`, formatted to 2 decimal places, sign preserved
                  (e.g. `"25.00"`, `"-15.50"`).
        fiatUsd:
          allOf:
            - $ref: '#/components/schemas/signedFixedDecimalString'
          description: |-
            Signed sum of the customer's USD fiat-wallet balances, read from the
                  cached Erebor mirror (`account_balances`, USD 1:1). No Erebor call on the
                  hot path. Formatted to 2 decimal places, sign preserved.
        cryptoUsd:
          allOf:
            - $ref: '#/components/schemas/signedFixedDecimalString'
          description: >-
            Signed sum of Coinme custodial crypto balances valued in USD,
            formatted to
                  2 decimal places. `"0.00"` for a customer with no Coinme account.
      description: >-
        USD balance rollup exposed on the customer-balance read, shaped to match
        the

        OMS `Customer.totalBalance` object so OMSX maps it field-for-field.


        All three values are signed USD decimal strings (a fiat balance may be

        negative after an ACH clawback that overdraws the deposit account, so
        the

        total may be negative too — consumers must render the sign verbatim,
        never

        clamp to zero). Read-only: this object appears only on the balance GET.


        `cryptoUsd` is custodial-only. It sums Coinme's per-asset

        `estimatedBalanceValue` (already USD-denominated; no new
        oracle/pricing).

        Embedded (non-custodial) wallets have no balance source in BPN and are
        not

        valued here. An Erebor-only customer (no Coinme account) gets

        `cryptoUsd = "0"` rather than a 422.
    CustomerWallet:
      type: object
      properties:
        id:
          allOf:
            - $ref: '#/components/schemas/typeId'
          description: Unique identifier.
        customerId:
          allOf:
            - $ref: '#/components/schemas/typeId'
          description: |-
            The customer that owns the wallet. `cst_` prefix. Always present in
            project-wide `GET /wallets` responses so each row is attributable.
        walletAddress:
          type: string
          description: On-chain wallet address.
        currencySymbol:
          type: string
          description: Display symbol of the currency.
        currencyName:
          type: string
          description: Display name of the currency.
        assetId:
          type: string
          description: Asset identifier.
        chain:
          type: string
          description: Chain the wallet lives on.
        blockchainAsset:
          $ref: '#/components/schemas/BlockchainAsset'
        balance:
          type: string
          description: Current balance.
        createdAt:
          type: string
          format: date-time
          description: When the resource was created.
      description: >-
        A single customer wallet: one asset on one chain, with its balance and
        address.
    DepositAddress:
      type: object
      properties:
        id:
          allOf:
            - $ref: '#/components/schemas/typeId'
          description: Deposit Address ID (`da_` prefix).
        object:
          type: string
          enum:
            - depositAddress
          description: Resource type discriminator. Always "depositAddress".
        customerId:
          allOf:
            - $ref: '#/components/schemas/typeId'
          description: >-
            Public customer id (cst_...). Named customerId to match VA's naming
            convention.
        status:
          allOf:
            - $ref: '#/components/schemas/DepositAddressStatus'
          description: Current lifecycle status of the deposit address.
        statusReason:
          type: string
          description: Human-readable explanation of the current status.
        expectedSourceAsset:
          type: string
          description: Asset of the inbound crypto the DA expects.
        expectedSourceNetwork:
          allOf:
            - $ref: '#/components/schemas/CryptoNetwork'
          description: Network of the inbound crypto the DA expects.
        depositInstructions:
          allOf:
            - $ref: '#/components/schemas/DepositAddressDepositInstructions'
          description: >-
            Null in the 201 until DEPOSIT_ACCOUNT.OPEN populates the
            Erebor-owned inlet

            address.
        destination:
          allOf:
            - $ref: '#/components/schemas/TransactionDestination'
          description: >-
            V0.10: unified destination shape (payoutOrigin now lives inside
            TransactionDestination).
        returnDestination:
          allOf:
            - $ref: '#/components/schemas/CryptoReturnDestination'
          description: 'Registered crypto return destination (v0.11-8), echoed when set.'
        failureReason:
          allOf:
            - $ref: '#/components/schemas/DepositAddressFailureReason'
          description: >-
            Set when status = `failed`; closed enum identifying the failure
            category.
        sourceToDestination:
          allOf:
            - $ref: '#/components/schemas/SourceToDestination'
          description: |-
            Derived from the destination type: `cryptoToFiatAccount` for a bank
            destination, or `cryptoToCrypto` for a crypto-wallet destination.
        sponsorGas:
          type: boolean
          description: >-
            Whether OMS absorbs the on-chain gas cost for the destination
            delivery.

            Persisted from the create/update request (currently only `true` is

            accepted).
        label:
          type: string
          description: Partner display label.
        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 deposit address was created.
        updatedAt:
          type: string
          format: date-time
          description: When the deposit address was last updated.
      description: >-
        A reusable crypto deposit configuration. Senders deposit the expected

        asset/network to the assigned on-chain address; OMS converts and
        delivers the

        funds to the configured bank destination automatically, creating a

        transaction per inbound deposit.
    DepositAddressCreateRequest:
      type: object
      required:
        - customerId
        - expectedSourceAsset
        - expectedSourceNetwork
        - destination
      properties:
        customerId:
          type: string
          description: Owning customer (cus_… or legacy public id).
        expectedSourceAsset:
          type: string
          description: >-
            Asset of the inbound crypto the DA expects. "usdc" | "usdt"
            (lowercase).
        expectedSourceNetwork:
          allOf:
            - $ref: '#/components/schemas/CryptoNetwork'
          description: >-
            Network of the inbound crypto the DA expects. `CryptoNetwork` is the
            wire

            vocabulary (ethereum/polygon/base/solana); availability here is
            narrower —

            a closed allowlist of `ethereum` | `base` | `solana`. Any other
            value

            (arbitrum, optimism, polygon, ink, sui, …) is rejected with

            `expectedSourceNetworkUnsupported`.
        destination:
          allOf:
            - $ref: '#/components/schemas/DepositAddressDestinationRequest'
          description: >-
            Side-shaped destination. Fiat: bankUs / bankIban / bankCanada
            registered

            External Account (cryptoToFiatAccount). Crypto: walletExternal
            (registered

            ExternalAccount) delivers crypto onward (cryptoToCrypto;
            routes-table gated

            to ethereum/base/solana). walletOms is NOT currently supported — 422

            destinationWalletOmsNotSupported; use walletExternal. The server
            validates

            details (asset/network/accountHolder) against the resolved EA.
        returnDestination:
          allOf:
            - $ref: '#/components/schemas/CryptoReturnDestination'
          description: >-
            Registered crypto return destination (v0.11-8), for
            operations-triggered

            returns of stranded inbound deposits.
        sponsorGas:
          type: boolean
          description: |-
            When `true`, OMS absorbs the on-chain gas cost for the destination
            delivery. Only `true` is currently supported. Ignored for non-crypto
            destinations (no on-chain leg).
          default: true
        label:
          type: string
          description: Partner display label.
        metadata:
          type: object
          additionalProperties:
            type: string
          description: >-
            Free-form key-value pairs stored on the resource and echoed back on
            reads.
      description: >-
        Create a Deposit Address: the expected inbound asset/network pair plus
        the

        bank destination that receives the converted funds.
      example:
        customerId: cst_vfa0nxw6zvyws9g237jrxn4y7k
        expectedSourceAsset: usdc
        expectedSourceNetwork: ethereum
        destination:
          type: bankUs
          details:
            id: ext_fky491gakzj0dd46qb6whsr2vq
            asset: usd
            network: ach
            accountHolder: customer
        sponsorGas: true
        label: Alice deposit address
    DepositAddressDepositInstructions:
      type: object
      required:
        - asset
        - network
        - address
      properties:
        asset:
          type: string
          description: Same value as expectedSourceAsset.
        network:
          allOf:
            - $ref: '#/components/schemas/CryptoNetwork'
          description: Same value as expectedSourceNetwork.
        address:
          type: string
          description: Erebor-owned on-chain inlet address for this DA.
        expiresAt:
          type: string
          format: date-time
          description: >-
            Placeholder for a future provider-imposed inlet expiry. Null for
            Erebor

            DDAs today; surfaced now so adding it later is not a breaking
            change.
      description: 'The on-chain address senders deposit to, with its asset and network.'
    DepositAddressDestinationRequest:
      type: object
      oneOf:
        - $ref: '#/components/schemas/BankUsSideRequest'
        - $ref: '#/components/schemas/BankIbanSideRequest'
        - $ref: '#/components/schemas/BankCanadaSideRequest'
        - $ref: '#/components/schemas/WalletOmsSideRequest'
        - $ref: '#/components/schemas/WalletExternalRegisteredSideRequest'
      discriminator:
        propertyName: type
        mapping:
          bankUs: '#/components/schemas/BankUsSideRequest'
          bankIban: '#/components/schemas/BankIbanSideRequest'
          bankCanada: '#/components/schemas/BankCanadaSideRequest'
          walletOms: '#/components/schemas/WalletOmsSideRequest'
          walletExternal: '#/components/schemas/WalletExternalRegisteredSideRequest'
      description: >-
        Deposit Address destination — where converted funds are delivered, on
        the

        shared discriminated side shape.


        Fiat arms (`bankUs` / `bankIban` / `bankCanada`) deliver to a registered

        bank-type External Account (`cryptoToFiatAccount`). The `walletExternal`

        crypto arm delivers crypto onward to a registered wallet
        (`cryptoToCrypto`),

        gated by the routes table to Erebor-serviceable networks

        (ethereum/base/solana — Polygon is rejected). `walletExternal` is

        registered-only (`ext_wlt_` EA id; raw blockchainAddress stays
        Cash-In-only).


        `walletOms` is declared but NOT currently supported as a destination: it
        is

        rejected with 422 `destinationWalletOmsNotSupported`. Use
        `walletExternal`

        for externally-held wallets. (Planned to return for non-custodial
        wallets in

        v0.12.)


        The reused side arms carry an optional `amount`, which is meaningless
        for a

        standing destination and rejected at validation. The server validates
        the side

        `details` (asset/network/accountHolder) against the resolved EA/wallet.
    DepositAddressFailureReason:
      type: string
      enum:
        - provisioningTimeout
        - systemError
        - ereborRejected
        - intlBankAccountCreateRejected
        - noMatchingNetwork
        - blockchainAddressInUse
        - bankAccountInUse
      description: >-
        Closed enum carried on DA when status = "failed". camelCase per partner
        channel naming convention.
    DepositAddressList:
      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/DepositAddress'
          description: The page of results.
      description: Paginated list of DepositAddress resources.
    DepositAddressStatus:
      type: string
      enum:
        - pending
        - active
        - frozen
        - closed
        - failed
        - inactiveActionRequired
      description: >-
        Lifecycle of a Deposit Address. pending: awaiting on-chain address

        assignment. active: accepting deposits. frozen: deposits held by
        compliance.

        inactiveActionRequired: destination unusable, re-point `destination` to

        recover. closed: permanently disabled. failed: provisioning failed.
    DepositAddressUpdateRequest:
      type: object
      properties:
        destination:
          allOf:
            - $ref: '#/components/schemas/DepositAddressDestinationRequest'
          description: >-
            Re-point the DA destination (bank-type External Account by EA id, or
            a

            registered walletExternal crypto wallet). Re-validated exactly like

            create; walletOms is NOT currently supported — 422

            destinationWalletOmsNotSupported.
        returnDestination:
          allOf:
            - $ref: '#/components/schemas/CryptoReturnDestination'
          description: >-
            Re-point the registered crypto return destination (v0.11-8).
            PATCHable per

            the v0.11-8 contract; send explicit `null` to clear.
        sponsorGas:
          type: boolean
          description: |-
            When `true`, OMS absorbs the on-chain gas cost for the destination
            delivery. Only `true` is currently supported; accepted for
            forward-compatibility.
          default: true
        label:
          type: string
          description: Partner display label.
        metadata:
          type: object
          additionalProperties:
            type: string
          description: >-
            Free-form key-value pairs stored on the resource and echoed back on
            reads.
      description: >-
        Partial update payload for a Deposit Address. The patchable fields are

        `destination` (re-point to a different bank-type External Account),
        `returnDestination`,

        `label`, and `metadata`. Any additional key in the JSON body is rejected
        with 400 by

        the handler (strict whitelist).


        Re-pointing `destination` to a healthy bank External Account recovers a
        DA

        from `inactiveActionRequired` back to `active`; a re-point on an

        already `active` DA updates the target without a status transition.
    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
    DirectionalFlag:
      type: object
      required:
        - asSource
        - asDestination
      properties:
        asSource:
          type: boolean
        asDestination:
          type: boolean
      description: >-
        Whether a resource can use a network as a transaction source, a
        destination,

        or both. Both flags are always present; `false` means checked-and-no.
    EreborValidationFailedErrorBody:
      type: object
      required:
        - error
        - code
      properties:
        error:
          type: string
        code:
          type: string
          enum:
            - ereborValidationFailed
        details:
          $ref: '#/components/schemas/ProviderRejectionDetail'
      description: >-
        Body of the 422 returned when the payment provider terminally rejects a
        Virtual Account or Deposit Address create. `details` carries the
        structured, partner-safe rejection reason when the provider returned a
        decoded error envelope.
    ExternalAccount:
      type: object
      properties:
        id:
          allOf:
            - $ref: '#/components/schemas/typeId'
          description: External Account ID (`ext_` prefix).
        object:
          type: string
          enum:
            - externalAccount
          description: Resource type discriminator. Always "externalAccount".
        owner:
          allOf:
            - $ref: '#/components/schemas/ExternalAccountOwner'
          description: 'Who owns this account: the customer or one of their counterparties.'
        type:
          allOf:
            - $ref: '#/components/schemas/ExternalAccountType'
          description: The instrument type; determines which detail object is populated.
        category:
          allOf:
            - $ref: '#/components/schemas/ExternalAccountCategory'
          description: >-
            High-level grouping: `fiatAccount` for bank or card accounts,
            `crypto` for

            wallets. The same value as the instrument `category` when this
            account is

            referenced in a transaction.
        status:
          allOf:
            - $ref: '#/components/schemas/ExternalAccountStatus'
          description: |-
            Current lifecycle status. A transition to `invalid` always fires the
            `externalAccount.statusChanged` webhook.
        failureReason:
          allOf:
            - $ref: '#/components/schemas/ExternalAccountFailureReason'
          description: Set when `status = failed`.
        failureDetail:
          allOf:
            - $ref: '#/components/schemas/ProviderRejectionDetail'
          description: >-
            Structured provider rejection detail. Set when `status = failed` and
            the failure was a provider terminal rejection; absent for
            provisioning timeouts and internal failures.
        rejectionReason:
          type: string
          description: Set when status = `rejected` (compliance screening).
        invalidReason:
          type: string
          description: >-
            Set when `status = invalid` (derived from payout returns). Free-text
            for

            now; a closed enum lands with the invalidation transition logic.
        label:
          type: string
          description: Optional display label.
        metadata:
          type: object
          additionalProperties:
            type: string
          description: Free-form key-value pairs supplied at creation or update.
        bankUs:
          allOf:
            - $ref: '#/components/schemas/ExternalAccountBankUsResponse'
          description: Populated when `type = bankUs`.
        bankIban:
          allOf:
            - $ref: '#/components/schemas/ExternalAccountBankIbanResponse'
          description: Populated when `type = bankIban`.
        bankCanada:
          allOf:
            - $ref: '#/components/schemas/ExternalAccountBankCanadaResponse'
          description: Populated when `type = bankCanada`.
        walletExternal:
          allOf:
            - $ref: '#/components/schemas/ExternalAccountWalletExternalResponse'
          description: Populated when `type = walletExternal`.
        card:
          allOf:
            - $ref: '#/components/schemas/ExternalAccountCardResponse'
          description: Populated when `type = card`.
        resolvedTransactions:
          type: array
          items:
            $ref: '#/components/schemas/typeId'
          description: >-
            Transaction ids that this registration submitted for
            sender-attribution

            release. Returned ONLY on the POST create response, and only when

            registering this walletExternal matched held inbounds. Attribution
            is async:

            each entry is submitted to the provider from

            `awaitingAction.awaitingSenderAttribution` and moves to

            `processing.fundsPulled` once settlement confirms — so an immediate
            GET of an

            id may still show `awaitingAction`. Omitted on GETs (the create path
            is the

            only writer).
        createdAt:
          type: string
          format: date-time
          description: When the external account was registered.
        updatedAt:
          type: string
          format: date-time
          description: When the external account was last updated.
      description: |-
        A saved payment destination registered for a customer or one of their
        counterparties. Exactly one of the per-type response detail objects is
        populated, selected by `type`. Write-only secrets (full account number,
        full IBAN) are never present on reads - only their last-4 renderings.
    ExternalAccountBankCanadaRequest:
      type: object
      required:
        - institutionNumber
        - transitNumber
        - accountNumber
      properties:
        institutionNumber:
          type: string
          description: Three-digit institution number.
        transitNumber:
          type: string
          description: Five-digit transit number.
        accountNumber:
          type: string
          description: >-
            Canadian bank account number (7-12 digits). Write-only; never
            returned

            (reads expose `accountNumberLast4`).
        bankName:
          type: string
          description: Bank display name.
      description: bankCanada create detail.
    ExternalAccountBankCanadaResponse:
      type: object
      required:
        - institutionNumber
        - transitNumber
        - accountNumberLast4
      properties:
        institutionNumber:
          type: string
          description: Three-digit institution number.
        transitNumber:
          type: string
          description: Five-digit transit number.
        accountNumberLast4:
          type: string
          description: Last four digits of the Canadian bank account number.
        bankName:
          type: string
          description: Bank display name.
      description: >-
        bankCanada response detail. The full account number is never echoed -
        only

        its last four digits.
    ExternalAccountBankIbanRequest:
      type: object
      required:
        - iban
        - BIC
      properties:
        iban:
          type: string
          description: |-
            IBAN value. Write-only; never returned (reads expose `ibanLast4`).
            Shape `^[A-Z]{2}[0-9]{2}[A-Z0-9]{11,30}$`.
        BIC:
          type: string
          description: SWIFT BIC (8 or 11 chars).
        bankAddress:
          allOf:
            - $ref: '#/components/schemas/Address'
          description: Structured bank postal address (canonical Address).
        countryCode:
          type: string
          description: >-
            ISO 3166-1 alpha-2. Optional - derived from the IBAN's first two
            letters

            when omitted; validated against any supplied value.
      description: bankIban create detail.
    ExternalAccountBankIbanResponse:
      type: object
      required:
        - ibanLast4
        - BIC
        - countryCode
      properties:
        ibanLast4:
          type: string
          description: Last four characters of the IBAN.
        BIC:
          type: string
          description: SWIFT BIC (8 or 11 chars).
        bankAddress:
          allOf:
            - $ref: '#/components/schemas/Address'
          description: Structured bank postal address (canonical Address).
        countryCode:
          type: string
          description: ISO 3166-1 alpha-2; derived from the IBAN prefix when not supplied.
      description: |-
        bankIban response detail. The full IBAN is never echoed - only its last
        four characters.
    ExternalAccountBankUsRequest:
      type: object
      required:
        - accountNumber
        - routingNumber
      properties:
        accountNumber:
          type: string
          description: |-
            US bank account number. Write-only; never returned (reads expose
            `accountNumberLast4`).
        routingNumber:
          type: string
          description: Nine-digit ABA routing number.
        accountType:
          $ref: '#/components/schemas/BankAccountType'
        bankName:
          type: string
          description: Bank display name.
      description: bankUs create detail.
    ExternalAccountBankUsResponse:
      type: object
      required:
        - accountNumberLast4
        - routingNumber
      properties:
        accountNumberLast4:
          type: string
          description: Last four digits of the US bank account number.
        routingNumber:
          type: string
          description: Nine-digit ABA routing number (not a secret).
        accountType:
          $ref: '#/components/schemas/BankAccountType'
        bankName:
          type: string
          description: Bank display name.
      description: >-
        bankUs response detail. The full account number is never echoed - only
        its

        last four digits.
    ExternalAccountCardResponse:
      type: object
      properties:
        cardNumberLast4:
          type: string
          description: Last four digits of the card PAN.
        cardProvider:
          allOf:
            - $ref: '#/components/schemas/CardBrand'
          description: 'Card brand, derived server-side from the PAN.'
        cardType:
          allOf:
            - $ref: '#/components/schemas/CardType'
          description: 'Card funding type, derived server-side. Only `debit` today.'
        expiryMonth:
          type: integer
          format: int32
          description: Card expiry month (MM).
        expiryYear:
          type: integer
          format: int32
          description: Card expiry year (YYYY).
        billingAddressSource:
          allOf:
            - $ref: '#/components/schemas/BillingAddressSource'
          description: >-
            Whether the stored billing address was supplied on the request or
            filled

            from the owning customer's address.
      description: >-
        card response detail. Last-4 + expiry only; PAN/CVV are never stored or

        returned. `cardProvider` (brand) and `cardType` are derived server-side
        from

        the PAN and are response-only.
    ExternalAccountCategory:
      type: string
      enum:
        - fiatAccount
        - crypto
      description: 'Coarse classification derived from `type`, stored for query convenience.'
    ExternalAccountCreateRequest:
      type: object
      required:
        - owner
        - type
      properties:
        owner:
          allOf:
            - $ref: '#/components/schemas/ExternalAccountOwner'
          description: >-
            Who owns this account - `{ kind: customer, customerId }` or

            `{ kind: counterparty, counterpartyId }`. Cards must be
            customer-owned.
        type:
          allOf:
            - $ref: '#/components/schemas/ExternalAccountType'
          description: >-
            The instrument type. Exactly one matching per-type detail object
            must be

            supplied.
        label:
          type: string
          description: Optional display label.
        metadata:
          type: object
          additionalProperties:
            type: string
          description: >-
            Free-form key-value pairs stored on the resource and echoed back on
            reads.
        bankUs:
          allOf:
            - $ref: '#/components/schemas/ExternalAccountBankUsRequest'
          description: Required when `type = bankUs`.
        bankIban:
          allOf:
            - $ref: '#/components/schemas/ExternalAccountBankIbanRequest'
          description: Required when `type = bankIban`.
        bankCanada:
          allOf:
            - $ref: '#/components/schemas/ExternalAccountBankCanadaRequest'
          description: Required when `type = bankCanada`.
        walletExternal:
          allOf:
            - $ref: '#/components/schemas/ExternalAccountWalletExternalRequest'
          description: Required when `type = walletExternal`.
      description: |-
        Create an External Account. Exactly one per-type detail object must be
        supplied, matching `type`; the service validates the correct subset and
        rejects mismatches with 422.
    ExternalAccountFailureReason:
      type: string
      enum:
        - ereborRejected
        - cardProviderRejected
        - providerAccountMissing
        - cardLimitReached
        - cardInUse
        - provisioningTimeout
        - systemError
      description: Closed enum stamped on an External Account when `status = failed`.
    ExternalAccountList:
      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/ExternalAccount'
          description: The page of results.
      description: Paginated list of ExternalAccount resources.
    ExternalAccountOwner:
      type: object
      oneOf:
        - $ref: '#/components/schemas/OwnerCustomer'
        - $ref: '#/components/schemas/OwnerCounterparty'
      discriminator:
        propertyName: kind
        mapping:
          customer: '#/components/schemas/OwnerCustomer'
          counterparty: '#/components/schemas/OwnerCounterparty'
      description: Who owns the External Account.
    ExternalAccountRejectedErrorBody:
      type: object
      required:
        - error
        - code
      properties:
        error:
          type: string
        code:
          type: string
          enum:
            - externalAccountRejected
        details:
          $ref: '#/components/schemas/ProviderRejectionDetail'
      description: >-
        Body of the 422 returned when the payment provider terminally rejects an
        External Account create. `details` carries the structured, partner-safe
        rejection reason when the provider returned a decoded error envelope; it
        is absent when the rejection has no partner-safe detail (e.g. a
        provider-side auth failure).
    ExternalAccountStatus:
      type: string
      enum:
        - active
        - pending
        - rejected
        - invalid
        - deleted
        - failed
      description: >-
        Lifecycle of an External Account. `pending → active` on successful
        Erebor

        provisioning; `pending → failed` on Erebor rejection or provisioning

        timeout. `rejected` (create-time country screening) and `invalid`
        (derived

        from payout returns) are reserved enum values with no transition logic
        in

        this slice. `deleted` is the soft-delete terminal.
    ExternalAccountStatusReason:
      type: string
      enum:
        - deleted
        - invalid
    ExternalAccountType:
      type: string
      enum:
        - bankUs
        - bankIban
        - bankCanada
        - card
        - walletExternal
      description: >-
        External Account type. `card` is created only via the dedicated

        `POST /external-accounts/cards` endpoint; supplying `type = card` to the

        generic create is rejected with 422 `cardMustUseCardEndpoint`. `card`
        and

        `walletExternal` remain valid for reads, lists, get and delete.
    ExternalAccountUpdateRequest:
      type: object
      properties:
        label:
          type: string
          description: Optional display label.
        metadata:
          type: object
          additionalProperties:
            type: string
          description: >-
            Free-form key-value pairs stored on the resource and echoed back on
            reads.
      description: |-
        Partial update - only `label` and `metadata` are mutable. Financial /
        identity fields are immutable (re-pointing a destination is create-new +
        re-point). Any other JSON key in the body is rejected with 400.
    ExternalAccountWalletExternalRequest:
      type: object
      required:
        - blockchainAddress
        - networkFamily
        - custodian
      properties:
        blockchainAddress:
          type: string
          description: >-
            Blockchain wallet address. For `networkFamily = evm` the address
            must be

            all-lowercase, all-uppercase, or a valid EIP-55 checksummed form; an

            inconsistent mixed-case address is rejected as a likely casing typo,
            and the

            zero address is rejected. Solana is validated structurally.
        networkFamily:
          $ref: '#/components/schemas/NetworkFamily'
        custodian:
          allOf:
            - $ref: '#/components/schemas/DestinationCustodian'
          description: DestinationCustodian enum value (reused from VA).
        otherCustodian:
          type: string
          description: Required iff `custodian = OTHER`; max 100 chars.
      description: >-
        walletExternal create detail. The address is stored as submitted and
        matched

        exactly; the service normalizes it (EVM lowercased, Solana raw) for the

        upsert key.
    ExternalAccountWalletExternalResponse:
      type: object
      required:
        - blockchainAddress
        - networkFamily
        - custodian
      properties:
        blockchainAddress:
          type: string
          description: 'The registered blockchain address, as submitted.'
        networkFamily:
          $ref: '#/components/schemas/NetworkFamily'
        custodian:
          allOf:
            - $ref: '#/components/schemas/DestinationCustodian'
          description: DestinationCustodian enum value (reused from VA).
        otherCustodian:
          type: string
          description: Set when `custodian = OTHER`.
        supportedDestinations:
          type: array
          items:
            $ref: '#/components/schemas/SupportedDestination'
          description: >-
            The (asset, network) pairs this wallet can receive, derived from

            `networkFamily` (`{usdc, usdt}` across the family's served
            networks).
      description: >-
        walletExternal response detail. The blockchain address is public, so it
        is

        echoed as submitted.
    ExternalCustodyCreditInfo:
      type: object
      required:
        - walletAddress
      properties:
        walletAddress:
          type: string
          description: On-chain wallet address.
        blockchainMemo:
          type: string
          description: On-chain memo/tag to attach to the credit.
      description: >-
        Destination details for crediting funds to a wallet held in external
        custody.
    FeeEntry:
      type: object
      properties:
        id:
          type: string
          description: Unique identifier assigned by OMS. Present on responses only.
        percentage:
          type: string
          description: Percentage fee as a decimal rate. "0.02" = 2%.
        flatFee:
          type: string
          description: Fixed fee in USD. Converted to fee-side asset at the exchange rate.
        amount:
          type: string
          description: Computed fee amount for this entry. Present on responses only.
        payoutAsset:
          type: string
          enum:
            - usdc
            - usdt
          description: Crypto asset for fee payout. Defaults to "usdc".
        wallet:
          type: string
          description: OMS wallet to receive this fee.
      description: >-
        A single developer fee entry. At least one of percentage or flatFee is
        required.
    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.
    FiatReturnDestination:
      type: object
      oneOf:
        - $ref: '#/components/schemas/FiatReturnDestinationBankUs'
        - $ref: '#/components/schemas/FiatReturnDestinationBankIban'
        - $ref: '#/components/schemas/FiatReturnDestinationBankCanada'
        - $ref: '#/components/schemas/FiatReturnDestinationWalletFiat'
      discriminator:
        propertyName: type
        mapping:
          bankUs: '#/components/schemas/FiatReturnDestinationBankUs'
          bankIban: '#/components/schemas/FiatReturnDestinationBankIban'
          bankCanada: '#/components/schemas/FiatReturnDestinationBankCanada'
          walletFiat: '#/components/schemas/FiatReturnDestinationWalletFiat'
      description: >-
        Where inbound fiat is returned when its outbound leg can't be completed

        (v0.11-8). Pick a `type`: a bank account (`bankUs` / `bankIban` /

        `bankCanada`, each with a required `network` naming the rail) or a fiat

        balance wallet (`walletFiat` — no network, internal ledger). Shared by
        the

        Virtual Account `returnDestination` and (later) the return policy's

        `fiat.returnDestinations`. `walletFiat`, and `bankCanada` with a `local`

        network (CAD), are rejected with 422 `railNotSupported` in v1 — bank
        rails

        (USD) only.
    FiatReturnDestinationBankCanada:
      type: object
      required:
        - type
        - network
        - id
      properties:
        type:
          type: string
          enum:
            - bankCanada
          description: Type discriminator.
        network:
          type: string
          enum:
            - swift
            - local
          description: USD uses swift; CAD uses local (CAD rejected 422 in v1).
        id:
          type: string
          description: Canadian bank ExternalAccount id (ext_ prefix).
      description: >-
        Registered Canadian bank fiat return destination (v0.11-8). USD uses
        `swift`;

        CAD (`local`) is rejected with 422 in v1 (USD-only).
      title: Canadian bank account
    FiatReturnDestinationBankIban:
      type: object
      required:
        - type
        - network
        - id
      properties:
        type:
          type: string
          enum:
            - bankIban
          description: Type discriminator.
        network:
          type: string
          enum:
            - swift
        id:
          type: string
          description: IBAN ExternalAccount id (ext_ prefix).
      description: Registered IBAN fiat return destination (v0.11-8).
      title: IBAN bank account
    FiatReturnDestinationBankUs:
      type: object
      required:
        - type
        - network
        - id
      properties:
        type:
          type: string
          enum:
            - bankUs
          description: Type discriminator.
        network:
          type: string
          enum:
            - ach
            - achSameDay
            - wire
          description: Rail to return on.
        id:
          type: string
          description: US bank ExternalAccount id (ext_ prefix).
      description: Registered US bank fiat return destination (v0.11-8).
      title: US bank account
    FiatReturnDestinationWalletFiat:
      type: object
      required:
        - type
        - id
      properties:
        type:
          type: string
          enum:
            - walletFiat
          description: Type discriminator.
        id:
          type: string
          description: OMS fiat wallet id (wlt_fiat_ prefix). Rejected 422 in v1.
      description: >-
        Fiat balance wallet return destination (v0.11-8). Rejected with 422 in
        v1 —

        holding a return as a fiat balance is planned for v0.12 (mirrors the

        `walletFiat` VA-destination rejection).
      title: Fiat wallet
    Hold:
      type: object
      oneOf:
        - $ref: '#/components/schemas/HoldSenderAttribution'
        - $ref: '#/components/schemas/HoldDepositAddressFrozen'
        - $ref: '#/components/schemas/HoldDepositAddressInactive'
      discriminator:
        propertyName: type
        mapping:
          senderAttribution: '#/components/schemas/HoldSenderAttribution'
          depositAddressFrozen: '#/components/schemas/HoldDepositAddressFrozen'
          depositAddressInactive: '#/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.
    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
    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:
          type: string
          description: Machine-readable reason the destination became invalid.
      description: >-
        Why a depositAddressInactive hold's destination external account went
        unusable.
    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.
        txHash:
          type: string
          description: The transaction hash of the unattributed inbound deposit.
        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
    InvalidCustomerIdErrorBody:
      type: object
      required:
        - error
      properties:
        error:
          type: string
          enum:
            - invalid customer id
          description: Human-readable error identifier.
    ListCashInsResponse:
      type: object
      required:
        - data
        - hasMore
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/CashIn'
          description: The page of results.
        hasMore:
          type: boolean
          description: Whether more results exist beyond this page.
        nextCursor:
          type: string
          description: Cursor for the next page; null when there are no more results.
      description: A paginated list of cash-ins.
    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).
    MatchableExternalAccountCriteria:
      type: object
      properties:
        type:
          type: string
          enum:
            - walletExternal
          description: Always `walletExternal` — the EA type that resolves the hold.
        customerId:
          allOf:
            - $ref: '#/components/schemas/typeId'
          description: The OMS customer that owns this record (`cst_` prefix).
        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.
    NetworkAsset:
      type: object
      required:
        - asset
      properties:
        asset:
          type: string
          description: 'Lowercase canonical asset code, e.g. `usdc`.'
        contractAddress:
          type: string
          nullable: true
          description: >-
            Token contract address. OMITTED — the JSON key is absent, not sent
            as an

            explicit `null` — for a native asset (BPN stores `token_id =
            'native'`

            for those) and for any asset with no on-chain identity row. `?: T |
            null`

            in TypeSpec compiles (oapi-codegen) to a Go `*string` tagged
            `omitempty`,

            so a nil pointer drops the key rather than emitting `null`; "key
            absent"

            and "explicit null" are treated as equivalent here on purpose, not
            by

            oversight — every consumer already does (the generated Zod schema

            accepts both via `.nullish()`), so there is no case that needs
            telling

            the two apart.
        decimals:
          type: integer
          format: int32
          nullable: true
          description: >-
            Count of decimal places in the on-chain smallest unit. OMITTED (key

            absent, not explicit `null`) — see `contractAddress` for why absent
            and

            null are equivalent here — when BPN has no on-chain identity row for

            this (asset, network): the scale is then genuinely unknown, not
            zero.

            A partner must not assume a default scale and must not format an
            amount

            in this asset while `decimals` is absent — the same "absent means

            unproven, not false" convention `supportedBy.wallet` uses for a

            capability instead of a scale.
      description: One asset available on a network.
    NetworkCategory:
      type: string
      enum:
        - crypto
        - fiatAccount
        - cash
      description: Which broad class of network this is.
    NetworkFamily:
      type: string
      enum:
        - evm
        - solana
      description: >-
        Crypto network family for a registered external wallet. A walletExternal
        is

        registered per family (an EVM address is valid across every EVM chain);
        the

        service provisions one Erebor CounterpartyBlockchainAddress per served

        network in the family.
    NetworkKind:
      type: string
      enum:
        - blockchain
        - bankRail
        - card
        - physical
      description: >-
        The transport a network uses. Named `NetworkKind` rather than
        `NetworkType`

        because `NetworkType` is already taken by the internal admin vocabulary

        (`chain | fiat_rail`) in admin.tsp — a different set with a different
        audience.
    NetworkListResponse:
      type: object
      required:
        - data
      properties:
        object:
          type: string
          enum:
            - list
        data:
          type: array
          items:
            $ref: '#/components/schemas/SupportedNetwork'
    OmsFeeEntry:
      type: object
      required:
        - type
      properties:
        type:
          type: string
          description: Type discriminator.
        rate:
          type: string
          description: Fee rate as a decimal.
        amount:
          type: string
          description: Amount as a decimal string.
      description: A single OMS fee line.
    OmsFeeSchedule:
      type: object
      required:
        - feeCurrency
        - entries
      properties:
        feeCurrency:
          type: string
          description: Currency the fee lines are denominated in.
        entries:
          type: array
          items:
            $ref: '#/components/schemas/OmsFeeEntry'
          description: Individual fee lines.
      description: 'The OMS fee lines applied, denominated in `feeCurrency`.'
    OwnerCounterparty:
      type: object
      required:
        - kind
        - counterpartyId
      properties:
        kind:
          type: string
          enum:
            - counterparty
          description: Owner kind discriminator.
        counterpartyId:
          allOf:
            - $ref: '#/components/schemas/typeId'
          description: Counterparty (ctp_…) id.
      description: Counterparty-owned External Account (an address-book entry).
      title: Counterparty-owned
    OwnerCustomer:
      type: object
      required:
        - kind
        - customerId
      properties:
        kind:
          type: string
          enum:
            - customer
          description: Owner kind discriminator.
        customerId:
          allOf:
            - $ref: '#/components/schemas/typeId'
          description: Owning customer (cus_… or legacy public id).
      description: Customer-owned External Account.
      title: Customer-owned
    OwnerType:
      type: string
      enum:
        - individual
        - business
    Party:
      type: object
      oneOf:
        - $ref: '#/components/schemas/PartyCustomer'
        - $ref: '#/components/schemas/PartyOtherCustomer'
        - $ref: '#/components/schemas/PartyExternalRegistered'
        - $ref: '#/components/schemas/PartyExternalUnregistered'
      discriminator:
        propertyName: relationship
        mapping:
          customer: '#/components/schemas/PartyCustomer'
          otherCustomer: '#/components/schemas/PartyOtherCustomer'
          externalRegistered: '#/components/schemas/PartyExternalRegistered'
          externalUnregistered: '#/components/schemas/PartyExternalUnregistered'
    PartyCustomer:
      type: object
      required:
        - relationship
        - customerId
      properties:
        relationship:
          type: string
          enum:
            - customer
          description: Relationship discriminator.
        entityType:
          $ref: '#/components/schemas/OwnerType'
        customerId:
          allOf:
            - $ref: '#/components/schemas/typeId'
          description: The OMS customer that owns this record (`cst_` prefix).
      description: The owning OMS customer is on this side.
      title: Customer
    PartyExternalRegistered:
      type: object
      required:
        - relationship
        - counterpartyId
      properties:
        relationship:
          type: string
          enum:
            - externalRegistered
          description: Relationship discriminator.
        entityType:
          $ref: '#/components/schemas/OwnerType'
        counterpartyId:
          allOf:
            - $ref: '#/components/schemas/typeId'
          description: Counterparty ID (`ctp_` prefix).
        name:
          type: string
          nullable: true
          description: Display name.
        address:
          type: object
          allOf:
            - $ref: '#/components/schemas/Address'
          nullable: true
          description: Postal address.
      description: A registered counterparty (saved third party) is on this side.
      title: Registered external account
    PartyExternalUnregistered:
      type: object
      required:
        - relationship
      properties:
        relationship:
          type: string
          enum:
            - externalUnregistered
          description: Relationship discriminator.
        name:
          type: string
          nullable: true
          description: Display name.
        address:
          type: object
          allOf:
            - $ref: '#/components/schemas/Address'
          nullable: true
          description: Postal address.
      description: >-
        An unrecognized external party (no saved record) is on this side. There
        is no

        OMS record behind it, so it carries no entityType.
      title: Unregistered external account
    PartyOtherCustomer:
      type: object
      required:
        - relationship
        - customerId
      properties:
        relationship:
          type: string
          enum:
            - otherCustomer
          description: Relationship discriminator.
        entityType:
          $ref: '#/components/schemas/OwnerType'
        customerId:
          allOf:
            - $ref: '#/components/schemas/typeId'
          description: The OMS customer that owns this record (`cst_` prefix).
        name:
          type: string
          nullable: true
          description: Display name.
      description: A different OMS customer is on this side.
      title: Another customer
    PayoutOrigin:
      type: object
      oneOf:
        - $ref: '#/components/schemas/PayoutOriginBank'
        - $ref: '#/components/schemas/PayoutOriginBlockchain'
      discriminator:
        propertyName: type
        mapping:
          bank: '#/components/schemas/PayoutOriginBank'
          blockchain: '#/components/schemas/PayoutOriginBlockchain'
      description: >-
        Where last-mile delivery is sent *from*. Tiered: Quote & Deposit

        Address echo the choice only; the Transaction carries full detail

        (`accountNumber`/`routingNumber`/`txHash`). At launch all payouts route
        through

        Erebor, so the field is forward-compatible but single-valued.
    PayoutOriginBank:
      type: object
      required:
        - type
        - details
      properties:
        type:
          type: string
          enum:
            - bank
          description: Type discriminator.
        details:
          $ref: '#/components/schemas/PayoutOriginBankDetails'
      description: >-
        Payout originates from a bank account. v0.10 wraps the fields in a
        `details`

        envelope (matches the `precursor` shape).
        `accountNumber`/`routingNumber` are

        full sending-account detail rendered on the Transaction only, null on

        Quote/Deposit Address (choice-only).
      title: Bank
    PayoutOriginBankDetails:
      type: object
      properties:
        accountHolder:
          $ref: '#/components/schemas/AccountHolder'
        accountHolderName:
          type: string
          description: Name of the sending account holder.
        accountNumber:
          type: string
          nullable: true
          description: Bank account number.
        routingNumber:
          type: string
          nullable: true
          description: US ABA routing number.
        virtualAccountId:
          type: string
          allOf:
            - $ref: '#/components/schemas/typeId'
          nullable: true
          description: Virtual Account ID (`va_` prefix).
      description: >-
        Bank payout-origin detail. `accountHolder`(+`Name`) is the chosen sender

        identity (echoed on Quote/DA too); `accountNumber`/`routingNumber` are
        the

        full sending-account coordinates (Transaction only, else null);
        `virtualAccountId`

        is the VA the funds were pulled from.
    PayoutOriginBlockchain:
      type: object
      required:
        - type
      properties:
        type:
          type: string
          enum:
            - blockchain
          description: Type discriminator.
        blockchainAddress:
          type: string
          description: On-chain address.
        network:
          type: string
          description: Network identifier.
        txHash:
          type: string
          description: On-chain transaction hash.
        custodian:
          type: string
          description: Custodian holding the funds.
      description: Payout originates from an on-chain address.
      title: Blockchain
    Precursor:
      type: object
      oneOf:
        - $ref: '#/components/schemas/PrecursorDepositAddress'
        - $ref: '#/components/schemas/PrecursorVirtualAccount'
        - $ref: '#/components/schemas/PrecursorCashIn'
        - $ref: '#/components/schemas/PrecursorQuote'
        - $ref: '#/components/schemas/PrecursorManual'
      discriminator:
        propertyName: type
        mapping:
          depositAddress: '#/components/schemas/PrecursorDepositAddress'
          virtualAccount: '#/components/schemas/PrecursorVirtualAccount'
          cashIn: '#/components/schemas/PrecursorCashIn'
          quote: '#/components/schemas/PrecursorQuote'
          manual: '#/components/schemas/PrecursorManual'
      description: >-
        What created this transaction, carrying that origin's deposit
        instructions.

        Additive over the legacy
        `depositAddressId`/`virtualAccountId`/`cashInId` +

        `depositInstructions` fields, which it loosely supersedes.
    PrecursorCashIn:
      type: object
      required:
        - type
        - details
      properties:
        type:
          type: string
          enum:
            - cashIn
          description: Type discriminator.
        details:
          $ref: '#/components/schemas/PrecursorCashInDetails'
      description: Created by a cash-in.
      title: Cash-in
    PrecursorCashInDetails:
      type: object
      required:
        - cashInId
      properties:
        cashInId:
          allOf:
            - $ref: '#/components/schemas/typeId'
          description: Cash-in ID (`ci_` prefix).
        depositInstructions:
          $ref: '#/components/schemas/CashInDepositInstructions'
        expiresAt:
          type: string
          format: date-time
          description: >-
            When the cash-in deposit code expires. Mirrors the originating
            cash-in's

            top-level expiresAt (#2144: the per-instruction expiresAt was
            removed).
      description: >-
        cashIn origin payload: the cash-in id + the retail deposit code +
        location.
    PrecursorDepositAddress:
      type: object
      required:
        - type
        - details
      properties:
        type:
          type: string
          enum:
            - depositAddress
          description: Type discriminator.
        details:
          $ref: '#/components/schemas/PrecursorDepositAddressDetails'
      description: Created by a deposit address.
      title: Deposit address
    PrecursorDepositAddressDetails:
      type: object
      required:
        - depositAddressId
      properties:
        depositAddressId:
          allOf:
            - $ref: '#/components/schemas/typeId'
          description: Deposit Address ID (`da_` prefix).
        depositInstructions:
          $ref: '#/components/schemas/DepositAddressDepositInstructions'
      description: >-
        depositAddress origin payload: the DA id + its on-chain inlet
        instructions.
    PrecursorManual:
      type: object
      required:
        - type
      properties:
        type:
          type: string
          enum:
            - manual
      description: >-
        Created outside the automated flows — origin not tracked
        (manual/ops-initiated).

        Carries no `details`: there is nothing origin-specific to report. Covers
        any

        transaction whose origin FKs
        (depositAddress/virtualAccount/cashIn/quote) are

        all unset, so `precursor` can be required without a legacy-row escape
        hatch.
      title: Manual
    PrecursorQuote:
      type: object
      required:
        - type
        - details
      properties:
        type:
          type: string
          enum:
            - quote
          description: Type discriminator.
        details:
          $ref: '#/components/schemas/PrecursorQuoteDetails'
      description: Created by accepting a quote.
      title: Quote
    PrecursorQuoteDetails:
      type: object
      required:
        - quoteId
      properties:
        quoteId:
          allOf:
            - $ref: '#/components/schemas/typeId'
          description: Quote ID (`qt_` prefix).
      description: 'quote origin payload: the quote id (no deposit instructions).'
    PrecursorVirtualAccount:
      type: object
      required:
        - type
        - details
      properties:
        type:
          type: string
          enum:
            - virtualAccount
          description: Type discriminator.
        details:
          $ref: '#/components/schemas/PrecursorVirtualAccountDetails'
      description: Created by a virtual account.
      title: Virtual account
    PrecursorVirtualAccountDetails:
      type: object
      required:
        - virtualAccountId
      properties:
        virtualAccountId:
          allOf:
            - $ref: '#/components/schemas/typeId'
          description: Virtual Account ID (`va_` prefix).
        depositInstructions:
          $ref: '#/components/schemas/VirtualAccountInstructions'
      description: 'virtualAccount origin payload: the VA id + its bank routing block(s).'
    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.
    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.
    ProviderErrorBody:
      type: object
      required:
        - error
        - code
      properties:
        error:
          type: string
          description: Human-readable error identifier.
        code:
          type: string
          enum:
            - providerError
          description: Machine-readable code.
    ProviderRejectionDetail:
      type: object
      properties:
        provider:
          type: string
          description: Vendor that rejected the request (e.g. `erebor`).
        code:
          type: string
          description: Vendor machine-readable error code (e.g. `INVALID_REQUEST`).
        message:
          type: string
          description: Vendor human-readable message.
        details:
          type: array
          items:
            type: string
          description: 'Per-field validation messages, each in `field: message` form.'
        providerRequestId:
          type: string
          description: 'Vendor request id, for support escalation.'
      description: >-
        Structured, partner-safe description of a terminal provider rejection.
        Populated alongside a `failed` status so the rejection reason is visible
        without support/log access. The same object is returned as the `details`
        field of the `422` error body when a create is terminally rejected by
        the provider.
    ProviderUnreachableErrorBody:
      type: object
      required:
        - error
        - code
      properties:
        error:
          type: string
          enum:
            - upstream provider unreachable
          description: Human-readable error identifier.
        code:
          type: string
          enum:
            - providerUnreachable
          description: Machine-readable code.
    ProviderUserAccountNotFoundErrorBody:
      type: object
      required:
        - error
        - code
      properties:
        error:
          type: string
          enum:
            - provider account not provisioned for this customer
          description: Human-readable error identifier.
        code:
          type: string
          enum:
            - providerUserAccountNotFound
          description: Machine-readable code.
    Quote:
      type: object
      required:
        - id
        - object
        - status
        - customerId
        - source
        - destination
        - pricing
      properties:
        id:
          allOf:
            - $ref: '#/components/schemas/typeId'
          description: Quote ID (`qt_` prefix).
        object:
          type: string
          enum:
            - quote
          description: Resource type discriminator. Always "quote".
        status:
          allOf:
            - $ref: '#/components/schemas/QuoteStatus'
          description: Current status of the quote.
        sourceToDestination:
          allOf:
            - $ref: '#/components/schemas/SourceToDestination'
          description: Corridor composite derived from the two sides.
        customerId:
          allOf:
            - $ref: '#/components/schemas/typeId'
          description: The OMS customer that owns this record (`cst_` prefix).
        source:
          allOf:
            - $ref: '#/components/schemas/TransactionSide'
          description: >-
            The funding side, echoed from the request with resolved instrument
            detail.
        destination:
          allOf:
            - $ref: '#/components/schemas/TransactionDestination'
          description: >-
            The receiving side, echoed from the request with resolved instrument
            detail.
        pricing:
          allOf:
            - $ref: '#/components/schemas/Pricing'
          description: Consolidated economics.
        expiresAt:
          type: string
          format: date-time
          description: When the locked pricing expires.
        createdAt:
          type: string
          format: date-time
          description: When the quote was created.
        metadata:
          type: object
          additionalProperties:
            type: string
          description: Free-form key-value pairs supplied at creation or update.
      description: >-
        A price quote for moving money between two instruments. It locks an
        exchange rate and the amounts for a short window; execute it by creating
        a transaction that references this quote's id.
      example:
        id: qt_0gq9aesz4wb5etdv88z1j61qcm
        object: quote
        status: open
        sourceToDestination: cryptoToFiatAccount
        customerId: cst_vfa0nxw6zvyws9g237jrxn4y7k
        source:
          party:
            relationship: customer
            customerId: cst_vfa0nxw6zvyws9g237jrxn4y7k
            entityType: individual
          type: walletOms
          category: crypto
          details:
            id: wlt_5h4jzzpr9xre3bamd9ca7qyghn
            asset: usdc
            network: polygon
            blockchainAddress: '0x7B3A9F2C4D1eA8bf6390cE5D2b7fA104c8e3D9B1'
            custodyType: custodial
        destination:
          party:
            relationship: externalRegistered
            counterpartyId: ctp_yp5z8m7n22svc0vh6edqgcfdat
            entityType: individual
            name: Alice Smith
            address:
              line1: 500 Market St
              city: San Francisco
              state: CA
              country: US
              zipCode: '94105'
          type: bankUs
          category: fiatAccount
          details:
            id: ext_fky491gakzj0dd46qb6whsr2vq
            asset: usd
            network: ach
            accountNumberLast4: '1234'
            routingNumber: '021000021'
            bankName: Chase
            accountType: checking
          payoutOrigin:
            type: bank
            details:
              accountHolder: customer
              accountHolderName: Jane Smith
        pricing:
          source:
            asset: usdc
            amountGross: '100.00'
            amountNet: '100.00'
            feesDeducted:
              total: '0.00'
              developer: '0.00'
              oms: '0.00'
              gas: '0.00'
          destination:
            asset: usd
            amountGross: '100.00'
            amountNet: '100.00'
            feesDeducted:
              total: '0.00'
              developer: '0.00'
              oms: '0.00'
              gas: '0.00'
          pair: usdc/usd
          exchangeRate: '1.0000'
          effectiveRate: '1.0000'
          fixedAmountSide: source
          sponsorGas: true
          sponsorGasCost: '0.00'
        expiresAt: '2026-03-14T19:15:00Z'
        createdAt: '2026-03-14T19:00:00Z'
    QuoteCreateRequest:
      type: object
      required:
        - customerId
        - source
        - destination
      properties:
        customerId:
          type: string
          description: The customer this quote is for (`cst_` prefix).
        source:
          allOf:
            - $ref: '#/components/schemas/QuoteSourceRequest'
          description: >-
            What funds the transaction. Pick a `type`: an OMS crypto wallet
            (`walletOms`)

            or a registered card (`card`, pull-from-card).
        destination:
          allOf:
            - $ref: '#/components/schemas/QuoteSideRequest'
          description: >-
            The instrument that receives the funds. Pick a `type`: a wallet
            (`walletOms` /

            `walletExternal`), a bank account (`bankUs` / `bankIban` /
            `bankCanada`), a `card`, or `cash`.
        sponsorGas:
          type: boolean
          description: >-
            When `true`, OMS absorbs the on-chain gas cost for the destination
            delivery. Only

            `true` is currently supported. Ignored for non-crypto destinations
            (no on-chain leg).
        settlementType:
          type: string
          enum:
            - internal
            - external
          description: >-
            Card rail only: INTERNAL (Coinme custodies the crypto) or EXTERNAL
            (on-chain

            wallet). Defaults: card buy -> external, card sell -> internal.
            Ignored for

            non-card rails.
        metadata:
          type: object
          additionalProperties:
            type: string
          description: >-
            Free-form key-value pairs stored on the quote and copied to the
            resulting transaction.
      description: >-
        Request body for creating a quote. Pick a `type` on each side and set
        the

        amount on exactly one side; OMS calculates the other.
      example:
        customerId: cst_vfa0nxw6zvyws9g237jrxn4y7k
        source:
          type: walletOms
          details:
            id: wlt_5h4jzzpr9xre3bamd9ca7qyghn
            asset: usdc
            network: polygon
          amount: '100.00'
        destination:
          type: bankUs
          details:
            id: ext_fky491gakzj0dd46qb6whsr2vq
            asset: usd
            network: ach
            accountHolder: customer
        sponsorGas: true
        metadata:
          orderId: order_12345
    QuoteSideRequest:
      type: object
      oneOf:
        - $ref: '#/components/schemas/WalletOmsSideRequest'
        - $ref: '#/components/schemas/WalletExternalSideRequest'
        - $ref: '#/components/schemas/BankUsSideRequest'
        - $ref: '#/components/schemas/BankIbanSideRequest'
        - $ref: '#/components/schemas/BankCanadaSideRequest'
        - $ref: '#/components/schemas/CardSideRequest'
        - $ref: '#/components/schemas/CashSideRequest'
      discriminator:
        propertyName: type
        mapping:
          walletOms: '#/components/schemas/WalletOmsSideRequest'
          walletExternal: '#/components/schemas/WalletExternalSideRequest'
          bankUs: '#/components/schemas/BankUsSideRequest'
          bankIban: '#/components/schemas/BankIbanSideRequest'
          bankCanada: '#/components/schemas/BankCanadaSideRequest'
          card: '#/components/schemas/CardSideRequest'
          cash: '#/components/schemas/CashSideRequest'
      description: >-
        The instrument that receives the funds: a wallet (`walletOms` /

        `walletExternal`), a bank account (`bankUs` / `bankIban` /
        `bankCanada`), a

        `card`, or `cash`.
    QuoteSourceRequest:
      type: object
      oneOf:
        - $ref: '#/components/schemas/WalletOmsSideRequest'
        - $ref: '#/components/schemas/WalletFiatSideRequest'
        - $ref: '#/components/schemas/CardSideRequest'
      discriminator:
        propertyName: type
        mapping:
          walletOms: '#/components/schemas/WalletOmsSideRequest'
          walletFiat: '#/components/schemas/WalletFiatSideRequest'
          card: '#/components/schemas/CardSideRequest'
      description: >-
        What funds a quote: an OMS Multi-Chain Wallet (`walletOms`), a fiat
        balance

        wallet (`walletFiat`), or a registered card (`card`, pull-from-card).
        `card`

        requires `asset: usd`.
    QuoteStatus:
      type: string
      enum:
        - open
        - accepted
        - expired
      description: >-
        Status of a quote. open: pricing locked, awaiting acceptance. accepted:
        a transaction has been created from it. expired: the pricing window
        elapsed.
    Rates:
      type: object
      required:
        - pair
        - exchangeRate
        - effectiveRate
      properties:
        pair:
          type: string
          description: 'Asset pair string, e.g. "usdc/usd".'
        exchangeRate:
          type: string
          description: Units of destination asset per 1 unit of source asset.
        effectiveRate:
          type: string
          description: All-in rate inclusive of all fees on both sides.
      description: Exchange and effective rates.
    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.
    RefreshRateLimitedDetails:
      type: object
      properties:
        maxRefreshes:
          type: integer
          format: int32
          description: >-
            Set for `refreshLimitReached`: the maximum number of refreshes
            permitted

            for a single cash-in.
        retryAfterSeconds:
          type: integer
          format: int32
          description: >-
            Set for `refreshTooFrequent`: how long (seconds) to wait before
            retrying,

            mirroring the `Retry-After` header.
      description: |-
        Machine-readable context for a refresh 429 (#2402). Exactly one field is
        populated, per the `code`.
    RefreshRateLimitedErrorBody:
      type: object
      required:
        - error
        - code
        - details
      properties:
        error:
          type: string
        code:
          type: string
          enum:
            - refreshLimitReached
            - refreshTooFrequent
        details:
          $ref: '#/components/schemas/RefreshRateLimitedDetails'
      description: >-
        Body of the 429 returned by the per-cash-in refresh guard (#2402).
        `code`

        discriminates the two breaches: `refreshLimitReached` (the per-cash-in
        cap of

        total refreshes has been hit — permanent for this cash-in, create a new
        one)

        and `refreshTooFrequent` (the minimum interval between refreshes has not
        yet

        elapsed — retry after the window). Both are DISTINCT from the generic
        project

        rate limit (`rateLimited`).
    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`.
    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.
    SimulateCashInCancelRequest:
      type: object
      required:
        - cashInCode
        - amount
        - originalConfirmationId
      properties:
        cashInCode:
          type: string
        amount:
          $ref: '#/components/schemas/decimalString'
        originalConfirmationId:
          type: string
          description: The `confirmationId` returned by `present-code`.
    SimulateCashInCancelResponse:
      type: object
      required:
        - responseCode
        - responseText
        - responseId
      properties:
        responseCode:
          type: string
        responseText:
          type: string
        responseId:
          type: string
    SimulateCashInDepositCashRequest:
      type: object
      required:
        - cashInCode
        - amount
        - originalConfirmationId
      properties:
        cashInCode:
          type: string
        amount:
          $ref: '#/components/schemas/decimalString'
        originalConfirmationId:
          type: string
          description: The `confirmationId` returned by `present-code`.
    SimulateCashInDepositCashResponse:
      type: object
      required:
        - responseCode
        - responseText
        - responseId
        - confirmationId
        - authorizedAmount
      properties:
        responseCode:
          type: string
        responseText:
          type: string
        responseId:
          type: string
        confirmationId:
          type: string
          description: Confirmation of the completed deposit.
        authorizedAmount:
          allOf:
            - $ref: '#/components/schemas/decimalString'
          description: Amount deposited.
    SimulateCashInPresentCodeRequest:
      type: object
      required:
        - cashInCode
        - amount
      properties:
        cashInCode:
          type: string
          description: >-
            The cash-in's `depositInstructions.code` — what the customer
            presents at the register.
        amount:
          $ref: '#/components/schemas/decimalString'
    SimulateCashInPresentCodeResponse:
      type: object
      required:
        - responseCode
        - responseText
        - responseId
        - confirmationId
        - authorizedAmount
        - balance
      properties:
        responseCode:
          type: string
        responseText:
          type: string
        responseId:
          type: string
        confirmationId:
          type: string
          description: >-
            Authorization confirmation — pass as `originalConfirmationId` to
            `deposit-cash` or `cancel`.
        authorizedAmount:
          allOf:
            - $ref: '#/components/schemas/decimalString'
          description: Amount the provider authorized.
        balance:
          allOf:
            - $ref: '#/components/schemas/decimalString'
          description: >-
            Provider-reported running balance for this cash-in code after the
            authorization.
    SimulateVaBankIbanInboundRequest:
      type: object
      required:
        - type
        - network
        - asset
        - amount
      properties:
        type:
          type: string
          enum:
            - bankIban
          description: Rail discriminator. Always `bankIban` for an international inbound.
        network:
          type: string
          enum:
            - swift
          description: Always "swift" for the international rail.
        asset:
          type: string
          enum:
            - usd
          description: 'Always "usd", the only asset the VA rail supports today.'
        amount:
          allOf:
            - $ref: '#/components/schemas/decimalString'
          description: >-
            Must be greater than 0.00 and at most 1000.00 (400
            `amountExceedsCap` beyond).
      description: International (SWIFT) inbound simulation against a Virtual Account.
      title: International bank account (SWIFT)
    SimulateVaBankUsInboundRequest:
      type: object
      required:
        - type
        - network
        - asset
        - amount
      properties:
        type:
          type: string
          enum:
            - bankUs
          description: Rail discriminator. Always `bankUs` for a US domestic inbound.
        network:
          allOf:
            - $ref: '#/components/schemas/SimulateVaBankUsNetwork'
          description: Which US rail to simulate.
        asset:
          type: string
          enum:
            - usd
          description: 'Always "usd", the only asset the VA rail supports today.'
        amount:
          allOf:
            - $ref: '#/components/schemas/decimalString'
          description: >-
            Must be greater than 0.00 and at most 1000.00 (400
            `amountExceedsCap` beyond).
      description: US domestic (ACH or Wire) inbound simulation against a Virtual Account.
      title: US bank account (ACH or Wire)
    SimulateVaBankUsNetwork:
      type: string
      enum:
        - ach
        - wire
      description: Network for a `bankUs` (US domestic) inbound simulation.
    SimulateVaInboundTransferNetwork:
      type: string
      enum:
        - ach
        - wire
        - swift
      description: Network actually used — the union of both request rails' networks.
    SimulateVaInboundTransferRequest:
      type: object
      oneOf:
        - $ref: '#/components/schemas/SimulateVaBankUsInboundRequest'
        - $ref: '#/components/schemas/SimulateVaBankIbanInboundRequest'
      discriminator:
        propertyName: type
        mapping:
          bankUs: '#/components/schemas/SimulateVaBankUsInboundRequest'
          bankIban: '#/components/schemas/SimulateVaBankIbanInboundRequest'
      description: |-
        Type-discriminated request for
        POST /virtual-accounts/{id}/simulate/inbound-transfer.
    SimulateVaInboundTransferResponse:
      type: object
      required:
        - virtualAccountId
        - type
        - network
        - asset
        - amount
        - status
        - submittedAt
        - referenceId
      properties:
        virtualAccountId:
          allOf:
            - $ref: '#/components/schemas/typeId'
          description: >-
            The Virtual Account that received the simulated transfer (`va_`
            prefix).
        type:
          allOf:
            - $ref: '#/components/schemas/SimulateVaInboundTransferType'
          description: Echoes the request's rail discriminator.
        network:
          allOf:
            - $ref: '#/components/schemas/SimulateVaInboundTransferNetwork'
          description: The rail the transfer settled on.
        asset:
          type: string
          enum:
            - usd
          description: Always "usd".
        amount:
          allOf:
            - $ref: '#/components/schemas/decimalString'
          description: The simulated transfer amount.
        status:
          type: string
          enum:
            - submitted
            - pending
          description: >-
            "submitted" for ach/wire (settles synchronously); "pending" for
            swift —

            the upstream provider settles SWIFT asynchronously.
        submittedAt:
          type: string
          format: date-time
          description: When the simulated transfer was submitted.
        referenceId:
          type: string
          nullable: true
          description: |-
            Correlation id for the subsequent webhook. `null` for ach/wire;
            an `intl_wire_in_…` id for swift.
      description: |-
        Flat (non-discriminated) response for
        POST /virtual-accounts/{id}/simulate/inbound-transfer.
    SimulateVaInboundTransferType:
      type: string
      enum:
        - bankUs
        - bankIban
      description: Echoes the request's `type` discriminator on the response.
    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.
    SupportedBy:
      type: object
      properties:
        externalAccount:
          type: object
          properties:
            asSource:
              type: array
              items:
                type: string
            asDestination:
              type: array
              items:
                type: string
          required:
            - asSource
            - asDestination
          description: |-
            External-account types usable on this network, per direction — e.g.
            `["walletExternal"]` on a chain, `["bankUs"]` on `ach`.
        depositAddress:
          $ref: '#/components/schemas/DirectionalFlag'
        virtualAccount:
          $ref: '#/components/schemas/DirectionalFlag'
        cashIn:
          $ref: '#/components/schemas/DirectionalFlag'
        wallet:
          allOf:
            - $ref: '#/components/schemas/DirectionalFlag'
          description: >-
            Whether an OMS-custodied wallet can hold value on this network and
            use it

            as a source or destination.


            ABSENT means unproven, not false. OMS wallet custody is an enforced

            two-vendor allow-list (`services/depositaddress/helpers.go` —

            `WalletRecord.VendorID` must be the multi-asset Erebor-embedded
            wallet, and

            a Coinme-custodial wallet fails closed). Erebor's served networks
            are

            therefore provable and are populated here. Coinme has no equivalent

            capability authority — `canonicalChains` is a name-normalisation
            set, not a

            support list, and it contains `bitcoin` — so `polygon`, the one

            Coinme-only network, omits this property until #2763 establishes
            Coinme's

            matrix. That will be a data change, not a contract change.
      description: >-
        Which OMS resources can use this network, and in which direction.


        Every property is optional, and absence is meaningful: it means BPN has
        not

        established the answer, NOT that the answer is no. A client must not
        treat a

        missing property as `false`. `wallet` is the field this applies to in

        practice — see its own docstring.


        Two spec fields are deliberately absent from the whole response rather
        than

        null, because their values are not BPN's to invent:

        `assets[].gasSponsorshipSupported` (today's `sponsor_gas` columns are

        per-request defaults, not a statement of what BPN can absorb) and

        `assets[].limits` (BPN's existing `transfer_limits` subsystem is
        rail-scoped

        USD, a different key and denomination — two overlapping limit surfaces
        would

        invite "which one wins" bugs). Both are additive later. See #2754.
    SupportedDestination:
      type: object
      required:
        - asset
        - network
      properties:
        asset:
          type: string
          description: 'Stablecoin symbol, e.g. `usdc` / `usdt`.'
        network:
          allOf:
            - $ref: '#/components/schemas/CryptoNetwork'
          description: >-
            Network the asset can be delivered on, e.g. `ethereum` / `base` /
            `solana`.
      description: >-
        An (asset, network) pair a walletExternal external account can receive —
        one

        entry per supported stablecoin on each network its family serves.
    SupportedNetwork:
      type: object
      required:
        - network
        - category
        - type
        - displayName
        - assets
        - supportedBy
      properties:
        network:
          type: string
          description: >-
            Partner-facing network token — the value to send in a request
            `network`

            field. Internal route-config codes are mapped here at the boundary

            (`international_wire` is emitted as `swift`), so this is never a

            snake_case internal token. `achSameDay` and `local` are also

            contract-legal request values with no distinct entry here: routes
            are

            validated against the coarser `ach` / `swift` rail respectively, so

            `achSameDay` availability is reported under `ach` and `local` under

            `swift` rather than as their own network.
        category:
          $ref: '#/components/schemas/NetworkCategory'
        type:
          $ref: '#/components/schemas/NetworkKind'
        chainId:
          type: integer
          format: int64
          nullable: true
          description: >-
            EVM chain id. OMITTED (key absent, not explicit `null`) for a
            non-EVM

            network — see `contractAddress` for why absent and null are
            equivalent

            here. BPN stores `chain_id` as non-empty text for every row
            including

            Solana, whose value is a base58 genesis hash — anything that does
            not

            parse as an integer omits the key.


            Declared `int64`, not `safeint`, despite `safeint` — "an integer

            exactly representable in JS" — being the semantically correct scalar

            for a value this small (every real chain id fits well under 2^53;

            Aurora's 1313161554 is the largest in practice, and `int32` is
            already

            too small for it). Tried as the fix for comment 3732256949 (the

            generated Zod schema coerces to `bigint` while the generated TS type
            is

            `number`, so parsing a response can silently hand a caller a
            `bigint`

            where the exported type promised `number`) and reverted: the

            `@typespec/openapi3` emitter's default `safeint` strategy still
            emits

            `format: int64` in the OpenAPI schema — identical to plain `int64` —

            and hey-api's Zod generator decides bigint-coercion purely from that

            `format` string (`shouldCoerceToBigInt`), so the scalar swap changes

            nothing generated. Fixing this for real needs the emitter's

            `safeint-strategy: double-int` option, which is a schema-wide (not

            per-field) setting untested against every other `int64`/`safeint`
            use

            in this spec — out of scope for a one-field fix. Tracked as a known

            generator quirk rather than half-fixed here.
        networkFamily:
          allOf:
            - $ref: '#/components/schemas/NetworkFamily'
          nullable: true
          description: >-
            OMITTED (key absent, not explicit `null`) for non-blockchain
            networks —

            see `contractAddress` for why absent and null are equivalent here.
        displayName:
          type: string
          description: 'Human-readable label, e.g. "Polygon PoS".'
        assets:
          type: array
          items:
            $ref: '#/components/schemas/NetworkAsset'
        supportedBy:
          $ref: '#/components/schemas/SupportedBy'
      description: >-
        A network BPN supports, with its identifiers, assets, and capability
        map.
    Transaction:
      type: object
      required:
        - id
        - object
        - status
        - 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`). Absent when
            the transaction

            has no meaningful sub-state.
        customerId:
          allOf:
            - $ref: '#/components/schemas/typeId'
          description: The owning (sender) customer. OMSX customer TypeID (cst_…).
        precursor:
          allOf:
            - $ref: '#/components/schemas/Precursor'
          description: >-
            What created this transaction, carrying that origin's deposit
            instructions.

            Always present: the `manual` arm covers any transaction with no

            automated origin.
        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.
    TransactionCreateRequest:
      type: object
      required:
        - quoteId
      properties:
        quoteId:
          type: string
          description: >-
            The quote to accept (`qt_` prefix). Must be `open` with non-expired
            pricing.
        deviceFingerprint:
          type: string
          description: 'Device fingerprint of the end user, used for risk screening.'
        externalAccountId:
          type: string
          description: >-
            The BPN external-account id of the debit card funding (buy) or
            receiving

            (sell) this transaction. BPN resolves it to the Coinme
            paymentMethodId.
        paymentMethodId:
          type: string
          description: |-
            Deprecated for cards: raw Coinme paymentMethodId passthrough. Use
            externalAccountId instead.
        partnerTransactionId:
          type: integer
          format: int32
          description: 'Your own transaction reference, for reconciliation.'
        externalCustodyCreditInfo:
          allOf:
            - $ref: '#/components/schemas/ExternalCustodyCreditInfo'
          description: 'External custody credit details, required for EXTERNAL settlement.'
        sourceWalletAddress:
          type: string
          description: Expected sending address for crypto-funded transactions.
        tags:
          type: string
          description: Free-form labels attached to the transaction.
        webSessionId:
          type: string
          description: Risk/session identifier from the client SDK.
        metadata:
          type: object
          additionalProperties:
            type: string
          description: >-
            Free-form key-value pairs stored on the resource and echoed back on
            reads.
      description: >-
        Request body for executing a transaction. References the quote to
        accept; the remaining fields are optional routing hints and metadata.
      example:
        quoteId: qt_0gq9aesz4wb5etdv88z1j61qcm
        metadata:
          orderId: order_12345
    TransactionDestination:
      type: object
      oneOf:
        - $ref: '#/components/schemas/WalletOmsDestination'
        - $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:
          walletOms: '#/components/schemas/WalletOmsDestination'
          walletExternal: '#/components/schemas/WalletExternalDestination'
          walletFiat: '#/components/schemas/WalletFiatDestination'
          bankUs: '#/components/schemas/BankUsDestination'
          bankIban: '#/components/schemas/BankIbanDestination'
          bankCanada: '#/components/schemas/BankCanadaDestination'
          card: '#/components/schemas/CardDestination'
          cash: '#/components/schemas/CashDestination'
      description: >-
        The destination side of a transaction/quote (v0.10): a typed instrument
        plus

        `payoutOrigin`. Amounts live only in `pricing`.
    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.
    TransactionPrecursorType:
      type: string
      enum:
        - quote
        - depositAddress
        - virtualAccount
        - cashIn
      description: |-
        The kind of precursor resource that originated a transaction. `reversal`
        is deliberately absent until reversal automation lands (#2141).
    TransactionSide:
      type: object
      oneOf:
        - $ref: '#/components/schemas/WalletOmsInstrument'
        - $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:
          walletOms: '#/components/schemas/WalletOmsInstrument'
          walletExternal: '#/components/schemas/WalletExternalInstrument'
          walletFiat: '#/components/schemas/WalletFiatInstrument'
          bankUs: '#/components/schemas/BankUsInstrument'
          bankIban: '#/components/schemas/BankIbanInstrument'
          bankCanada: '#/components/schemas/BankCanadaInstrument'
          card: '#/components/schemas/CardInstrument'
          cash: '#/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`.
    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.
    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
      description: >-
        Finer-grained, status-scoped sub-state of a transaction (v0.10). Each
        member is

        namespaced by its parent `status` (e.g. `processing.cashPickupReady`).
        Largely a

        closed set aligned to the v0.11 spec; 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. Absent when there is
        no meaningful

        sub-state.


        (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.
    TransactionType:
      type: string
      enum:
        - credit
        - debit
        - hold
        - release
      description: 'Type of account ledger entry: a credit, debit, hold, or release.'
    TransferType:
      type: string
      enum:
        - cryptoToCrypto
        - fiatToCrypto
        - cryptoToFiat
      description: >-
        Direction of value across rails: cryptoToCrypto, fiatToCrypto, or
        cryptoToFiat.

        Retained for resources not yet on the `SourceToDestination` shape

        (onramp/cash-in, customer filters).
    UnauthorizedErrorBody:
      type: object
      required:
        - error
      properties:
        error:
          type: string
          enum:
            - unauthorized
          description: Human-readable error identifier.
    VirtualAccount:
      type: object
      properties:
        id:
          allOf:
            - $ref: '#/components/schemas/typeId'
          description: Virtual Account ID (`va_` prefix).
        object:
          type: string
          enum:
            - virtualAccount
          description: Resource type discriminator. Always "virtualAccount".
        customerId:
          allOf:
            - $ref: '#/components/schemas/typeId'
          description: The OMS customer that owns this record (`cst_` prefix).
        status:
          allOf:
            - $ref: '#/components/schemas/VirtualAccountStatus'
          description: Current lifecycle status of the virtual account.
        sourceToDestination:
          allOf:
            - $ref: '#/components/schemas/SourceToDestination'
          description: >-
            Corridor composite derived from the destination type —
            `fiatAccountToCrypto`

            for a crypto-wallet destination (inbound fiat auto-converts), or

            `fiatAccountToFiatAccount` for a bank destination (inbound USD
            forwarded

            onward).
        statusReason:
          type: string
          description: Human-readable explanation of the current status.
        source:
          allOf:
            - $ref: '#/components/schemas/VirtualAccountSource'
          description: Expected inbound rail detail.
        depositInstructions:
          allOf:
            - $ref: '#/components/schemas/VirtualAccountInstructions'
          description: Null until Erebor provisions the DDA (DEPOSIT_ACCOUNT.OPEN).
        destination:
          allOf:
            - $ref: '#/components/schemas/TransactionSide'
          description: 'V0.10: unified side shape.'
        returnDestination:
          allOf:
            - $ref: '#/components/schemas/FiatReturnDestination'
          description: >-
            The configured fiat return destination (v0.11-8) for failed outbound

            legs; absent/null when none is set (the project return policy
            applies

            instead, once T13 wires the waterfall).
        sponsorGas:
          type: boolean
          description: >-
            Whether OMS absorbs the on-chain gas cost for the destination
            delivery.

            Persisted from the create/update request (currently only `true` is

            accepted).
        bankMemo:
          type: string
          description: Wire/ACH memo the customer can include with deposits.
        label:
          type: string
          description: Partner display label.
        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 virtual account was created.
        updatedAt:
          type: string
          format: date-time
          description: When the virtual account was last updated.
        failureReason:
          allOf:
            - $ref: '#/components/schemas/VirtualAccountFailureReason'
          description: >-
            Set when status = `failed`; closed enum identifying the failure
            category.
        deletionRequestedAt:
          type: string
          format: date-time
          description: >-
            Set when DELETE has been requested but the close webhook has not yet
            finalized.
        deletionRequestedBy:
          type: string
          description: Identity (JWT subject claim) of the caller who invoked DELETE.
        finalBalance:
          allOf:
            - $ref: '#/components/schemas/AmountObject'
          description: DDA balance snapshot at the moment the VA flipped to `deleted`.
      description: >-
        A dedicated bank account number issued for a customer. Inbound fiat
        deposits are

        automatically converted and delivered to the configured destination,
        creating a

        transaction per deposit.
    VirtualAccountCloseUnavailableErrorBody:
      type: object
      required:
        - error
        - code
      properties:
        error:
          type: string
          enum:
            - Account closure is not yet available at the provider; retry later.
          description: >-
            Human-readable error identifier. Stable string — partners branch on
            it.
        code:
          type: string
          enum:
            - virtualAccountCloseUnavailable
          description: Machine-readable code.
      description: >-
        Body of the 503 returned when Erebor's account-close primitive itself is

        not yet enabled for this DDA — not a rejection of this particular delete

        request. The VA is not deleted and remains active/deletable — no

        delete-pending marker persists — so the partner can safely retry once
        the

        primitive is available upstream. Retires the misleading `502` framing
        from

        bug #1653.
    VirtualAccountCreateRequest:
      type: object
      required:
        - customerId
        - source
        - destination
        - accountHolder
        - type
      properties:
        customerId:
          type: string
          description: Owning customer (cus_… or legacy public id).
        source:
          allOf:
            - $ref: '#/components/schemas/VirtualAccountSource'
          description: Expected inbound bank rail.
        destination:
          allOf:
            - $ref: '#/components/schemas/VirtualAccountDestinationRequest'
          description: >-
            V0.10 side-shaped destination: walletExternal (registered
            ExternalAccount)

            or a bank arm. walletOms is NOT currently supported — 422

            destinationWalletOmsNotSupported; use walletExternal. The server
            validates

            asset/network against the resolved EA.
        returnDestination:
          allOf:
            - $ref: '#/components/schemas/FiatReturnDestination'
          description: >-
            Optional fiat return destination (v0.11-8): where inbound fiat is
            sent if

            the outbound leg can't be completed. Bank arms only in v1 — `bankUs`
            /

            `bankIban` / `bankCanada` (network `swift`, USD); `walletFiat` and

            `bankCanada` with network `local` (CAD) are rejected with 422

            `railNotSupported`.
        accountHolder:
          type: string
          description: >-
            Closed for Alpha: must be "customer" (additive later — bankMexico /
            more

            accountHolders land within 6-12 months).
        type:
          type: string
          description: 'Closed for Alpha: must be "bankUs".'
        sponsorGas:
          type: boolean
          description: |-
            When `true`, OMS absorbs the on-chain gas cost for the destination
            delivery. Only `true` is currently supported.
          default: true
        bankMemo:
          type: string
          description: Optional wire/ACH memo the customer can include.
        label:
          type: string
          description: Partner display label.
        metadata:
          type: object
          additionalProperties:
            type: string
          description: >-
            Free-form key-value pairs stored on the resource and echoed back on
            reads.
      description: >-
        Create a Virtual Account: the inbound bank rail plus the destination
        that receives the

        converted funds.
      example:
        customerId: cst_vfa0nxw6zvyws9g237jrxn4y7k
        type: bankUs
        accountHolder: customer
        source:
          asset: usd
          network: ach
        destination:
          type: walletExternal
          details:
            id: ext_fky491gakzj0dd46qb6whsr2vq
            asset: usdc
            network: ethereum
        sponsorGas: true
        label: Alice USD deposit account
    VirtualAccountDestinationRequest:
      type: object
      oneOf:
        - $ref: '#/components/schemas/BankUsSideRequest'
        - $ref: '#/components/schemas/BankIbanSideRequest'
        - $ref: '#/components/schemas/BankCanadaSideRequest'
        - $ref: '#/components/schemas/WalletOmsSideRequest'
        - $ref: '#/components/schemas/WalletExternalRegisteredSideRequest'
      discriminator:
        propertyName: type
        mapping:
          bankUs: '#/components/schemas/BankUsSideRequest'
          bankIban: '#/components/schemas/BankIbanSideRequest'
          bankCanada: '#/components/schemas/BankCanadaSideRequest'
          walletOms: '#/components/schemas/WalletOmsSideRequest'
          walletExternal: '#/components/schemas/WalletExternalRegisteredSideRequest'
      description: >-
        Where the Virtual Account delivers the deposited value, on the shared

        discriminated side shape (same shapes as Deposit Addresses).


        Crypto arms auto-convert the inbound fiat to crypto
        (`fiatAccountToCrypto`):

        `walletExternal` delivers to a registered External Account (ext_ id).
        Unlike

        Cash-In, Virtual Accounts require the external wallet to be registered —
        raw

        unregistered addresses are not allowed. `walletOms` is declared but NOT

        currently supported: it is rejected with 422

        `destinationWalletOmsNotSupported` — use `walletExternal` for
        externally-held

        wallets. (Planned to return for non-custodial wallets in v0.12.)


        Bank arms (`bankUs` / `bankIban` / `bankCanada`) auto-forward the
        inbound USD

        onward to a registered bank-type External Account
        (`fiatAccountToFiatAccount`).

        The `network` enums are carried verbatim from the shared Side models
        (bankUs:

        ach|achSameDay|wire; bankIban: swift; bankCanada: swift|local); the 422

        filtering of CAD / `local` is applied service-side, not by this
        contract.


        The reused side arms carry an optional `amount`, which is meaningless
        for a

        standing destination — the deposited value determines what is delivered
        — and

        is rejected at validation. The server validates the side `details`

        (asset/network/accountHolder) against the resolved EA/wallet.


        A `walletFiat` destination (holding the inbound USD as a fiat balance)
        is

        deliberately not an arm of this union: it is rejected with 422

        `railNotSupported` and is planned for v0.12.
    VirtualAccountFailureReason:
      type: string
      enum:
        - provisioningTimeout
        - systemError
        - ereborRejected
        - deletePendingTimeout
      description: >-
        Closed enum stamped by failVA when a VA flips to terminal `failed`
        state.
    VirtualAccountInstructions:
      type: object
      properties:
        bankUs:
          type: array
          items:
            $ref: '#/components/schemas/BankRoutingBlock'
      description: >-
        Spec-mandated (v0.11/v0.11) VA deposit-instructions wrapper. bankUs
        holds

        zero, one, or two routing blocks (domestic + SWIFT), depending on which

        incoming rails the partner has enabled.
    VirtualAccountList:
      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/VirtualAccount'
          description: The page of results.
      description: Paginated list of VirtualAccount resources.
    VirtualAccountSource:
      type: object
      required:
        - asset
        - network
      properties:
        asset:
          type: string
          description: 'Fixed for Alpha: "usd".'
        network:
          type: string
          description: 'Fixed for Alpha: "usBank".'
      description: >-
        Expected inbound rail for the virtual account: fiat asset and bank
        network.
    VirtualAccountStatus:
      type: string
      enum:
        - pending
        - active
        - frozen
        - closed
        - deleted
        - failed
        - inactiveActionRequired
      description: >-
        Lifecycle of a Virtual Account. pending: awaiting bank provisioning.
        active: accepting

        deposits. frozen: deposits held by compliance. inactiveActionRequired:
        destination unusable -

        re-point `destination` to recover. closed: permanently disabled.
        deleted: close flow finalized.

        failed: provisioning failed.
    VirtualAccountUpdateRequest:
      type: object
      properties:
        destination:
          allOf:
            - $ref: '#/components/schemas/VirtualAccountDestinationRequest'
          description: >-
            Re-point the VA destination (walletExternal by registered EA id, or
            a bank

            EA — same kind as the current destination). Re-validated exactly
            like

            create; walletOms is NOT currently supported — 422

            destinationWalletOmsNotSupported.
        returnDestination:
          allOf:
            - $ref: '#/components/schemas/FiatReturnDestination'
          description: >-
            Re-point or clear the fiat return destination (v0.11-8).
            Re-validated

            exactly like create; an explicit `null` in the JSON body clears a

            previously set return destination.
        sponsorGas:
          type: boolean
          description: |-
            When `true`, OMS absorbs the on-chain gas cost for the destination
            delivery. Only `true` is currently supported; accepted for
            forward-compatibility.
          default: true
        label:
          type: string
          description: Partner display label.
        metadata:
          type: object
          additionalProperties:
            type: string
          description: >-
            Free-form key-value pairs stored on the resource and echoed back on
            reads.
      description: >-
        Partial update payload for a Virtual Account. The patchable fields are

        `destination` (re-point to a different walletExternal or bank target),

        `returnDestination` (re-point or clear the fiat return destination),

        `sponsorGas`, `label`, and `metadata`. Any additional key in the JSON
        body

        is rejected with 400 by the handler (strict whitelist).


        Re-pointing `destination` to a healthy External Account recovers a VA
        from

        `inactiveActionRequired` back to `active`; a re-point on an already

        `active` VA updates the target without a status transition.
    BpnWallet:
      type: object
      properties:
        id:
          allOf:
            - $ref: '#/components/schemas/typeId'
          description: Wallet ID.
        object:
          type: string
          enum:
            - wallet
          description: Resource type discriminator. Always "wallet".
        customerId:
          allOf:
            - $ref: '#/components/schemas/typeId'
          description: The OMS customer that owns this record (`cst_` prefix).
        type:
          allOf:
            - $ref: '#/components/schemas/WalletType'
          description: '`internal` (OMS-managed) or `external` (held outside OMS).'
        asset:
          type: string
          description: Asset held by this wallet.
        chain:
          type: string
          description: Chain the wallet lives on.
        blockchainAsset:
          allOf:
            - $ref: '#/components/schemas/BlockchainAsset'
          description: Resolved asset/network detail for the wallet's asset.
        address:
          type: string
          description: On-chain address of the wallet.
        status:
          allOf:
            - $ref: '#/components/schemas/WalletStatus'
          description: Current lifecycle status of the wallet.
        createdAt:
          type: string
          format: date-time
          description: When the wallet was created.
        updatedAt:
          type: string
          format: date-time
          description: When the wallet was last updated.
      description: >-
        A wallet holding a single asset on one chain for a customer. internal
        wallets are OMS-managed; external wallets are held outside OMS.
    WalletBalance:
      type: object
      properties:
        data:
          type: object
          properties:
            id:
              allOf:
                - $ref: '#/components/schemas/typeId'
              description: >-
                Public wallet ID, format `wlt_<typeID>` (legacy `acc_` also
                accepted on input).
            customerId:
              allOf:
                - $ref: '#/components/schemas/typeId'
              description: 'Public OMS customer ID, format `cst_<typeID>`.'
            asset:
              type: string
              description: Canonical asset symbol (e.g. "usdc").
            chain:
              type: string
              description: Canonical chain name (e.g. "polygon").
            blockchainAsset:
              allOf:
                - $ref: '#/components/schemas/BlockchainAsset'
              description: On-chain identity for the wallet asset and chain.
            address:
              type: string
              description: On-chain wallet address.
            balance:
              type: string
              description: Balance in display units (decimal string).
            currencyName:
              type: string
              description: Human-readable currency name (e.g. "USD Coin").
            estimatedBalanceValue:
              type: string
              description: |-
                Estimated balance value in the currency requested via the
                        `estimatedBalanceCurrencyCode` query param, computed by the upstream
                        provider at read time. Defaults to USD when the query param is
                        omitted.
            updatedAt:
              type: string
              format: date-time
              description: When the cached OMS-side balance row was last updated.
          description: The balance entry for the wallet.
      description: >-
        The current balance of a single wallet, with its estimated value in the
        requested currency.
    WalletCreateRequest:
      type: object
      required:
        - asset
        - chain
      properties:
        asset:
          type: string
          description: Asset the wallet will hold (e.g. `usdc`).
        chain:
          type: string
          description: Chain the wallet lives on.
      description: >-
        Request body for creating a wallet: the asset to hold and the chain it
        lives on.
      example:
        asset: usdc
        chain: ethereum
    WalletExternalDestination:
      type: object
      required:
        - type
        - category
        - details
      properties:
        party:
          $ref: '#/components/schemas/Party'
        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.
        details:
          $ref: '#/components/schemas/WalletExternalDetails'
        payoutOrigin:
          $ref: '#/components/schemas/PayoutOrigin'
      title: External wallet
    WalletExternalDetails:
      type: object
      properties:
        id:
          allOf:
            - $ref: '#/components/schemas/typeId'
          description: Unique identifier.
        asset:
          type: string
          description: Canonical asset identifier.
        network:
          type: string
          description: Network identifier.
        blockchainAddress:
          type: string
          description: On-chain address.
        custodian:
          type: string
          description: Custodian holding the funds.
        otherCustodian:
          type: string
          description: Free-text custodian name when `custodian` is `other`.
        txHash:
          type: string
          description: On-chain transaction hash.
        blockchainAsset:
          allOf:
            - $ref: '#/components/schemas/BlockchainAsset'
          description: >-
            BPN extension: resolved on-chain asset identity
            (protocol/chainId/tokenId).
      description: >-
        WalletExternal instrument details: a crypto wallet held in external
        custody.
    WalletExternalInstrument:
      type: object
      required:
        - type
        - category
        - details
      properties:
        party:
          $ref: '#/components/schemas/Party'
        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.
        details:
          $ref: '#/components/schemas/WalletExternalDetails'
      description: Externally-custodied crypto wallet instrument.
      title: External wallet
    WalletExternalRegisteredSideDetails:
      type: object
      required:
        - id
        - asset
        - network
      properties:
        id:
          type: string
          description: Registered ExternalAccount ID (ext_wlt_ prefix). Required.
        asset:
          type: string
          description: 'Crypto asset. One of: usdc, usdt.'
        network:
          allOf:
            - $ref: '#/components/schemas/CryptoNetwork'
          description: Network identifier.
    WalletExternalRegisteredSideRequest:
      type: object
      required:
        - type
        - details
      properties:
        type:
          type: string
          enum:
            - walletExternal
          description: Type discriminator.
        details:
          $ref: '#/components/schemas/WalletExternalRegisteredSideDetails'
        amount:
          $ref: '#/components/schemas/decimalString'
      description: >-
        Deliver to a wallet held outside OMS, by registered ExternalAccount only

        (id-only; raw addresses are not accepted). Used by Virtual Account

        destinations; the raw-address `WalletExternalSideRequest` stays
        quote/transaction-only.
      title: External wallet (registered)
    WalletExternalSideDetails:
      type: object
      required:
        - asset
        - network
      properties:
        id:
          type: string
          description: ExternalAccount ID (ext_wlt_ prefix). One of id/blockchainAddress.
        blockchainAddress:
          type: string
          description: >-
            Raw on-chain address (when not registered). One of
            id/blockchainAddress.

            For an EVM network the address must be all-lowercase, all-uppercase,
            or a

            valid EIP-55 checksummed form; an inconsistent mixed-case address is
            rejected

            as a likely casing typo, and the zero address is rejected.
            Solana/SUI are

            validated per their own network rules.
        asset:
          type: string
          description: 'Crypto asset. One of: usdc, usdt.'
        network:
          allOf:
            - $ref: '#/components/schemas/CryptoNetwork'
          description: Network identifier.
    WalletExternalSideRequest:
      type: object
      required:
        - type
        - details
      properties:
        type:
          type: string
          enum:
            - walletExternal
          description: Type discriminator.
        details:
          $ref: '#/components/schemas/WalletExternalSideDetails'
        amount:
          $ref: '#/components/schemas/decimalString'
      description: >-
        Deliver to a wallet held outside OMS. Provide exactly one of `id` (a

        registered ExternalAccount, ext_wlt_ prefix) or `blockchainAddress` (a
        raw

        on-chain address).
      title: External wallet
    WalletFiatDestination:
      type: object
      required:
        - type
        - category
        - details
      properties:
        party:
          $ref: '#/components/schemas/Party'
        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.
        details:
          $ref: '#/components/schemas/WalletFiatInstrumentDetails'
        payoutOrigin:
          $ref: '#/components/schemas/PayoutOrigin'
      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
    WalletFiatInstrument:
      type: object
      required:
        - type
        - category
        - details
      properties:
        party:
          $ref: '#/components/schemas/Party'
        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.
        details:
          $ref: '#/components/schemas/WalletFiatInstrumentDetails'
      description: |-
        Fiat balance wallet instrument — a USD balance held at a partner bank
        (Erebor Bank, N.A.). No network or on-chain address; an internal ledger.
      title: Fiat wallet
    WalletFiatInstrumentDetails:
      type: object
      properties:
        id:
          type: string
          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.
            Matches the

            sibling `WalletFiatSideDetails.id` in quote.tsp.
        asset:
          type: string
          enum:
            - usd
          description: Fiat currency of the balance. Only `usd` today.
        provider:
          type: string
          description: >-
            Legal entity holding the balance (e.g. "Erebor Bank, N.A.").
            Read-only.
      description: >-
        WalletFiat instrument details: a fiat balance wallet held at a partner
        bank

        (e.g. USD at Erebor Bank, N.A.). No network or on-chain address — an

        internal ledger balance.
    WalletFiatSideDetails:
      type: object
      required:
        - id
        - asset
      properties:
        id:
          type: string
          description: OMS fiat wallet ID (wlt_fiat_ prefix).
        asset:
          type: string
          enum:
            - usd
          description: Fiat currency. Only `usd` today.
    WalletFiatSideRequest:
      type: object
      required:
        - type
        - details
      properties:
        type:
          type: string
          enum:
            - walletFiat
          description: Type discriminator.
        details:
          $ref: '#/components/schemas/WalletFiatSideDetails'
        amount:
          $ref: '#/components/schemas/decimalString'
      description: |-
        Pull from / deliver to a fiat balance wallet owned by the customer. No
        `network` — the balance lives on an internal ledger.
      title: Fiat wallet
    WalletList:
      type: object
      properties:
        data:
          type: object
          properties:
            walletAddresses:
              type: array
              items:
                $ref: '#/components/schemas/CustomerWallet'
      description: A list of a customer's wallets.
    WalletOmsDestination:
      type: object
      required:
        - type
        - category
        - details
      properties:
        party:
          allOf:
            - $ref: '#/components/schemas/Party'
          description: Structured identity of who is on this side.
        type:
          type: string
          enum:
            - walletOms
          description: Type discriminator.
        category:
          type: string
          enum:
            - crypto
          description: >-
            High-level grouping: `fiatAccount` for bank or card accounts,
            `crypto` for wallets.
        details:
          $ref: '#/components/schemas/WalletOmsDetails'
        payoutOrigin:
          $ref: '#/components/schemas/PayoutOrigin'
      title: OMS wallet
    WalletOmsDetails:
      type: object
      properties:
        id:
          allOf:
            - $ref: '#/components/schemas/typeId'
          description: >-
            Internal OMS wallet (`wlt_` prefix; legacy `acc_` also accepted on
            input).
        asset:
          type: string
          description: Canonical asset identifier.
        network:
          type: string
          description: Network identifier.
        blockchainAddress:
          type: string
          description: On-chain address.
        custodyType:
          type: string
          enum:
            - custodial
            - embedded
          description: 'How the wallet is held: `custodial` or `embedded`.'
        txHash:
          type: string
          description: On-chain transaction hash.
        blockchainAsset:
          allOf:
            - $ref: '#/components/schemas/BlockchainAsset'
          description: >-
            BPN extension: resolved on-chain asset identity
            (protocol/chainId/tokenId).
      description: 'WalletOms instrument details: an OMS-custodied crypto wallet.'
    WalletOmsInstrument:
      type: object
      required:
        - type
        - category
        - details
      properties:
        party:
          allOf:
            - $ref: '#/components/schemas/Party'
          description: Structured identity of who is on this side.
        type:
          type: string
          enum:
            - walletOms
          description: Type discriminator.
        category:
          type: string
          enum:
            - crypto
          description: >-
            High-level grouping: `fiatAccount` for bank or card accounts,
            `crypto` for wallets.
        details:
          $ref: '#/components/schemas/WalletOmsDetails'
      description: OMS-custodied crypto wallet instrument.
      title: OMS wallet
    WalletOmsSideDetails:
      type: object
      required:
        - id
        - asset
        - network
      properties:
        id:
          type: string
          description: OMS wallet ID (wlt_ prefix).
        asset:
          type: string
          description: 'Crypto asset. One of: usdc, usdt.'
        network:
          allOf:
            - $ref: '#/components/schemas/CryptoNetwork'
          description: Network identifier.
    WalletOmsSideRequest:
      type: object
      required:
        - type
        - details
      properties:
        type:
          type: string
          enum:
            - walletOms
          description: Type discriminator.
        details:
          $ref: '#/components/schemas/WalletOmsSideDetails'
        amount:
          $ref: '#/components/schemas/decimalString'
      description: Pull from / deliver to an OMS Multi-Chain Wallet owned by the customer.
      title: OMS wallet
    WalletStatus:
      type: string
      enum:
        - active
        - suspended
        - frozen
        - closed
    WalletType:
      type: string
      enum:
        - internal
        - external
      description: >-
        Whether a wallet is internal (OMS-managed) or external (held outside
        OMS).
    decimalString:
      type: string
      description: >-
        Wire-safe decimal string for financial float values (USD amounts,
        percentages).
      x-go-type-import:
        path: github.com/shopspring/decimal
      x-go-type: decimal.Decimal
    fixedDecimalString:
      type: string
      description: Wire-safe decimal string that preserves trailing zeros on the wire.
      x-go-type-import:
        path: github.com/0xPolygon/bpn-lib/numeric
      x-go-type: numeric.FixedDecimalString
    int64String:
      type: string
      description: Wire-safe integer string for fiat amounts within int64 range.
      x-go-type-import:
        path: github.com/0xPolygon/bpn-lib/numeric
      x-go-type: numeric.Int64String
    omsxProjectId:
      type: string
      pattern: ^prj_.+$
      description: 'Opaque OMSX project ID, e.g. `prj_01kpxxa7esk9a`.'
      x-go-type: string
    paymentMemo:
      type: string
      maxLength: 140
      pattern: '^[A-Za-z0-9 /?:().,''+\-]*$'
      description: >-
        Customer-supplied payment memo carried to the beneficiary's bank in the

        ISO 20022 unstructured remittance-information field. Allowed characters
        are

        the ISO 20022 set only: letters, digits, space and `/?:().,'+-`.


        `maxLength` is the ISO 20022 OUTER bound (140), which is what Fedwire
        and

        SWIFT accept. Per-rail rules are enforced server-side rather than in the

        schema. Note that ACH is not simply shorter: the NACHA addenda record is
        a

        different character set (uppercase only, no `/`, but `&=@_#%` allowed)
        capped

        at 80, so the two sets overlap without either containing the other.


        The pattern below MUST stay byte-identical to `iso20022.CharsetPattern`

        (`lib/iso20022/charset.go`), the Go-side authority the request
        validators and

        the outbound memo builders share. `TestCharsetPatternMatchesTypeSpec`
        reads

        this file and fails if the two drift.
      x-go-type: string
    signedFixedDecimalString:
      type: string
      description: >-
        Wire-safe decimal string for signed financial values that must ship with
        a

        fixed scale (trailing zeros preserved). It combines the two guarantees
        the

        OMS `Customer.totalBalance` fields need at once: the leading minus is
        part of

        the contract — a fiat balance may be negative after an ACH clawback, so

        consumers render the sign as-is and never clamp to zero — and the scale
        is

        preserved on the wire (e.g. `"25.00"`, `"-25.00"`, `"0.00"`), unlike

        `signedDecimalString`/`decimal.Decimal`, whose `.String()` trims
        trailing

        zeros (`"25.00"` → `"25"`). Same underlying `numeric.FixedDecimalString`
        Go

        type as `fixedDecimalString`; the builder is responsible for setting the

        scale (via `StringFixed`).
      x-go-type-import:
        path: github.com/0xPolygon/bpn-lib/numeric
      x-go-type: numeric.FixedDecimalString
    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
  parameters:
    IdempotencyKey:
      name: Idempotency-Key
      in: header
      required: true
      schema:
        type: string
      description: Unique key to prevent duplicate requests. Required on all POST requests.
      example: ord_123_attempt_1
    IdempotencyKeyHeader:
      name: Idempotency-Key
      in: header
      required: true
      description: >-
        Required on POST and PUT requests. Use a unique value per logical
        mutation attempt, for example a UUID.
      schema:
        type: string
    PaginationParams.endingBefore:
      name: endingBefore
      in: query
      required: false
      schema:
        type: string
    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
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: Token from POST /auth/token
