openapi: 3.0.0
info:
  title: Buildmarkets Investment API
  version: 1.0.0
  description: |
    The Buildmarkets API provides embeddable investment experiences, allowing fintech partners to manage investor accounts, facilitate trading, handle document uploads, and manage wallet operations.

    ### Response conventions

    Every resource response carries a small set of Stripe-shaped envelope keys
    followed by domain fields:

    ```json
    {
      "id": "<prefix>_<base32>",
      "object": "<resource>",
      "created": <unix_seconds>,
      "livemode": <boolean>,
      "metadata": { ... },
      ... domain fields ...
    }
    ```

    List endpoints return:

    ```json
    {
      "object": "list",
      "url": "/v1/<resource>",
      "has_more": false,
      "data": [ <resource>... ]
    }
    ```

    Errors are wrapped in:

    ```json
    {
      "error": {
        "type": "invalid_request_error",
        "code": "BLUM-400-001",
        "message": "...",
        "param": "tax_id"
      }
    }
    ```

    See `ResourceEnvelope`, `ListEnvelope`, and `ErrorEnvelope` in
    `shared-schemas.yaml` for the full schemas.

    ### Field naming (Column-style)

    - snake_case throughout (no camelCase)
    - `email` / `phone` (not `email_address` / `phone_number`)
    - `first_name` / `middle_name` / `last_name` (not `given_name` / `family_name`)
    - `address: { street: [string], unit?, city, state?, postal_code?, country }`
      (the `street` array form preserves multi-line addresses; ISO 3166-1
      alpha-2 country code on `address.country` and on the top-level
      `country_of_*` fields)
    - `quantity` (not `qty`)
    - Status enums are lowercase Buildmarkets-native vocab (e.g. `pending` / `filled` / `cancelled` / `failed`),
      not Alpaca's `accepted` / `partially_filled` / `rejected` / etc.

    Regulatory vocabulary (CAIS / FINRA / IRS / FATF) is preserved verbatim
    (e.g. `tax_id_type`, `country_of_tax_residence`, `is_politically_exposed`,
    `funding_source`).

    ### Terminology

    The investor resource lives at `/v1/investors`. Path parameter is
    `investor_id`.

    ### Asset classification

    Assets carry a canonical `(class, country)` pair:
    - `class`: `equity` | `etf` | `bond` | `bill` | `note` | `mutual_fund` |
      `derivative` | `cryptocurrency` | `commodity` | `real_estate` | `cash`
    - `country`: ISO 3166-1 alpha-2, lower-case (`us`, `ng`, …). Null for
      country-agnostic instruments (most crypto).

    The legacy combined field `asset_class` (e.g. `us_equity`, `ng_bond`)
    is still accepted on requests and emitted on responses for backwards
    compatibility, but is deprecated and will be removed.

    ### Fixed income (bonds)

    Bond orders use the same `POST /v1/investors/{investor_id}/orders`
    endpoint as equities, with bond-specific semantics:
    - `quantity` carries **face value** (e.g. `"10000"` for $10k face),
      and must be a multiple of the bond's `min_increment`.
    - `limit_price` is quoted as **% of par** (e.g. `"99.875"` = 99.875%
      of face value).
    - `settlement_date` is optional; defaults to T+1 for US treasuries
      and T+2 for corporates.
    - Bond quote responses (`/v1/market-data/assets/{symbol}/quote`)
      include a `bond` block with clean/dirty price, accrued interest,
      and yield to maturity.

    Bond trading must be explicitly enabled on the tenant before orders
    will route. Contact Buildmarkets support to flip `fixedIncomeEnabled`.

    ### Authentication

    HTTP Basic Authentication. **API Key** is the username, **API Secret** is
    the password. Base64-encode `API_KEY:API_SECRET` and send in the
    `Authorization` header.
servers:
  - url: https://api.tappengine.com/v1
    description: Production Environment
  - url: https://dev-tapp-api.tappengine.com/v1
    description: Sandbox/Testing Environment
security:
  - BluumApiKeyAuth: []
  - BearerAuth: []
tags:
  - name: Investors
    description: Create and manage investor accounts, wallets, and transactions.
  - name: Compliance
    description: Investor compliance workflows, KYC checks, and document submissions.
  - name: Transfers
    description: Deposit and withdrawal operations for investor wallets.
  - name: Funding Sources
    description: Connect and manage external funding sources (Plaid, bank accounts).
  - name: Trading
    description: Place, list, and cancel investor orders.
  - name: Positions
    description: View investor portfolio positions.
  - name: Assets
    description: Search and retrieve asset reference data.
  - name: Document Management
    description: Upload, list, and download documents.
  - name: Markets
    description: Market reference data, status, calendar, and halts.
  - name: Market Data
    description: Real-time quotes, snapshots, and historical bars (paywalled product).
  - name: Webhooks
    description: Register and manage webhook endpoints for event delivery.
  - name: Disclosures
    description: Partner-facing disclosure library (verbatim regulated copy, PDFs) + per-investor acceptance trail.
  - name: Cash Sweep
    description: High Yield Cash (HYC) / FDIC Bank Sweep enrollment, tier management, and interest reporting.
  - name: Investor Profile
    description: '[Wealth] Manage investor demographics, employment, tax, and preferences.'
  - name: Dependents
    description: '[Wealth] Manage investor dependents.'
  - name: Risk Assessment
    description: '[Wealth] Submit and view investor risk assessments.'
  - name: Goals
    description: '[Wealth] Create and manage financial goals.'
  - name: Life Events
    description: '[Wealth] Track significant life events that affect financial planning.'
  - name: External Accounts
    description: '[Wealth] Manage accounts held outside the platform.'
  - name: Financial Plan
    description: '[Wealth] Generate and view financial plans.'
  - name: Investment Policy
    description: '[Wealth] Create and validate investment policy statements.'
  - name: Portfolio Management
    description: '[Wealth] Portfolio summary, holdings, performance, and rebalancing.'
  - name: Auto-Invest
    description: '[Wealth] Recurring investment schedules and dividend reinvestment.'
  - name: Insights & Recommendations
    description: '[Wealth] AI-driven insights, recommendations, and tax optimization.'
  - name: Reports
    description: '[Wealth] Account statements, P&L, and benchmark reports.'
paths:
  /investors:
    get:
      tags:
        - Investors
      summary: List all investors for the authenticated tenant
      operationId: listAccounts
      responses:
        '200':
          description: List of investors.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/ListEnvelope'
                  - type: object
                    properties:
                      data:
                        type: array
                        items:
                          $ref: '#/components/schemas/Investor'
              examples:
                success:
                  summary: One active investor
                  value:
                    object: list
                    url: /v1/investors
                    has_more: false
                    data:
                      - id: inv_01j9x8m2k7qpzwv3t5r6y8n0ab
                        object: investor
                        created: 1747776000
                        livemode: false
                        metadata: {}
                        status: active
                        account_type: individual
                        management_type: self_directed
                        tax_advantaged: false
                        tax_designation: null
                        account_number: '968430933'
                        currency: USD
                        balance: '1000.00'
                        buying_power: '10000.00'
                        cash_withdrawable: '5000.00'
                        last_equity: '5000.00'
                        crypto_status: null
                        trading_type: cash
                        first_name: John
                        middle_name: null
                        last_name: Doe
                        date_of_birth: '1980-01-01'
                        email: john.doe@example.com
                        phone: '+15555555555'
                        address:
                          street:
                            - 123 Main St
                          unit: null
                          city: Berkeley
                          state: CA
                          postal_code: '94704'
                          country: US
                        tax_id_type: SSN
                        country_of_tax_residence: US
                        country_of_citizenship: US
                        country_of_birth: US
                        funding_source:
                          - employment_income
                        is_control_person: false
                        is_affiliated_exchange_or_finra: false
                        is_affiliated_exchange_or_iiroc: null
                        is_politically_exposed: false
                        immediate_family_exposed: false
                        employment_status: employed
                        employer_name: Acme Inc
                        employer_address: 1 Tech Way, Berkeley, CA
                        employment_position: Engineer
                        signed_agreements:
                          - type: investor_agreement
                            signed_at: '2026-01-15T10:30:00.000Z'
                            ip_address: 203.0.113.42
                        trusted_contact: null
                        portfolios: []
        '401':
          $ref: '#/components/responses/UnauthorizedError'
    post:
      tags:
        - Investors
      summary: Create a new investor
      description: |
        Create an investor with full KYC data. The request body is
        flat: regulatory fields at the top level; only
        `address`, `signed_agreements[]`, and `trusted_contact` are nested.
      operationId: createAccount
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/NewAccountRequest'
            examples:
              individual:
                summary: Individual self-directed investor
                value:
                  account_type: individual
                  management_type: self_directed
                  tax_advantaged: false
                  first_name: Jane
                  last_name: Doe
                  date_of_birth: '1990-05-15'
                  email: jane.doe@example.com
                  phone: '+14155551234'
                  address:
                    street:
                      - 456 Oak Avenue
                    city: San Francisco
                    state: CA
                    postal_code: '94102'
                    country: US
                  tax_id: 987-65-4321
                  tax_id_type: SSN
                  country_of_tax_residence: US
                  country_of_citizenship: US
                  country_of_birth: US
                  funding_source:
                    - employment_income
                  annual_income:
                    min: '75000'
                    max: '99999'
                  liquid_net_worth:
                    min: '20000'
                    max: '49999'
                  is_control_person: false
                  is_affiliated_exchange_or_finra: false
                  is_politically_exposed: false
                  immediate_family_exposed: false
                  employment_status: employed
                  employer_name: Acme Inc
                  signed_agreements:
                    - type: investor_agreement
                      signed_at: '2026-01-15T10:30:00.000Z'
                      ip_address: 203.0.113.42
                    - type: margin_disclosure_acknowledged
                      signed_at: '2026-01-15T10:30:00.000Z'
                      ip_address: 203.0.113.42
      responses:
        '201':
          description: Investor created. Pending compliance approval.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Investor'
              examples:
                created:
                  summary: Investor created; compliance checks pending
                  value:
                    id: inv_01j9x8m2k7qpzwv3t5r6y8n0ab
                    object: investor
                    created: 1747776000
                    livemode: false
                    metadata: {}
                    status: onboarding
                    account_type: individual
                    management_type: self_directed
                    tax_advantaged: false
                    tax_designation: null
                    account_number: null
                    currency: USD
                    balance: '0.00'
                    buying_power: '0'
                    cash_withdrawable: '0'
                    last_equity: '0.00'
                    crypto_status: null
                    trading_type: null
                    first_name: Jane
                    middle_name: null
                    last_name: Doe
                    date_of_birth: '1990-05-15'
                    email: jane.doe@example.com
                    phone: '+14155551234'
                    address:
                      street:
                        - 456 Oak Avenue
                      unit: null
                      city: San Francisco
                      state: CA
                      postal_code: '94102'
                      country: US
                    tax_id_type: SSN
                    country_of_tax_residence: US
                    country_of_citizenship: US
                    country_of_birth: US
                    funding_source:
                      - employment_income
                    is_control_person: false
                    is_affiliated_exchange_or_finra: false
                    is_affiliated_exchange_or_iiroc: null
                    is_politically_exposed: false
                    immediate_family_exposed: false
                    employment_status: employed
                    employer_name: Acme Inc
                    employer_address: null
                    employment_position: null
                    signed_agreements:
                      - type: investor_agreement
                        signed_at: '2026-01-15T10:30:00.000Z'
                        ip_address: 203.0.113.42
                    trusted_contact: null
                    portfolios: []
                    compliance_checks:
                      - workflow_id: cw_01j9x8m2k7qpzwv3t5r6y8n0cd
                        check_type: identity_verification
                        status: pending
                        provider: persona-identity
                        external_id: inq_abc123def456
                        verification_url: https://withpersona.com/verify?inquiry-id=inq_abc123def456
                        verification_token: null
                      - workflow_id: cw_01j9x8m2k7qpzwv3t5r6y8n0cd
                        check_type: screening
                        status: pending
                        provider: persona-screening
                        external_id: null
                        verification_url: null
                        verification_token: null
        '400':
          $ref: '#/components/responses/BadRequestError'
  /investors/{investor_id}:
    get:
      tags:
        - Investors
      summary: Retrieve a specific investor
      operationId: getAccount
      parameters:
        - $ref: '#/components/parameters/InvestorIdPath'
      responses:
        '200':
          description: Investor details.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Investor'
              examples:
                active:
                  summary: Active investor with balance
                  value:
                    id: inv_01j9x8m2k7qpzwv3t5r6y8n0ab
                    object: investor
                    created: 1740000000
                    livemode: false
                    metadata: {}
                    status: active
                    account_type: individual
                    management_type: self_directed
                    tax_advantaged: false
                    tax_designation: null
                    account_number: '968430933'
                    currency: USD
                    balance: '1000.00'
                    buying_power: '10000.00'
                    cash_withdrawable: '5000.00'
                    last_equity: '5000.00'
                    crypto_status: null
                    trading_type: cash
                    first_name: John
                    middle_name: null
                    last_name: Doe
                    date_of_birth: '1980-01-01'
                    email: john.doe@example.com
                    phone: '+15555555555'
                    address:
                      street:
                        - 123 Main St
                      unit: null
                      city: Berkeley
                      state: CA
                      postal_code: '94704'
                      country: US
                    tax_id_type: SSN
                    country_of_tax_residence: US
                    country_of_citizenship: US
                    country_of_birth: US
                    funding_source:
                      - employment_income
                    is_control_person: false
                    is_affiliated_exchange_or_finra: false
                    is_affiliated_exchange_or_iiroc: null
                    is_politically_exposed: false
                    immediate_family_exposed: false
                    employment_status: employed
                    employer_name: Acme Inc
                    employer_address: 1 Tech Way, Berkeley, CA
                    employment_position: Engineer
                    signed_agreements:
                      - type: investor_agreement
                        signed_at: '2026-01-15T10:30:00.000Z'
                        ip_address: 203.0.113.42
                    trusted_contact: null
                    portfolios: []
        '404':
          $ref: '#/components/responses/NotFoundError'
  /investors/{investor_id}/close:
    post:
      tags:
        - Investors
      summary: Close an investor account
      description: |
        Closes an investor account. The account must have no open positions,
        no pending orders, and zero wallet balance. Returns 409 Conflict if
        any of these conditions are not met.
      operationId: closeAccount
      parameters:
        - $ref: '#/components/parameters/InvestorIdPath'
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                reason:
                  type: string
                  description: Optional reason for closing the account.
                  example: Customer requested account closure
      responses:
        '200':
          description: Investor closed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Investor'
              examples:
                closed:
                  summary: Closed investor
                  value:
                    id: inv_01j9x8m2k7qpzwv3t5r6y8n0ab
                    object: investor
                    created: 1740000000
                    livemode: false
                    metadata: {}
                    status: closed
                    account_type: individual
                    currency: USD
                    balance: '0.00'
                    buying_power: '0'
                    cash_withdrawable: '0'
                    last_equity: '0.00'
                    first_name: John
                    last_name: Doe
                    email: john.doe@example.com
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
        '409':
          $ref: '#/components/responses/ConflictError'
  /investors/{investor_id}/trusted-contact:
    put:
      tags:
        - Investors
      summary: Set or update an investor's trusted contact
      description: |
        Set or update the trusted contact for an investor. FINRA SR Rule
        4512 requires partners to give end-users a way to add a trusted
        contact post-onboarding. All four fields are required together —
        partial submissions are rejected.
      operationId: setTrustedContact
      parameters:
        - $ref: '#/components/parameters/InvestorIdPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TrustedContact'
            examples:
              default:
                summary: Set a trusted contact
                value:
                  first_name: Mary
                  last_name: Doe
                  email: mary@example.com
                  phone: '+15555550199'
      responses:
        '200':
          description: Trusted contact updated successfully.
          content:
            application/json:
              schema:
                type: object
                required:
                  - object
                  - investor_id
                  - first_name
                  - last_name
                  - email
                  - phone
                properties:
                  object:
                    type: string
                    enum:
                      - trusted_contact
                  livemode:
                    type: boolean
                  investor_id:
                    type: string
                  first_name:
                    type: string
                  last_name:
                    type: string
                  email:
                    type: string
                  phone:
                    type: string
              example:
                object: trusted_contact
                livemode: false
                investor_id: inv_01j9x8m2k7qpzwv3t5r6y8n0ab
                first_name: Mary
                last_name: Doe
                email: mary@example.com
                phone: '+15555550199'
        '400':
          $ref: '#/components/responses/BadRequestError'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /investors/{investor_id}/compliance:
    get:
      tags:
        - Investors
      summary: Get compliance status for an investor
      description: |
        Retrieve the compliance/verification workflow status and individual
        check results for a specific investor. Returns the most recent
        compliance workflow.
      operationId: getAccountCompliance
      parameters:
        - $ref: '#/components/parameters/InvestorIdPath'
      responses:
        '200':
          description: Compliance status.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ComplianceStatus'
              examples:
                approved:
                  summary: Approved KYC workflow
                  value:
                    object: compliance_workflow
                    livemode: false
                    investor_id: inv_01j9x8m2k7qpzwv3t5r6y8n0ab
                    workflow_status: APPROVED
                    workflow_type: kyc
                    risk_level: low
                    status: approved
                    checks:
                      - type: identity_verification
                        status: clear
                        completed_at: '2026-03-15T10:05:00.000Z'
                      - type: screening
                        status: clear
                        completed_at: '2026-03-15T10:05:00.000Z'
                      - type: risk_assessment
                        status: clear
                        completed_at: '2026-03-15T10:05:00.000Z'
                    created_at: '2026-03-15T10:00:00.000Z'
                    updated_at: '2026-03-15T10:05:00.000Z'
                running:
                  summary: In-progress KYC workflow
                  value:
                    object: compliance_workflow
                    livemode: false
                    investor_id: inv_01j9x8m2k7qpzwv3t5r6y8n0ab
                    workflow_status: IN_PROGRESS
                    workflow_type: kyc
                    risk_level: null
                    status: running
                    checks:
                      - type: identity_verification
                        status: pending
                        completed_at: null
                      - type: screening
                        status: pending
                        completed_at: null
                    created_at: '2026-03-15T10:00:00.000Z'
                    updated_at: '2026-03-15T10:00:00.000Z'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /investors/{investor_id}/wallets:
    get:
      tags:
        - Investors
      summary: List wallets for an investor
      description: |
        Retrieves all wallets (currency accounts) for a specific investor.
        Each wallet holds a balance for a specific currency.
      operationId: getAccountWallets
      parameters:
        - $ref: '#/components/parameters/InvestorIdPath'
      responses:
        '200':
          description: List of wallets.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/ListEnvelope'
                  - type: object
                    properties:
                      data:
                        type: array
                        items:
                          $ref: '#/components/schemas/Wallet'
              examples:
                multi_wallet:
                  summary: Investor with two wallets
                  value:
                    object: list
                    url: /v1/investors/inv_01j9x8m2k7qpzwv3t5r6y8n0ab/wallets
                    has_more: false
                    data:
                      - id: wlt_01j9x8m2k7qpzwv3t5r6y8n0cd
                        object: wallet
                        created: 1747776000
                        livemode: false
                        metadata: {}
                        currency: USD
                        balance: '1500.00'
                        available_balance: '1200.00'
                        reserved_balance: '300.00'
                        cash_withdrawable: '1000.00'
                        buying_power: '5000.00'
                        equity: '8500.00'
                        status: active
                      - id: wlt_01j9x8m2k7qpzwv3t5r6y8n0ef
                        object: wallet
                        created: 1747780000
                        livemode: false
                        metadata: {}
                        currency: EUR
                        balance: '500.00'
                        available_balance: '500.00'
                        reserved_balance: '0.00'
                        cash_withdrawable: '0'
                        buying_power: '0'
                        equity: '0'
                        status: active
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /investors/{investor_id}/transactions:
    get:
      tags:
        - Investors
      summary: List transactions for an investor
      description: |
        Returns the investor's cash activity:

        - **Funding** — `deposit` and `withdrawal` movements.
        - **Trades** — `buy` / `sell` cash settlements from filled orders.
        - **Activity** — non-trade account activity: dividends, fees,
          interest, fixed-income maturity, journals, withholdings, and
          corporate actions.

        Pending fund reservations from in-flight orders are not listed.
      operationId: listAccountTransactions
      parameters:
        - $ref: '#/components/parameters/InvestorIdPath'
        - name: type
          in: query
          required: false
          schema:
            type: string
            enum:
              - deposit
              - withdrawal
              - buy
              - sell
              - activity
          description: Filter by transaction kind (funding, trade cash movement, or custodian activity)
        - name: activity_type
          in: query
          required: false
          schema:
            type: string
            example: FIMAT,CDIV
          description: |
            Comma-separated activity tags to filter on (e.g.
            `FIMAT,CDIV`). Only meaningful when `type=activity` or `type`
            is omitted. Common values: `FIMAT` (fixed-income maturity),
            `CDIV` / `SDIV` (dividends), `DIVNRA` (dividend withholding),
            `FEE`, `INT`, `JNLC` / `JNLS` (journals), `ACATC` / `ACATS`,
            corporate actions (`FSPLIT`, `RSPLIT`, `CMA`, `SMA`,
            `REORG`, `SPIN`, `VOF`).
        - name: status
          in: query
          required: false
          schema:
            type: string
            enum:
              - pending
              - processing
              - received
              - completed
              - submitted
              - expired
              - canceled
              - failed
          description: Filter by deposit/withdrawal status (Buildmarkets-native enum, lowercased in responses)
        - name: currency
          in: query
          required: false
          schema:
            type: string
            minLength: 3
            maxLength: 3
            example: USD
        - name: date_from
          in: query
          required: false
          schema:
            type: string
            format: date
        - name: date_to
          in: query
          required: false
          schema:
            type: string
            format: date
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 50
        - name: offset
          in: query
          required: false
          schema:
            type: integer
            minimum: 0
            default: 0
      responses:
        '200':
          description: List of transactions.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/ListEnvelope'
                  - type: object
                    properties:
                      data:
                        type: array
                        items:
                          $ref: '#/components/schemas/Transaction'
              examples:
                page:
                  summary: Two transactions
                  value:
                    object: list
                    url: /v1/investors/inv_01j9x8m2k7qpzwv3t5r6y8n0ab/transactions
                    has_more: false
                    data:
                      - id: txn_01j9x8m2k7qpzwv3t5r6y8n0gh
                        object: transaction
                        created: 1747776000
                        livemode: false
                        metadata: {}
                        investor_id: inv_01j9x8m2k7qpzwv3t5r6y8n0ab
                        wallet_id: wlt_01j9x8m2k7qpzwv3t5r6y8n0cd
                        type: deposit
                        status: completed
                        amount: '5000.00'
                        currency: USD
                        method: ach
                        description: Initial account funding
                        completed_at: '2026-01-16T14:20:00Z'
                        failed_at: null
                        failure_reason: null
                      - id: txn_01j9x8m2k7qpzwv3t5r6y8n0ij
                        object: transaction
                        created: 1747780000
                        livemode: false
                        metadata: {}
                        investor_id: inv_01j9x8m2k7qpzwv3t5r6y8n0ab
                        wallet_id: wlt_01j9x8m2k7qpzwv3t5r6y8n0cd
                        type: withdrawal
                        status: pending
                        amount: '1000.00'
                        currency: USD
                        method: ach
                        description: Withdrawal to bank account
                        completed_at: null
                        failed_at: null
                        failure_reason: null
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /investors/{investor_id}/portfolio-chart:
    get:
      tags:
        - Investors
      summary: Get portfolio chart for an investor
      operationId: getPortfolioChart
      description: |
        Returns the investor's current portfolio value (cash + equity positions) and a historical time-series for portfolio chart.
      parameters:
        - $ref: '#/components/parameters/InvestorIdPath'
      responses:
        '200':
          description: Portfolio chart data.
          content:
            application/json:
              schema:
                type: object
                properties:
                  object:
                    type: string
                    enum:
                      - portfolio_chart
                  livemode:
                    type: boolean
                  investor_id:
                    type: string
                    description: Prefixed public id of the investor.
                  currency:
                    type: string
                    example: USD
                  current:
                    type: object
                    properties:
                      total_value:
                        type: string
                        description: Cash + positions value.
                        example: '2500.00'
                      cash_value:
                        type: string
                        description: Investor wallet balance.
                        example: '500.00'
                      positions_value:
                        type: string
                        description: Sum of quantity × currentPrice across all open positions.
                        example: '2000.00'
                      as_of:
                        type: string
                        format: date-time
                        description: Timestamp the snapshot was computed.
                  chart_data:
                    type: array
                    items:
                      type: object
                      properties:
                        date:
                          type: string
                          format: date
                          example: '2026-05-14'
                        total_value:
                          type: string
                          example: '2500.00'
              examples:
                success:
                  summary: Investor with positions and history
                  value:
                    object: portfolio_chart
                    livemode: false
                    metadata: {}
                    investor_id: inv_01j9x8m2k7qpzwv3t5r6y8n0ab
                    currency: USD
                    current:
                      total_value: '2500.00'
                      cash_value: '500.00'
                      positions_value: '2000.00'
                      as_of: '2026-05-14T12:00:00.000Z'
                    chart_data:
                      - date: '2026-04-14'
                        total_value: '2100.00'
                      - date: '2026-05-14'
                        total_value: '2500.00'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /documents:
    post:
      tags:
        - Document Management
      summary: Upload a document (flat resource)
      description: |
        Uploads a document. Owner is inferred from the body:
          * `investor_id` set → owner is the investor
          * `user_id`     set → owner is the user (e.g., UBO)
          * neither set       → owner is the calling tenant
        `investor_id` and `user_id` are mutually exclusive.
      operationId: createDocument
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required:
                - document
                - document_type
              properties:
                document:
                  type: string
                  format: binary
                  description: The file to upload (PDF, JPG, PNG, DOC, DOCX up to 10MB).
                document_type:
                  type: string
                  description: Free-form document classifier (e.g., `passport`, `proof_of_address`).
                purpose:
                  type: string
                  enum:
                    - KYC
                    - KYB
                    - EDD
                    - TAX
                    - FUNDING_VERIFICATION
                    - AGREEMENT
                    - ACCOUNT_STATEMENT
                    - TRADE_CONFIRMATION
                    - OTHER
                  description: Optional purpose tag; used for retention bookkeeping.
                investor_id:
                  type: string
                  description: Investor owner (prefixed `inv_…` id). Mutually exclusive with `user_id`.
                user_id:
                  type: string
                  description: User owner (e.g., UBO uploads). Mutually exclusive with `investor_id`.
                expires_at:
                  type: string
                  format: date-time
                  description: Optional explicit retention deadline.
                compliance_workflow_id:
                  type: string
                  format: uuid
                  description: Optional compliance workflow to link this document to.
                compliance_check_id:
                  type: string
                  format: uuid
                  description: Optional compliance check to link this document to.
                metadata:
                  type: object
                  additionalProperties: true
                  description: |
                    Optional metadata key-value pairs. For multipart clients that cannot send nested
                    objects, pass a JSON-encoded string; the API accepts either form.
      responses:
        '201':
          description: Document created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DocumentResponse'
        '400':
          $ref: '#/components/responses/BadRequestError'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
    get:
      tags:
        - Document Management
      summary: List documents (flat resource)
      operationId: listDocumentsFlat
      parameters:
        - name: investor_id
          in: query
          required: false
          schema:
            type: string
          description: Filter to documents owned by an investor (prefixed `inv_…` id).
        - name: user_id
          in: query
          required: false
          schema:
            type: string
          description: Filter to documents owned by a user.
        - name: purpose
          in: query
          required: false
          schema:
            type: string
            enum:
              - KYC
              - KYB
              - EDD
              - TAX
              - FUNDING_VERIFICATION
              - AGREEMENT
              - ACCOUNT_STATEMENT
              - TRADE_CONFIRMATION
              - OTHER
        - name: status
          in: query
          required: false
          schema:
            type: string
            enum:
              - UPLOADED
              - PROCESSING
              - ACCEPTED
              - REJECTED
              - EXPIRED
        - name: document_type
          in: query
          required: false
          schema:
            type: string
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
        - name: starting_after
          in: query
          required: false
          schema:
            type: string
            description: Cursor — `document_id` of the previous page's last item.
      responses:
        '200':
          description: Paginated list of documents
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/DocumentResponse'
                  has_more:
                    type: boolean
        '401':
          $ref: '#/components/responses/UnauthorizedError'
  /documents/{document_id}:
    get:
      tags:
        - Document Management
      summary: Retrieve a specific document
      operationId: getDocument
      parameters:
        - name: document_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
            example: doc_a1b2c3d4e5f6g7h8
      responses:
        '200':
          description: Document details retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DocumentResponse'
              examples:
                approved_document:
                  summary: Investor-owned document
                  value:
                    document_id: doc_01j9x8m2k7qpzwv3t5r6y8n0ab
                    object: document
                    owner_type: investor
                    owner_id: 01j9x8m2k7qpzwv3t5r6y8n0cd
                    purpose: kyc
                    document_type: PASSPORT
                    file_name: passport-front.png
                    mime_type: image/png
                    file_size: 524288
                    status: uploaded
                    expires_at: null
                    uploaded_at: '2025-01-10T09:00:00Z'
                    metadata: null
        '404':
          $ref: '#/components/responses/NotFoundError'
    delete:
      tags:
        - Document Management
      summary: Delete a document
      operationId: deleteDocument
      parameters:
        - name: document_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
            example: doc_a1b2c3d4e5f6g7h8
      responses:
        '204':
          description: Document deleted successfully
        '404':
          $ref: '#/components/responses/NotFoundError'
  /documents/{document_id}/download:
    get:
      tags:
        - Document Management
      summary: Download document bytes
      description: |
        Streams the stored file from object storage for the given `document_id`.
        Response body is raw bytes. `Content-Type` matches the document's stored MIME type
        (for example `application/pdf`, `image/png`). `Content-Disposition` is `attachment`
        with the original `file_name`.
      operationId: downloadDocument
      parameters:
        - name: document_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
            example: doc_a1b2c3d4e5f6g7h8
      responses:
        '200':
          description: Document file bytes
          headers:
            Content-Type:
              description: MIME type of the file (matches upload)
              schema:
                type: string
                example: application/pdf
            Content-Disposition:
              description: Attachment header including original filename
              schema:
                type: string
                example: attachment; filename="passport.pdf"
          content:
            application/octet-stream:
              schema:
                type: string
                format: binary
        '400':
          $ref: '#/components/responses/BadRequestError'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
        '500':
          $ref: '#/components/responses/InternalServerError'
  /investors/{investor_id}/order-estimates:
    post:
      tags:
        - Trading
      summary: Estimate order cost before placing
      operationId: estimateOrder
      description: |
        Returns a custodian-backed estimate for **market** or **limit** orders only.
        Does not place an order. Indicative values only — execution price and fees may differ.
      parameters:
        - $ref: '#/components/parameters/InvestorIdPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/OrderEstimateRequest'
            examples:
              market_qty:
                summary: Market buy with quantity
                value:
                  symbol: AAPL
                  side: buy
                  type: market
                  quantity: '10'
              market_notional:
                summary: Market buy with notional
                value:
                  symbol: GOOGL
                  side: buy
                  type: market
                  notional: '500.00'
              limit:
                summary: Limit buy
                value:
                  symbol: MSFT
                  side: buy
                  type: limit
                  quantity: '2'
                  limit_price: '400.00'
      responses:
        '200':
          description: Estimate returned.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OrderEstimate'
        '400':
          $ref: '#/components/responses/BadRequestError'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /investors/{investor_id}/orders:
    post:
      tags:
        - Trading
      summary: Place a new investment order
      operationId: createOrder
      parameters:
        - $ref: '#/components/parameters/InvestorIdPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/OrderRequest'
            examples:
              market_buy:
                summary: Market buy with quantity
                value:
                  symbol: AAPL
                  side: buy
                  type: market
                  time_in_force: day
                  quantity: '10'
                  extended_hours: false
              limit_buy:
                summary: Limit buy
                value:
                  symbol: MSFT
                  side: buy
                  type: limit
                  time_in_force: gtc
                  quantity: '5'
                  limit_price: '350.00'
                  client_order_id: my-order-123
              notional_buy:
                summary: Market buy with dollar amount
                value:
                  symbol: GOOGL
                  side: buy
                  type: market
                  time_in_force: day
                  notional: '1000.00'
              stop_loss:
                summary: Stop loss
                value:
                  symbol: TSLA
                  side: sell
                  type: stop
                  time_in_force: gtc
                  quantity: '20'
                  stop_price: '200.00'
              trailing_stop:
                summary: Trailing stop
                value:
                  symbol: NVDA
                  side: sell
                  type: trailing_stop
                  time_in_force: gtc
                  quantity: '15'
                  trail_percent: '5.0'
              bond_limit_buy:
                summary: US Treasury bond limit buy
                value:
                  symbol: 912797MU8
                  side: buy
                  type: limit
                  time_in_force: day
                  quantity: '10000'
                  limit_price: '99.875'
      responses:
        '201':
          description: Order accepted by the system.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Order'
              examples:
                pending_order:
                  summary: Order pending
                  value:
                    id: ord_01j9x8m2k7qpzwv3t5r6y8n0ab
                    object: order
                    created: 1748390400
                    livemode: false
                    metadata: {}
                    investor_id: inv_01j9x8m2k7qpzwv3t5r6y8n0cd
                    symbol: AAPL
                    currency: USD
                    side: buy
                    type: market
                    time_in_force: day
                    quantity: '10'
                    status: pending
                    filled_quantity: '0'
                    remaining_quantity: '10'
                    average_price: '0.00'
                    submitted_at: '2026-05-11T14:30:00Z'
                    filled_at: null
                    cancelled_at: null
                    failure_reason: null
        '400':
          $ref: '#/components/responses/BadRequestError'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
    get:
      tags:
        - Trading
      summary: List orders for an investor
      operationId: listOrders
      parameters:
        - $ref: '#/components/parameters/InvestorIdPath'
        - name: status
          in: query
          required: false
          schema:
            type: string
            enum:
              - open
              - pending
              - filled
              - partial
              - cancelled
              - failed
            description: |
              Filter orders by status. Use 'open' to retrieve all orders that are pending, submitted, or otherwise not yet in a terminal state.
        - name: symbol
          in: query
          required: false
          schema:
            type: string
        - name: side
          in: query
          required: false
          schema:
            type: string
            enum:
              - buy
              - sell
        - name: class
          in: query
          required: false
          schema:
            type: string
            description: |
              Filter orders by asset class name (case-insensitive). Common values: equity, bond, etf.
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
        - name: offset
          in: query
          required: false
          schema:
            type: integer
            minimum: 0
      responses:
        '200':
          description: List of orders.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/ListEnvelope'
                  - type: object
                    properties:
                      data:
                        type: array
                        items:
                          $ref: '#/components/schemas/Order'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /investors/{investor_id}/orders/{order_id}:
    get:
      tags:
        - Trading
      summary: Get an order by id
      operationId: getOrder
      parameters:
        - $ref: '#/components/parameters/InvestorIdPath'
        - $ref: '#/components/parameters/OrderIdPath'
      responses:
        '200':
          description: Order retrieved.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Order'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /investors/{investor_id}/orders/{order_id}/cancel:
    post:
      tags:
        - Trading
      summary: Cancel an open order
      operationId: cancelOrder
      parameters:
        - $ref: '#/components/parameters/InvestorIdPath'
        - $ref: '#/components/parameters/OrderIdPath'
      responses:
        '200':
          description: Order cancellation requested.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Order'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /investors/{investor_id}/positions:
    get:
      tags:
        - Positions
      summary: List positions for an investor
      operationId: listPositions
      parameters:
        - $ref: '#/components/parameters/InvestorIdPath'
        - name: symbol
          in: query
          required: false
          schema:
            type: string
        - name: non_zero_only
          in: query
          required: false
          schema:
            type: boolean
            default: false
        - name: refresh_prices
          in: query
          required: false
          schema:
            type: boolean
            default: true
          description: |
            When true, fetches live prices from market-data providers. The
            response will include `price_source`, `price_confidence`, and
            `price_timestamp`. Adds latency; set to false to use stored
            values only.
      responses:
        '200':
          description: List of positions.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/ListEnvelope'
                  - type: object
                    properties:
                      data:
                        type: array
                        items:
                          $ref: '#/components/schemas/Position'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /investors/{investor_id}/positions/{position_id}:
    get:
      tags:
        - Positions
      summary: Retrieve a specific position
      operationId: getPosition
      parameters:
        - $ref: '#/components/parameters/InvestorIdPath'
        - name: position_id
          in: path
          required: true
          schema:
            type: string
          description: Prefixed public id of the position (e.g. `pos_…`).
        - name: refresh_prices
          in: query
          required: false
          schema:
            type: boolean
            default: true
      responses:
        '200':
          description: Position retrieved.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Position'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /assets/search:
    get:
      tags:
        - Assets
      summary: Search for assets by ticker, name, or partial match
      operationId: searchAssets
      parameters:
        - name: q
          in: query
          required: false
          schema:
            type: string
          description: Search query (ticker, name, or partial match). If not provided, returns all assets up to the limit.
        - name: status
          in: query
          required: false
          schema:
            type: string
            enum:
              - active
              - inactive
            default: active
          description: Filter by asset status. Defaults to 'active'.
        - name: class
          in: query
          required: false
          schema:
            type: string
            enum:
              - equity
              - etf
              - bond
              - bill
              - note
              - mutual_fund
              - derivative
              - cryptocurrency
              - commodity
              - real_estate
              - cash
          description: Filter by canonical instrument class.
        - name: country
          in: query
          required: false
          schema:
            type: string
          description: Filter by ISO 3166-1 alpha-2 country code (lower-case, e.g. `us`, `ng`).
        - name: asset_class
          in: query
          required: false
          deprecated: true
          schema:
            type: string
            enum:
              - us_equity
              - crypto
              - us_option
              - ng_equity
              - ng_bond
              - ng_etf
          description: |
            **Deprecated.** Combined legacy classifier accepted during the
            asset-class refactor. Prefer `class` + `country`.
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 50
          description: Maximum number of results to return. Defaults to 50, maximum is 100.
      responses:
        '200':
          description: List of matching assets
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/AssetSearchResult'
                  count:
                    type: integer
                    description: Number of results returned
              examples:
                search_results:
                  summary: Search results for AAPL
                  value:
                    data:
                      - id: b0b6dd9d-8b9b-48b9-bbb8-bbbb49bb1bbb
                        class: us_equity
                        market: NASDAQ
                        symbol: AAPL
                        name: Apple Inc.
                        status: active
                        tradable: true
                        marginable: true
                        shortable: true
                        easy_to_borrow: true
                        fractionable: true
                        currency: USD
                      - id: c1c7ee0e-9c0c-59c0-ccc9-cccc5acc2ccc
                        class: us_equity
                        market: NYSE
                        symbol: AAPL
                        name: Apple Inc. Class A
                        status: active
                        tradable: true
                        marginable: true
                        shortable: true
                        easy_to_borrow: true
                        fractionable: true
                        currency: USD
                    count: 2
        '400':
          $ref: '#/components/responses/BadRequestError'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '500':
          $ref: '#/components/responses/InternalServerError'
  /assets:
    get:
      tags:
        - Assets
      summary: List all assets with optional filtering
      operationId: listAssets
      parameters:
        - name: status
          in: query
          required: false
          schema:
            type: string
            enum:
              - active
              - inactive
            default: active
          description: Filter by asset status. Defaults to 'active'.
        - name: class
          in: query
          required: false
          schema:
            type: string
            enum:
              - equity
              - etf
              - bond
              - bill
              - note
              - mutual_fund
              - derivative
              - cryptocurrency
              - commodity
              - real_estate
              - cash
          description: Filter by canonical instrument class.
        - name: country
          in: query
          required: false
          schema:
            type: string
          description: Filter by ISO 3166-1 alpha-2 country code (lower-case, e.g. `us`, `ng`).
        - name: asset_class
          in: query
          required: false
          deprecated: true
          schema:
            type: string
            enum:
              - us_equity
              - crypto
              - us_option
              - ng_equity
              - ng_bond
              - ng_etf
          description: |
            **Deprecated.** Combined legacy classifier accepted during the
            asset-class refactor. Prefer `class` + `country`.
        - name: tradable
          in: query
          required: false
          schema:
            type: boolean
          description: Filter for assets that are currently tradable.
      responses:
        '200':
          description: List of assets
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/AssetSearchResult'
              examples:
                asset_list:
                  summary: List of active US equity assets
                  value:
                    - id: b0b6dd9d-8b9b-48b9-bbb8-bbbb49bb1bbb
                      class: us_equity
                      market: NASDAQ
                      symbol: AAPL
                      name: Apple Inc.
                      status: active
                      tradable: true
                      marginable: true
                      shortable: true
                      easy_to_borrow: true
                      fractionable: true
                      currency: USD
                    - id: d2d8ff1f-ad1d-6ad1-ddd0-dddd6bdd3ddd
                      class: us_equity
                      market: NASDAQ
                      symbol: MSFT
                      name: Microsoft Corporation
                      status: active
                      tradable: true
                      marginable: true
                      shortable: true
                      easy_to_borrow: true
                      fractionable: true
                      currency: USD
                    - id: e3e9gg2g-be2e-7be2-eee1-eeee7cee4eee
                      class: us_equity
                      market: NYSE
                      symbol: GOOGL
                      name: Alphabet Inc. Class A
                      status: active
                      tradable: true
                      marginable: true
                      shortable: true
                      easy_to_borrow: true
                      fractionable: true
                      currency: USD
        '400':
          $ref: '#/components/responses/BadRequestError'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '500':
          $ref: '#/components/responses/InternalServerError'
  /assets/chart:
    get:
      tags:
        - Assets
      summary: Get historical chart/bar data for an asset
      operationId: getChart
      parameters:
        - name: symbol
          in: query
          required: true
          schema:
            type: string
          description: Asset ticker symbol (e.g., AAPL, MSFT, BTCUSD)
          example: AAPL
        - name: timeframe
          in: query
          required: true
          schema:
            type: string
            enum:
              - 1Min
              - 5Min
              - 15Min
              - 30Min
              - 1Hour
              - 1Day
              - 1Week
              - 1Month
          description: Bar timeframe
          example: 1Day
        - name: start
          in: query
          required: false
          schema:
            type: string
            format: date-time
          description: Start date/time (ISO 8601 format). If not provided, returns most recent bars up to limit.
          example: '2025-01-01T00:00:00Z'
        - name: end
          in: query
          required: false
          schema:
            type: string
            format: date-time
          description: End date/time (ISO 8601 format). If not provided, uses current time.
          example: '2025-01-31T23:59:59Z'
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 10000
            default: 100
          description: Maximum number of bars to return. Defaults to 100, maximum is 10000.
        - name: adjustment
          in: query
          required: false
          schema:
            type: string
            enum:
              - raw
              - split
              - dividend
              - all
            default: raw
          description: Corporate action adjustment. 'raw' = no adjustment, 'split' = split adjusted, 'dividend' = dividend adjusted, 'all' = both adjusted.
        - name: feed
          in: query
          required: false
          schema:
            type: string
            enum:
              - iex
              - sip
              - otc
            default: iex
          description: Data feed source. 'iex' = IEX (free), 'sip' = SIP (premium), 'otc' = OTC.
      responses:
        '200':
          description: Chart data with historical bars
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/ChartResponse'
              examples:
                daily_chart:
                  summary: Daily chart data for AAPL
                  value:
                    data:
                      symbol: AAPL
                      bars:
                        - timestamp: '2025-01-15T16:00:00Z'
                          open: 175.25
                          high: 177.5
                          low: 174.8
                          close: 176.75
                          volume: 5000000
                          tradeCount: 12500
                          volumeWeightedAveragePrice: 176.2
                        - timestamp: '2025-01-14T16:00:00Z'
                          open: 174
                          high: 175.5
                          low: 173.5
                          close: 175.25
                          volume: 4800000
                          tradeCount: 12000
                          volumeWeightedAveragePrice: 174.75
                        - timestamp: '2025-01-13T16:00:00Z'
                          open: 173.5
                          high: 174.8
                          low: 172.9
                          close: 174
                          volume: 5200000
                          tradeCount: 13000
                          volumeWeightedAveragePrice: 173.9
                      nextPageToken: null
        '400':
          $ref: '#/components/responses/BadRequestError'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '500':
          $ref: '#/components/responses/InternalServerError'
  /assets/{symbol}:
    get:
      tags:
        - Assets
      summary: Get a single asset by symbol/ticker
      description: |
        Looks up an asset by symbol across all supported markets and providers.

        **Resolution flow:**
        1. Checks database for cached asset
        2. If not found or stale, queries appropriate provider based on market hint
        3. If no market hint, searches all available providers (Alpaca for US, Naya for Nigeria)
        4. Returns asset with current price data

        **Supported markets:**
        - US: XNAS (NASDAQ), XNYS (NYSE), BATS, ARCA, OTC
        - Nigeria: XNSA (Nigerian Stock Exchange)
      operationId: getAssetBySymbol
      parameters:
        - name: symbol
          in: path
          required: true
          schema:
            type: string
          description: Asset ticker symbol (e.g., AAPL, MSFT, DANGOTE)
          example: AAPL
        - name: market
          in: query
          required: false
          schema:
            type: string
            enum:
              - XNAS
              - XNYS
              - BATS
              - ARCA
              - OTC
              - XNSA
          description: |
            Optional market hint for faster lookup. If provided, only the corresponding 
            provider is queried. Without this hint, all providers are searched.
          example: XNAS
      responses:
        '200':
          description: Asset information with current price data
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/AssetSearchResult'
              examples:
                asset_details:
                  summary: Asset details for AAPL
                  value:
                    data:
                      id: b0b6dd9d-8b9b-48b9-bbb8-bbbb49bb1bbb
                      class: us_equity
                      market: XNAS
                      symbol: AAPL
                      name: Apple Inc.
                      status: active
                      tradable: true
                      marginable: true
                      shortable: true
                      easy_to_borrow: true
                      fractionable: true
                      currency: USD
                      price: 178.5
                      change: 1.5
                      changePercent: 0.85
                      previousClose: 177
                      bidPrice: 178.48
                      askPrice: 178.52
        '400':
          $ref: '#/components/responses/BadRequestError'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
        '500':
          $ref: '#/components/responses/InternalServerError'
  /investors/{investor_id}/funding-sources:
    get:
      tags:
        - Funding Sources
      summary: List funding sources for an investor
      description: |
        Retrieves all connected funding sources (bank accounts) for a
        specific investor. Supports both Plaid-connected and manually-added
        bank accounts. Filter by type with `?type=plaid|manual|all`.
      operationId: getFundingSources
      parameters:
        - $ref: '#/components/parameters/parameters-InvestorIdPath'
        - name: type
          in: query
          required: false
          schema:
            type: string
            enum:
              - plaid
              - manual
              - all
            default: all
      responses:
        '200':
          description: Funding sources retrieved successfully.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/ListEnvelope'
                  - type: object
                    properties:
                      data:
                        type: array
                        items:
                          $ref: '#/components/schemas/FundingSource'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '403':
          $ref: '#/components/responses/ForbiddenError'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /investors/{investor_id}/funding-sources/{id}:
    patch:
      tags:
        - Funding Sources
      summary: Update a funding source
      description: |
        Partial update to a manual / wire funding source. Used to complete
        or correct a source post-connect — the `connect` flow accepts
        partial info, so wire payout details (bank, account, address) are
        commonly filled in here before the source can be used for an
        international-wire withdrawal. Absent fields are left untouched;
        `metadata` merges into the existing object.

        Plaid-connected funding sources cannot be edited — their account
        details are managed by Plaid (returns 400). To change a Plaid-linked
        account, disconnect and reconnect.
      operationId: updateFundingSource
      parameters:
        - $ref: '#/components/parameters/parameters-InvestorIdPath'
        - name: id
          in: path
          required: true
          schema:
            type: string
          description: Prefixed public id of the funding source (e.g. `fs_…`).
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              minProperties: 1
              additionalProperties: false
              properties:
                bank_name:
                  type: string
                account_holder_name:
                  type: string
                bank_account_type:
                  type: string
                  enum:
                    - CHECKING
                    - SAVINGS
                account_number:
                  type: string
                routing_number:
                  type: string
                  description: 9-digit US ABA routing number.
                swift_code:
                  type: string
                beneficiary_address:
                  type: string
                bank_code:
                  type: string
                country:
                  type: string
                  description: ISO 3166-1 alpha-2.
                currency:
                  type: string
                  description: ISO 4217 (3-letter).
                address_line_1:
                  type: string
                city:
                  type: string
                region:
                  type: string
                postal_code:
                  type: string
                iban:
                  type: string
                wire_routing_kind:
                  type: string
                metadata:
                  type: object
                  additionalProperties: true
            examples:
              complete_wire_payout:
                summary: Complete wire payout details before an international-wire withdrawal
                value:
                  bank_name: Deutsche Bank
                  account_holder_name: Jane Doe
                  account_number: '0123456789'
                  swift_code: DEUTDEFF
                  address_line_1: 123 Hauptstrasse
                  city: Berlin
                  country: DE
                  currency: EUR
      responses:
        '200':
          description: Funding source updated.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FundingSource'
        '400':
          description: Validation error, or attempt to edit a Plaid-connected source.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
    delete:
      tags:
        - Funding Sources
      summary: Disconnect a funding source
      description: |
        Disconnects (soft-deletes) a connected funding source. Returns the
        standard delete shape `{ id, object: "funding_source",
        deleted: true }`.
      operationId: disconnectFundingSource
      parameters:
        - $ref: '#/components/parameters/parameters-InvestorIdPath'
        - name: id
          in: path
          required: true
          schema:
            type: string
          description: Prefixed public id of the funding source (e.g. `fs_…`).
        - name: type
          in: query
          required: false
          schema:
            type: string
            enum:
              - plaid
              - manual
            default: plaid
      responses:
        '200':
          description: Funding source disconnected.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DeletedFundingSource'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /investors/{investor_id}/funding-sources/plaid/link-token:
    post:
      tags:
        - Funding Sources
      summary: Create a Plaid Link token
      description: |
        Creates a Plaid Link token for initializing Plaid Link.

        **Two integration options:**
        1. **SDK Integration** (default): use the `link_token` with Plaid Link SDK in your mobile/web app.
        2. **Hosted Link**: set `enable_hosted_link: true` to get a `hosted_link_url` that redirects users to a Plaid-hosted page. Users complete the flow on Plaid's site and are redirected back to your application.
      operationId: createPlaidLinkToken
      parameters:
        - $ref: '#/components/parameters/parameters-InvestorIdPath'
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateLinkTokenRequest'
            examples:
              sdk:
                summary: Get a link_token for Plaid Link SDK
                value:
                  enable_hosted_link: false
              hosted:
                summary: Get a hosted_link_url for the Plaid-hosted flow
                value:
                  enable_hosted_link: true
      responses:
        '200':
          description: Link token created successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LinkTokenResponse'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /investors/{investor_id}/funding-sources/connect:
    post:
      tags:
        - Funding Sources
      summary: Connect a funding source
      description: |
        Connect a funding source to an investor. Two flows:

        - **Plaid** (`type: plaid`): exchange a public token from Plaid Link;
          one or more bank accounts become available as funding sources.
          The response is a list envelope (one entry per linked account).
        - **Manual** (`type: manual`): supply bank details directly. The
          response is a single funding-source resource.
      operationId: connectFundingSource
      parameters:
        - $ref: '#/components/parameters/parameters-InvestorIdPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ConnectFundingSourceRequest'
            examples:
              plaid:
                summary: Connect via a Plaid public_token from Plaid Link
                value:
                  type: plaid
                  public_token: public-sandbox-1234abcd-5678-90ef
              manual_wire:
                summary: Connect a manual international-wire payout destination
                value:
                  type: manual
                  bank_name: Deutsche Bank
                  account_holder_name: Jane Doe
                  account_number: '0123456789'
                  swift_code: DEUTDEFF
                  iban: DE89370400440532013000
                  country: DE
                  currency: EUR
                  address_line_1: 123 Hauptstrasse
                  city: Berlin
                  postal_code: '10115'
              manual_us_ach:
                summary: Connect a manual US ACH bank account
                value:
                  type: manual
                  bank_name: Chase
                  account_holder_name: Jane Doe
                  account_number: '000123456789'
                  routing_number: '021000021'
                  bank_account_type: CHECKING
                  country: US
                  currency: USD
      responses:
        '201':
          description: Funding source(s) connected successfully.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/FundingSource'
                  - allOf:
                      - $ref: '#/components/schemas/ListEnvelope'
                      - type: object
                        properties:
                          data:
                            type: array
                            items:
                              $ref: '#/components/schemas/FundingSource'
        '400':
          $ref: '#/components/responses/BadRequestError'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /banks:
    get:
      tags:
        - Funding Sources
      summary: List banks by country
      description: |
        Returns a list of banks for a specific country with their names and codes.
        Use the ISO 3166-1 alpha-2 country code (e.g., NG for Nigeria).

        For manual connect, send `bank_name` from the selected row and optionally `bank_code` with the same `code` value.
      operationId: getBanksByCountry
      parameters:
        - name: country
          in: query
          required: true
          description: ISO 3166-1 alpha-2 country code (e.g., NG for Nigeria)
          schema:
            type: string
            example: NG
      responses:
        '200':
          description: Bank list retrieved successfully
          content:
            application/json:
              schema:
                type: object
                required:
                  - status
                  - data
                properties:
                  status:
                    type: string
                    example: success
                  data:
                    type: object
                    required:
                      - banks
                    properties:
                      banks:
                        type: array
                        items:
                          $ref: '#/components/schemas/Bank'
              examples:
                sample:
                  summary: Nigeria banks example
                  value:
                    status: success
                    data:
                      banks:
                        - name: Access Bank
                          code: '044'
                        - name: Kuda Bank
                          code: '50211'
        '400':
          $ref: '#/components/responses/BadRequestError'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
  /investors/{investor_id}/compliance/submit:
    post:
      tags:
        - Compliance
      summary: Submit a compliance check result
      description: |
        Submit the result of an async verification flow (e.g. Persona inquiry
        SDK, Dojah widget) as an alternative to webhook-based completion.
        `provider_payload` carries the provider's callback/completion data.
      operationId: submitComplianceCheck
      parameters:
        - $ref: '#/components/parameters/parameters-InvestorIdPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SubmitComplianceCheckRequest'
            example:
              workflow_id: cw_01j9x8m2k7qpzwv3t5r6y8n0ab
              check_type: identity_verification
              provider_payload:
                event_type: inquiry.approved
                inquiry_id: inq_abc123def456
                status: approved
      responses:
        '200':
          description: Check result processed successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ComplianceCheckResponse'
        '400':
          $ref: '#/components/responses/BadRequestError'
        '404':
          $ref: '#/components/responses/NotFoundError'
        '409':
          $ref: '#/components/responses/ConflictError'
  /investors/{investor_id}/compliance/restart:
    post:
      tags:
        - Compliance
      summary: Restart the compliance workflow for an investor
      description: |
        Re-initiates a fresh compliance workflow. Useful when a prior workflow
        was rejected and the investor needs to re-verify. Returns the new
        workflow with check statuses and SDK handoff data for async providers.
      operationId: restartComplianceWorkflow
      parameters:
        - $ref: '#/components/parameters/parameters-InvestorIdPath'
      responses:
        '200':
          description: Compliance workflow re-initiated successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ComplianceInitiationResponse'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /investors/{investor_id}/compliance/workflows/{workflow_id}:
    get:
      tags:
        - Compliance
      summary: Get a compliance workflow's status
      description: |
        Retrieves the current state of a compliance workflow and all its
        checks. Buildmarkets-native lowercase status vocabulary (`running` /
        `awaiting_review` / `approved` / `declined` / `suspended` / `expired`).
      operationId: getComplianceWorkflowStatus
      parameters:
        - $ref: '#/components/parameters/parameters-InvestorIdPath'
        - name: workflow_id
          in: path
          required: true
          schema:
            type: string
          description: Prefixed public id of the compliance workflow (e.g. `cw_…`).
      responses:
        '200':
          description: Workflow status retrieved successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ComplianceWorkflowResponse'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /disclosures:
    get:
      tags:
        - Disclosures
      summary: List disclosures
      description: |
        Returns every disclosure Buildmarkets surfaces to end-users — verbatim
        Alpaca regulated copy, Alpaca's reference PDF library (including
        the High Yield Cash / FDIC Bank Sweep variants), and Buildmarkets'
        platform disclosures.

        **No authentication required** — partners can hit this endpoint
        from un-authenticated screens (signup, onboarding intro) to
        render disclosure copy.

        Partners should cache the response by `version` per disclosure
        and re-fetch on each session boundary; when a `version` advances
        the partner must re-prompt the user for acknowledgement.

        The `text` field on `kind: verbatim_text` disclosures is
        regulated word-for-word copy. **Do not modify, translate, or
        truncate it.** Translations are permitted only if they match
        the source language word-for-word.
      operationId: listDisclosures
      security: []
      parameters:
        - name: source
          in: query
          required: false
          description: Filter by source. Omit for all.
          schema:
            type: string
            enum:
              - alpaca
              - bluum
        - name: route
          in: query
          required: false
          description: |
            Filter by onboarding route. `us` returns disclosures whose route
            is `us` OR `all`; same for `international`. `all` (default)
            returns every disclosure.
          schema:
            type: string
            enum:
              - all
              - us
              - international
            default: all
        - name: step
          in: query
          required: false
          description: |
            Filter to the disclosures the partner should surface at a
            specific point in the onboarding / enrollment flow.
          schema:
            type: string
            enum:
              - step_6_affiliations
              - step_7_w8_certification
              - step_9_broker_agreements
              - step_12_post_account
              - step_hyc_enrollment
              - step_fixed_income_enrollment
              - platform_signup
        - name: requires_acknowledgement
          in: query
          required: false
          description: |
            `true` returns only disclosures the partner must capture an
            explicit acknowledgement for (checkbox / "I Agree" button).
            `false` returns reference-only disclosures.
          schema:
            type: boolean
      responses:
        '200':
          description: Disclosure list.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/ListEnvelope'
                  - type: object
                    properties:
                      data:
                        type: array
                        items:
                          $ref: '#/components/schemas/Disclosure'
              examples:
                hyc:
                  summary: HYC enrollment disclosures (filtered)
                  value:
                    object: list
                    url: /v1/disclosures
                    has_more: false
                    data:
                      - object: disclosure
                        id: hyc_non_shariah_new_customer_ack
                        version: '2026-05-23'
                        source: alpaca
                        kind: verbatim_text
                        route: us
                        step: step_hyc_enrollment
                        title: HYC enrollment acknowledgement — new customer (Non-Shariah)
                        text: |
                          I have read, understood, and agree to be bound by Alpaca Securities LLC and Buildmarkets Invest LLC account terms, and all other terms, disclosures and disclaimers applicable to me, as referenced in the Alpaca Customer Agreement. I also acknowledge that I have been presented the Alpaca Securities LLC Bank Sweep Program Terms and Conditions.
                        requires_acknowledgement: true
                        agreement_key: null
                        source_reference: Tech Sign Off - Buildmarkets.xlsx, High Yield Cash 1.0 (new customer onboarding)
  /disclosures/{disclosure_id}:
    get:
      tags:
        - Disclosures
      summary: Get a single disclosure
      description: |
        Retrieve one disclosure by its stable `id`. Use this when the
        partner has cached an acceptance against a specific disclosure id
        and needs to refresh the copy/version.

        No authentication required.
      operationId: getDisclosure
      security: []
      parameters:
        - name: disclosure_id
          in: path
          required: true
          schema:
            type: string
          description: |
            The disclosure's stable id (e.g. `hyc_non_shariah_new_customer_ack`,
            `investor_agreement_ack`, `alpaca_library_form_crs`).
      responses:
        '200':
          description: Disclosure resource.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Disclosure'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /investors/{investor_id}/disclosures/acceptances:
    post:
      tags:
        - Disclosures
      summary: Record a disclosure acceptance
      description: |
        Records an end-user's explicit acceptance of a disclosure (the
        "checkbox click"). Used when the partner is recording the
        acknowledgement out-of-band from `POST /v1/investors` —
        for example, when the user accepts a disclosure in-app after
        their account was already created, or when re-prompting after
        a `version` bump.

        For Alpaca-required acknowledgements that map to an Alpaca
        agreement key (`customer_agreement`, `w8ben_certification`),
        prefer submitting via the `signed_agreements[]` array on
        `POST /v1/investors` so Alpaca receives the acceptance at
        account-create time. Use this endpoint for post-hoc acceptances
        or Buildmarkets-only disclosures.
      operationId: recordDisclosureAcceptance
      parameters:
        - $ref: '#/components/parameters/components-parameters-InvestorIdPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - disclosure_id
              properties:
                disclosure_id:
                  type: string
                  description: Stable id from the disclosure registry.
                  example: hyc_non_shariah_new_customer_ack
                version:
                  type: string
                  description: |
                    Version the user is acknowledging. If omitted the
                    server stamps the current version from the registry.
                  example: '2026-05-23'
                signed_at:
                  type: string
                  format: date-time
                  description: ISO-8601 timestamp of the click. Defaults to server time.
                ip_address:
                  type: string
                  description: Client IP that performed the click. Defaults to request IP.
                user_agent:
                  type: string
                  description: Client user-agent string. Defaults to the request User-Agent header.
                actor_ref:
                  type: string
                  description: Partner-defined reference for the acting user (e.g. session id, dashboard user id).
                metadata:
                  type: object
                  additionalProperties: true
            examples:
              hyc_enrollment:
                summary: User opted in to the FDIC Sweep program
                value:
                  disclosure_id: hyc_non_shariah_new_customer_ack
                  signed_at: '2026-05-23T15:04:11Z'
              advisory:
                summary: User accepted Buildmarkets' Form ADV disclosure
                value:
                  disclosure_id: bluum_advisory_disclosure
      responses:
        '201':
          description: Acceptance recorded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DisclosureAcceptance'
        '400':
          $ref: '#/components/responses/BadRequestError'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
    get:
      tags:
        - Disclosures
      summary: List an investor's disclosure acceptances
      description: |
        Returns every recorded acceptance for the investor — useful for
        rendering an audit trail or confirming the user is on the
        current `version` of a disclosure before allowing access to a
        product (e.g. HYC enrollment, margin trading).
      operationId: listDisclosureAcceptances
      parameters:
        - $ref: '#/components/parameters/components-parameters-InvestorIdPath'
        - name: disclosure_id
          in: query
          required: false
          schema:
            type: string
          description: Restrict to acceptances of a specific disclosure id.
      responses:
        '200':
          description: Acceptance list.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/ListEnvelope'
                  - type: object
                    properties:
                      data:
                        type: array
                        items:
                          $ref: '#/components/schemas/DisclosureAcceptance'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /investors/{investor_id}/cash-sweep/enroll:
    post:
      tags:
        - Cash Sweep
      summary: Enroll in cash sweep
      description: |
        Enroll an investor's brokerage account in the High Yield Cash (HYC) / FDIC
        Bank Sweep program. The account must be ACTIVE, fully-disclosed, and have a
        customer agreement at or above the minimum required version.

        Required disclosures can be accepted inline via `disclosure_acceptance`, or
        pre-recorded via `POST /v1/investors/{investor_id}/disclosures/acceptances`.
        If disclosures are missing and `disclosure_acceptance` is not provided, the
        endpoint returns 400 with the list of required disclosure IDs and their text.
      operationId: enrollCashSweep
      parameters:
        - $ref: '#/components/parameters/cash-sweep_components-parameters-InvestorIdPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/EnrollCashSweepRequest'
      responses:
        '200':
          description: Enrollment initiated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CashSweepEnrollmentResponse'
        '400':
          description: Validation error or missing disclosures
        '404':
          description: Investor or brokerage account not found
        '409':
          description: Already enrolled
    delete:
      tags:
        - Cash Sweep
      summary: Unenroll from cash sweep
      description: |
        Unenroll the investor from the cash sweep program. Requests submitted
        before 11:45 AM ET are processed same-day; after the cutoff they process
        the following business day.
      operationId: unenrollCashSweep
      parameters:
        - $ref: '#/components/parameters/cash-sweep_components-parameters-InvestorIdPath'
      responses:
        '200':
          description: Unenrollment initiated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CashSweepEnrollmentResponse'
        '404':
          description: Investor not found
        '409':
          description: Not enrolled
  /investors/{investor_id}/cash-sweep:
    get:
      tags:
        - Cash Sweep
      summary: Get cash sweep enrollment
      description: Returns the current cash sweep enrollment for the investor.
      operationId: getCashSweepEnrollment
      parameters:
        - $ref: '#/components/parameters/cash-sweep_components-parameters-InvestorIdPath'
      responses:
        '200':
          description: Enrollment details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CashSweepEnrollmentResponse'
        '404':
          description: No enrollment found
  /investors/{investor_id}/cash-sweep/tier:
    put:
      tags:
        - Cash Sweep
      summary: Reassign APR tier
      description: |
        Change the APR tier for an actively enrolled account. The account must
        have status `active`.
      operationId: reassignCashSweepTier
      parameters:
        - $ref: '#/components/parameters/cash-sweep_components-parameters-InvestorIdPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ReassignTierRequest'
      responses:
        '200':
          description: Tier reassigned
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CashSweepEnrollmentResponse'
        '404':
          description: Investor not found
        '409':
          description: Not actively enrolled
  /investors/{investor_id}/cash-sweep/interest:
    get:
      tags:
        - Cash Sweep
      summary: Get interest history
      description: |
        Returns end-of-day cash interest accrual entries for the investor's
        enrolled brokerage account. Supports date filtering and pagination.
      operationId: getCashSweepInterestHistory
      parameters:
        - $ref: '#/components/parameters/cash-sweep_components-parameters-InvestorIdPath'
        - name: date
          in: query
          description: Exact date (YYYY-MM-DD)
          schema:
            type: string
            format: date
        - name: after
          in: query
          description: Return entries after this date (YYYY-MM-DD)
          schema:
            type: string
            format: date
        - name: before
          in: query
          description: Return entries before this date (YYYY-MM-DD)
          schema:
            type: string
            format: date
        - name: page_size
          in: query
          description: Number of entries per page (1–10000)
          schema:
            type: integer
            minimum: 1
            maximum: 10000
        - name: page_token
          in: query
          description: Pagination cursor from a previous response
          schema:
            type: string
      responses:
        '200':
          description: Interest history entries
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InterestHistoryListResponse'
        '404':
          description: Investor or enrollment not found
  /cash-sweep/tiers:
    get:
      tags:
        - Cash Sweep
      summary: List APR tiers
      description: |
        Returns all available APR tiers for the cash sweep program. Not
        investor-scoped — tiers are platform-wide.
      operationId: listCashSweepAprTiers
      responses:
        '200':
          description: APR tiers
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AprTierListResponse'
  /webhooks/event-types:
    get:
      tags:
        - Webhooks
      summary: Get all available event types
      description: |
        Retrieves all event types that can be subscribed to via webhooks.

        **Available events:**

        | Event | Description |
        |-------|-------------|
        | `account.created` | New investor account created |
        | `account.updated` | Account details updated |
        | `transfer.deposit.initiated` | Deposit initiated, awaiting processing |
        | `transfer.deposit.processing` | Deposit being processed by provider |
        | `transfer.deposit.received` | Funds received (manual transfers) |
        | `transfer.deposit.completed` | Deposit completed, wallet credited |
        | `transfer.deposit.expired` | Pending deposit expired |
        | `transfer.deposit.canceled` | Deposit cancelled |
        | `transfer.deposit.failed` | Deposit failed |
        | `transfer.withdrawal.initiated` | Withdrawal initiated |
        | `transfer.withdrawal.processing` | Withdrawal being processed |
        | `transfer.withdrawal.submitted` | Withdrawal submitted to provider |
        | `transfer.withdrawal.completed` | Withdrawal completed, funds sent |
        | `transfer.withdrawal.canceled` | Withdrawal cancelled |
        | `transfer.withdrawal.failed` | Withdrawal failed |
        | `order.created` | Trading order created |
        | `order.filled` | Order fully filled |
        | `order.failed` | Order execution failed |
        | `kyc.submission.created` | KYC submission received |
        | `kyc.verification.approved` | KYC verification approved |
        | `kyc.verification.rejected` | KYC verification rejected |
      operationId: getAvailableEventTypes
      responses:
        '200':
          description: Event types retrieved successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: success
                  data:
                    type: object
                    properties:
                      eventTypes:
                        type: array
                        items:
                          $ref: '#/components/schemas/EventType'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
  /webhooks:
    get:
      tags:
        - Webhooks
      summary: List all webhooks
      description: Retrieves all webhooks configured for the authenticated tenant.
      operationId: listWebhooks
      responses:
        '200':
          description: Webhooks retrieved successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: success
                  data:
                    type: object
                    properties:
                      webhooks:
                        type: array
                        items:
                          $ref: '#/components/schemas/Webhook'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
    post:
      tags:
        - Webhooks
      summary: Create a new webhook
      description: Creates a new webhook subscription.
      operationId: createWebhook
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateWebhookRequest'
            examples:
              default:
                summary: Subscribe to order and transfer events
                value:
                  name: Production webhook
                  url: https://api.example.com/bluum/webhooks
                  description: Delivers order + transfer lifecycle events
                  eventTypeNames:
                    - order.filled
                    - order.canceled
                    - transfer.deposit.completed
                    - transfer.withdrawal.completed
      responses:
        '201':
          description: Webhook created successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: success
                  message:
                    type: string
                  data:
                    type: object
                    properties:
                      webhook:
                        $ref: '#/components/schemas/Webhook'
        '400':
          $ref: '#/components/responses/BadRequestError'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
  /webhooks/{webhook_id}:
    patch:
      tags:
        - Webhooks
      summary: Update a webhook
      description: Updates an existing webhook subscription.
      operationId: updateWebhook
      parameters:
        - name: webhook_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                eventTypeNames:
                  type: array
                  items:
                    type: string
                name:
                  type: string
                url:
                  type: string
                  format: uri
                description:
                  type: string
                  nullable: true
                status:
                  type: string
                  enum:
                    - ACTIVE
                    - INACTIVE
            examples:
              pause:
                summary: Pause webhook delivery
                value:
                  status: INACTIVE
              retarget:
                summary: Change endpoint URL
                value:
                  url: https://api.example.com/bluum/webhooks/v2
      responses:
        '200':
          description: Webhook updated successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: success
                  data:
                    type: object
                    properties:
                      webhook:
                        $ref: '#/components/schemas/Webhook'
        '400':
          $ref: '#/components/responses/BadRequestError'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
    delete:
      tags:
        - Webhooks
      summary: Delete a webhook
      description: Deletes a webhook subscription.
      operationId: deleteWebhook
      parameters:
        - name: webhook_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '204':
          description: Webhook deleted successfully
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /investors/{investor_id}/deposits:
    post:
      tags:
        - Transfers
      summary: Initiate a new deposit
      description: |
        Creates a new deposit request for the specified account.
        Supports multiple funding methods: ACH, Manual Bank Transfer, Wire, Mobile Money, and Card.
      operationId: initiateDeposit
      parameters:
        - $ref: '#/components/parameters/transfers_components-parameters-InvestorIdPath'
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateDepositRequest'
            examples:
              ach:
                summary: ACH deposit from a connected Plaid funding source
                value:
                  amount: '1000.00'
                  currency: USD
                  method: ach
                  funding_source_id: fs_01j9x8m2k7qpzwv3t5r6y8n0ef
              wire:
                summary: International wire deposit (returns funding instructions)
                value:
                  amount: '5000.00'
                  currency: USD
                  method: international_wire
              manual:
                summary: Manual bank transfer with reference code
                value:
                  amount: '1000.00'
                  currency: USD
                  method: manual_bank_transfer
      responses:
        '201':
          description: Deposit initiated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DepositResponse'
              examples:
                ach_deposit:
                  summary: ACH deposit initiated
                  value:
                    id: dep_01j9x8m2k7qpzwv3t5r6y8n0ab
                    object: deposit
                    created: 1747776000
                    livemode: false
                    method: ach
                    status: pending
                    amount: '1000.00'
                    currency: USD
                    description: null
                    method_details:
                      provider_name: alpaca
                      transfer_id: adc51a07-1f60-4616-abbc-4c67f0c7b047
                      alpaca_status: QUEUED
                    investor_id: inv_01j9x8m2k7qpzwv3t5r6y8n0ab
                    wallet_id: wlt_01j9x8m2k7qpzwv3t5r6y8n0cd
                    funding_source_id: fs_01j9x8m2k7qpzwv3t5r6y8n0ef
                    initiated_at: '2026-05-20T10:00:00.000Z'
                    received_at: null
                    completed_at: null
                    expires_at: null
                    failure_reason: null
                manual_bank_transfer_deposit:
                  summary: Manual bank transfer deposit
                  value:
                    id: dep_01j9x8m2k7qpzwv3t5r6y8n0gh
                    object: deposit
                    created: 1747776000
                    livemode: false
                    method: manual_bank_transfer
                    status: pending
                    amount: '5000.00'
                    currency: USD
                    description: Initial funding
                    method_details:
                      reference_code: BLM-A1B2C3D4
                      bank_details:
                        bank_name: First National Bank
                        bank_address: 123 Financial District, NY
                        account_name: Buildmarkets LLC
                        account_number: '****5678'
                        routing_number: '021000021'
                        swift_code: FNBKUS33
                        instructions: Include reference code "BLM-A1B2C3D4" in your transfer memo/description.
                      expires_at: '2026-05-27T10:00:00.000Z'
                    investor_id: inv_01j9x8m2k7qpzwv3t5r6y8n0ab
                    wallet_id: wlt_01j9x8m2k7qpzwv3t5r6y8n0cd
                    funding_source_id: null
                    initiated_at: '2026-05-20T10:00:00.000Z'
                    received_at: null
                    completed_at: null
                    expires_at: '2026-05-27T10:00:00.000Z'
                    failure_reason: null
        '400':
          $ref: '#/components/responses/BadRequestError'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '403':
          $ref: '#/components/responses/ForbiddenError'
        '404':
          $ref: '#/components/responses/NotFoundError'
        '409':
          description: Conflict - Idempotency key already used
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          $ref: '#/components/responses/InternalServerError'
    get:
      tags:
        - Transfers
      summary: List deposits for an account
      description: Returns a list of deposits for the specified account with optional filters.
      operationId: listDeposits
      parameters:
        - $ref: '#/components/parameters/transfers_components-parameters-InvestorIdPath'
        - name: method
          in: query
          required: false
          schema:
            type: string
            enum:
              - ach
              - manual_bank_transfer
              - wire
              - mobile_money
              - card
          description: Filter deposits by method.
        - name: status
          in: query
          required: false
          schema:
            type: string
            enum:
              - pending
              - processing
              - completed
              - cancelled
              - failed
          description: Filter deposits by status.
        - name: currency
          in: query
          required: false
          schema:
            type: string
            minLength: 3
            maxLength: 3
          description: Filter deposits by currency (3-letter ISO code).
        - name: date_from
          in: query
          required: false
          schema:
            type: string
            pattern: ^\d{4}-\d{2}-\d{2}$
          description: Filter deposits from this date (YYYY-MM-DD).
        - name: date_to
          in: query
          required: false
          schema:
            type: string
            pattern: ^\d{4}-\d{2}-\d{2}$
          description: Filter deposits to this date (YYYY-MM-DD).
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 50
          description: Maximum number of deposits to return.
        - name: offset
          in: query
          required: false
          schema:
            type: integer
            minimum: 0
            default: 0
          description: Number of deposits to skip for pagination.
      responses:
        '200':
          description: List of deposits for the account
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DepositListResponse'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '403':
          $ref: '#/components/responses/ForbiddenError'
        '404':
          $ref: '#/components/responses/NotFoundError'
        '500':
          $ref: '#/components/responses/InternalServerError'
  /investors/{investor_id}/deposits/{deposit_id}:
    get:
      tags:
        - Transfers
      summary: Get deposit details
      description: Returns details of a specific deposit.
      operationId: getDeposit
      parameters:
        - $ref: '#/components/parameters/transfers_components-parameters-InvestorIdPath'
        - $ref: '#/components/parameters/DepositIdPath'
      responses:
        '200':
          description: Deposit details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DepositResponse'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '403':
          $ref: '#/components/responses/ForbiddenError'
        '404':
          $ref: '#/components/responses/NotFoundError'
        '500':
          $ref: '#/components/responses/InternalServerError'
  /investors/{investor_id}/deposits/{deposit_id}/cancel:
    post:
      tags:
        - Transfers
      summary: Cancel a pending deposit
      description: |
        Cancels a deposit that is in a cancellable state (typically PENDING).
        Once cancelled, the deposit cannot be resumed.
      operationId: cancelDeposit
      parameters:
        - $ref: '#/components/parameters/transfers_components-parameters-InvestorIdPath'
        - $ref: '#/components/parameters/DepositIdPath'
      responses:
        '200':
          description: Deposit cancelled successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DepositResponse'
        '400':
          $ref: '#/components/responses/BadRequestError'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '403':
          $ref: '#/components/responses/ForbiddenError'
        '404':
          $ref: '#/components/responses/NotFoundError'
        '500':
          $ref: '#/components/responses/InternalServerError'
  /investors/{investor_id}/deposits/{deposit_id}/wire-details:
    get:
      tags:
        - Transfers
      summary: Download wire details PDF
      description: |
        Returns a formatted PDF document with wire transfer instructions for a manual bank transfer deposit.
        Includes domestic transfer details (and international if SWIFT code is configured).
        Only available for deposits with method `manual_bank_transfer`.
      operationId: getWireDetailsPdf
      parameters:
        - $ref: '#/components/parameters/transfers_components-parameters-InvestorIdPath'
        - $ref: '#/components/parameters/DepositIdPath'
      responses:
        '200':
          description: Wire details PDF document
          content:
            application/pdf:
              schema:
                type: string
                format: binary
        '400':
          $ref: '#/components/responses/BadRequestError'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '403':
          $ref: '#/components/responses/ForbiddenError'
        '404':
          $ref: '#/components/responses/NotFoundError'
        '500':
          $ref: '#/components/responses/InternalServerError'
  /investors/{investor_id}/withdrawals:
    post:
      tags:
        - Transfers
      summary: Initiate a new withdrawal
      description: |
        Creates a new withdrawal request from the specified account's wallet.
        Supports ACH and Wire transfer methods.
      operationId: initiateWithdrawal
      parameters:
        - $ref: '#/components/parameters/transfers_components-parameters-InvestorIdPath'
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateWithdrawalRequest'
            examples:
              ach:
                summary: ACH withdrawal to a connected Plaid funding source
                value:
                  amount: '500.00'
                  currency: USD
                  method: ach
                  funding_source_id: fs_01j9x8m2k7qpzwv3t5r6y8n0ef
              wire:
                summary: International wire withdrawal (requires a manual funding source with full wire payout details)
                value:
                  amount: '2500.00'
                  currency: USD
                  method: international_wire
                  funding_source_id: fs_01j9x8m2k7qpzwv3t5r6y8n0wr
      responses:
        '201':
          description: Withdrawal initiated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WithdrawalResponse'
              examples:
                ach_withdrawal:
                  summary: ACH withdrawal initiated
                  value:
                    id: wd_01j9x8m2k7qpzwv3t5r6y8n0ab
                    object: withdrawal
                    created: 1747776000
                    livemode: false
                    method: ach
                    status: pending
                    amount: '500.00'
                    currency: USD
                    description: Monthly withdrawal
                    method_details:
                      provider_name: alpaca
                      transfer_id: bef72b18-2g71-5727-bccd-5d78g1d8c158
                      alpaca_status: QUEUED
                    destination_details: null
                    investor_id: inv_01j9x8m2k7qpzwv3t5r6y8n0ab
                    wallet_id: wlt_01j9x8m2k7qpzwv3t5r6y8n0cd
                    funding_source_id: fs_01j9x8m2k7qpzwv3t5r6y8n0ef
                    initiated_at: '2026-05-20T10:00:00.000Z'
                    completed_at: null
                    failure_reason: null
        '400':
          $ref: '#/components/responses/BadRequestError'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '403':
          $ref: '#/components/responses/ForbiddenError'
        '404':
          $ref: '#/components/responses/NotFoundError'
        '409':
          description: Conflict - Idempotency key already used
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          $ref: '#/components/responses/InternalServerError'
    get:
      tags:
        - Transfers
      summary: List withdrawals for an account
      description: Returns a list of withdrawals for the specified account with optional filters.
      operationId: listWithdrawals
      parameters:
        - $ref: '#/components/parameters/transfers_components-parameters-InvestorIdPath'
        - name: method
          in: query
          required: false
          schema:
            type: string
            enum:
              - ach
              - wire
          description: Filter withdrawals by method.
        - name: status
          in: query
          required: false
          schema:
            type: string
            enum:
              - pending
              - processing
              - completed
              - cancelled
              - failed
          description: Filter withdrawals by status.
        - name: currency
          in: query
          required: false
          schema:
            type: string
            minLength: 3
            maxLength: 3
          description: Filter withdrawals by currency (3-letter ISO code).
        - name: date_from
          in: query
          required: false
          schema:
            type: string
            pattern: ^\d{4}-\d{2}-\d{2}$
          description: Filter withdrawals from this date (YYYY-MM-DD).
        - name: date_to
          in: query
          required: false
          schema:
            type: string
            pattern: ^\d{4}-\d{2}-\d{2}$
          description: Filter withdrawals to this date (YYYY-MM-DD).
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 50
          description: Maximum number of withdrawals to return.
        - name: offset
          in: query
          required: false
          schema:
            type: integer
            minimum: 0
            default: 0
          description: Number of withdrawals to skip for pagination.
      responses:
        '200':
          description: List of withdrawals for the account
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WithdrawalListResponse'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '403':
          $ref: '#/components/responses/ForbiddenError'
        '404':
          $ref: '#/components/responses/NotFoundError'
        '500':
          $ref: '#/components/responses/InternalServerError'
  /investors/{investor_id}/withdrawals/{withdrawal_id}:
    get:
      tags:
        - Transfers
      summary: Get withdrawal details
      description: Returns details of a specific withdrawal.
      operationId: getWithdrawal
      parameters:
        - $ref: '#/components/parameters/transfers_components-parameters-InvestorIdPath'
        - $ref: '#/components/parameters/WithdrawalIdPath'
      responses:
        '200':
          description: Withdrawal details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WithdrawalResponse'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '403':
          $ref: '#/components/responses/ForbiddenError'
        '404':
          $ref: '#/components/responses/NotFoundError'
        '500':
          $ref: '#/components/responses/InternalServerError'
  /investors/{investor_id}/withdrawals/{withdrawal_id}/cancel:
    post:
      tags:
        - Transfers
      summary: Cancel a pending withdrawal
      description: |
        Cancels a withdrawal that is in a cancellable state (typically PENDING).
        Once cancelled, the hold on funds is released back to the wallet.
      operationId: cancelWithdrawal
      parameters:
        - $ref: '#/components/parameters/transfers_components-parameters-InvestorIdPath'
        - $ref: '#/components/parameters/WithdrawalIdPath'
      responses:
        '200':
          description: Withdrawal cancelled successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WithdrawalResponse'
        '400':
          $ref: '#/components/responses/BadRequestError'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '403':
          $ref: '#/components/responses/ForbiddenError'
        '404':
          $ref: '#/components/responses/NotFoundError'
        '500':
          $ref: '#/components/responses/InternalServerError'
  /markets:
    get:
      summary: List available markets
      description: |
        Returns all available markets/exchanges with their details, trading hours,
        currency, and a compact `current_status` summary (live session state).

        These market reference endpoints are available to every tenant and are
        intentionally hosted outside `/market-data` (which represents the gated
        Market Data product covering live quotes, snapshots, and historical bars).
      operationId: listMarkets
      tags:
        - Markets
      parameters:
        - name: country
          in: query
          description: Filter by ISO 2-letter country code (e.g., US, NG)
          schema:
            type: string
        - name: status
          in: query
          description: Filter by market status
          schema:
            type: string
            enum:
              - active
              - inactive
            default: active
      responses:
        '200':
          description: List of markets
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: success
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/MarketResponse'
                  count:
                    type: integer
        '401':
          $ref: '#/components/responses/UnauthorizedError'
  /markets/{code}:
    get:
      summary: Get market details
      description: Get details for a specific market. Accepts both MIC codes (XNSA) and common codes (NGX). Includes a compact `current_status` summary.
      operationId: getMarket
      tags:
        - Markets
      parameters:
        - name: code
          in: path
          required: true
          description: Market identifier (MIC code like XNSA, or common code like NGX)
          schema:
            type: string
      responses:
        '200':
          description: Market details
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: success
                  data:
                    $ref: '#/components/schemas/MarketResponse'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /markets/{code}/status:
    get:
      summary: Get full live market status
      description: |
        Returns the full FIX-aligned trading session status (`PRE_OPEN`, `OPEN`,
        `EXTENDED`, `HALTED`, `PRE_CLOSE`, `CLOSED`, `REQUEST_REJECTED`), the day's
        schedule (pre-open, regular open/close, post-close, holiday/early-close
        flags), any active halts, and `extended_hours_supported` for the venue.
      operationId: getMarketStatus
      tags:
        - Markets
      parameters:
        - name: code
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Market status
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: success
                  data:
                    $ref: '#/components/schemas/MarketStatusResponse'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /markets/{code}/calendar:
    get:
      summary: Get market calendar
      description: Returns trading schedule and holidays for a market in a given year.
      operationId: getMarketCalendar
      tags:
        - Markets
      parameters:
        - name: code
          in: path
          required: true
          schema:
            type: string
        - name: year
          in: query
          description: Calendar year (defaults to current year)
          schema:
            type: integer
            example: 2026
      responses:
        '200':
          description: Market calendar
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: success
                  data:
                    $ref: '#/components/schemas/MarketCalendarResponse'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /markets/{code}/halts:
    get:
      summary: List halts for a market
      description: Returns active and (optionally) recent halts for a market. Includes both market-wide halts (symbol = null) and per-symbol halts.
      operationId: getMarketHalts
      tags:
        - Markets
      parameters:
        - name: code
          in: path
          required: true
          schema:
            type: string
        - name: active
          in: query
          description: When true, return only halts not yet resumed (resumedAt is null).
          schema:
            type: boolean
            default: false
        - name: since
          in: query
          description: ISO 8601 timestamp; only halts with startedAt at or after this point are returned.
          schema:
            type: string
            format: date-time
        - name: limit
          in: query
          schema:
            type: integer
            default: 100
            maximum: 500
      responses:
        '200':
          description: Halts list
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: success
                  data:
                    type: object
                    properties:
                      market_code:
                        type: string
                      halts:
                        type: array
                        items:
                          $ref: '#/components/schemas/MarketHaltResponse'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /markets/{code}/sessions:
    get:
      summary: Project upcoming session days
      description: Returns up to 90 future session days for a market (regular open/close, pre/post-market windows, holiday flags).
      operationId: getMarketSessions
      tags:
        - Markets
      parameters:
        - name: code
          in: path
          required: true
          schema:
            type: string
        - name: from
          in: query
          description: ISO 8601 start date. Defaults to today (market timezone).
          schema:
            type: string
            format: date-time
        - name: to
          in: query
          description: ISO 8601 end date. Defaults to from + limit days.
          schema:
            type: string
            format: date-time
        - name: limit
          in: query
          schema:
            type: integer
            default: 30
            maximum: 90
      responses:
        '200':
          description: Session projections
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: success
                  data:
                    type: object
                    properties:
                      market_code:
                        type: string
                      sessions:
                        type: array
                        items:
                          $ref: '#/components/schemas/MarketSessionDay'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /market-data/markets:
    get:
      summary: List available markets (alias)
      description: Alias of `GET /markets`. Available to every tenant — not subject to Market Data product gating.
      operationId: listMarketsViaMarketData
      tags:
        - Market Data
      parameters:
        - name: country
          in: query
          schema:
            type: string
        - name: status
          in: query
          schema:
            type: string
            enum:
              - active
              - inactive
            default: active
      responses:
        '200':
          description: List of markets
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: success
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/MarketResponse'
                  count:
                    type: integer
        '401':
          $ref: '#/components/responses/UnauthorizedError'
  /market-data/markets/{code}:
    get:
      summary: Get market details (alias)
      description: Alias of `GET /markets/{code}`. Available to every tenant — not subject to Market Data product gating.
      operationId: getMarketViaMarketData
      tags:
        - Market Data
      parameters:
        - name: code
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Market details
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: success
                  data:
                    $ref: '#/components/schemas/MarketResponse'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /market-data/markets/{code}/status:
    get:
      summary: Get full live market status (alias)
      description: Alias of `GET /markets/{code}/status`. Available to every tenant — not subject to Market Data product gating.
      operationId: getMarketStatusViaMarketData
      tags:
        - Market Data
      parameters:
        - name: code
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Market status
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: success
                  data:
                    $ref: '#/components/schemas/MarketStatusResponse'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /market-data/markets/{code}/calendar:
    get:
      summary: Get market calendar (alias)
      description: Alias of `GET /markets/{code}/calendar`. Available to every tenant — not subject to Market Data product gating.
      operationId: getMarketCalendarViaMarketData
      tags:
        - Market Data
      parameters:
        - name: code
          in: path
          required: true
          schema:
            type: string
        - name: year
          in: query
          schema:
            type: integer
            example: 2026
      responses:
        '200':
          description: Market calendar
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: success
                  data:
                    $ref: '#/components/schemas/MarketCalendarResponse'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /market-data/markets/{code}/halts:
    get:
      summary: List halts for a market (alias)
      description: Alias of `GET /markets/{code}/halts`. Available to every tenant — not subject to Market Data product gating.
      operationId: getMarketHaltsViaMarketData
      tags:
        - Market Data
      parameters:
        - name: code
          in: path
          required: true
          schema:
            type: string
        - name: active
          in: query
          schema:
            type: boolean
            default: false
        - name: since
          in: query
          schema:
            type: string
            format: date-time
        - name: limit
          in: query
          schema:
            type: integer
            default: 100
            maximum: 500
      responses:
        '200':
          description: Halts list
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: success
                  data:
                    type: object
                    properties:
                      market_code:
                        type: string
                      halts:
                        type: array
                        items:
                          $ref: '#/components/schemas/MarketHaltResponse'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /market-data/markets/{code}/sessions:
    get:
      summary: Project upcoming session days (alias)
      description: Alias of `GET /markets/{code}/sessions`. Available to every tenant — not subject to Market Data product gating.
      operationId: getMarketSessionsViaMarketData
      tags:
        - Market Data
      parameters:
        - name: code
          in: path
          required: true
          schema:
            type: string
        - name: from
          in: query
          schema:
            type: string
            format: date-time
        - name: to
          in: query
          schema:
            type: string
            format: date-time
        - name: limit
          in: query
          schema:
            type: integer
            default: 30
            maximum: 90
      responses:
        '200':
          description: Session projections
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: success
                  data:
                    type: object
                    properties:
                      market_code:
                        type: string
                      sessions:
                        type: array
                        items:
                          $ref: '#/components/schemas/MarketSessionDay'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /market-data/assets/search:
    get:
      summary: Search assets across markets
      description: Search for assets by ticker, name, or partial match across all supported markets.
      operationId: searchMarketDataAssets
      tags:
        - Market Data
      parameters:
        - name: q
          in: query
          required: true
          description: Search query (ticker symbol, company name, or partial match)
          schema:
            type: string
        - name: market
          in: query
          description: Filter by market (MIC code or common code)
          schema:
            type: string
        - name: class
          in: query
          description: Filter by canonical instrument class.
          schema:
            type: string
            enum:
              - equity
              - etf
              - bond
              - bill
              - note
              - mutual_fund
              - derivative
              - cryptocurrency
              - commodity
              - real_estate
              - cash
        - name: country
          in: query
          description: Filter by ISO 3166-1 alpha-2 country code (lower-case).
          schema:
            type: string
        - name: asset_class
          in: query
          deprecated: true
          description: |
            **Deprecated.** Combined legacy classifier accepted during the
            asset-class refactor. Prefer `class` + `country`.
          schema:
            type: string
            enum:
              - us_equity
              - crypto
              - us_option
              - ng_equity
              - ng_bond
              - ng_etf
        - name: limit
          in: query
          description: Maximum number of results
          schema:
            type: integer
            default: 50
            maximum: 100
      responses:
        '200':
          description: Search results
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: success
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/AssetSearchResult'
                  count:
                    type: integer
        '400':
          $ref: '#/components/responses/BadRequestError'
  /market-data/assets:
    get:
      summary: Get batch assets or list all assets
      description: |
        Returns asset with current price data. Two modes of operation:

        **Batch Mode (with symbols):** Pass comma-separated symbols to get details for specific assets.
        Maximum 20 symbols per request.

        **List Mode (no symbols):** Omit symbols to get a paginated list of all active assets.
        Use the `limit` parameter to control page size (default 20, max 100).
      operationId: getBatchAssets
      tags:
        - Market Data
      parameters:
        - name: symbols
          in: query
          required: false
          description: Comma-separated list of ticker symbols (max 20). If omitted, returns all assets.
          schema:
            type: string
            example: META,AAPL,TSLA
        - name: market
          in: query
          required: false
          description: Market hint to disambiguate symbols (e.g., XNAS, XNYS, XNSA)
          schema:
            type: string
            example: XNAS
        - name: limit
          in: query
          required: false
          description: Maximum number of assets to return (1-100, default 20). Only applies when symbols is omitted.
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
            example: 20
      responses:
        '200':
          description: List of asset profiles
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: success
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/AssetSearchResult'
                  count:
                    type: integer
                    description: Number of assets returned
        '400':
          $ref: '#/components/responses/BadRequestError'
  /market-data/assets/{symbol}:
    get:
      summary: Get asset profile with latest quote
      description: Returns asset details including the latest price data. Use the market query parameter to disambiguate symbols that exist on multiple exchanges.
      operationId: getMarketDataAssetProfile
      tags:
        - Market Data
      parameters:
        - name: symbol
          in: path
          required: true
          description: Asset ticker symbol
          schema:
            type: string
        - name: market
          in: query
          description: Market hint (MIC or common code) for disambiguation
          schema:
            type: string
      responses:
        '200':
          description: Asset profile
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: success
                  data:
                    $ref: '#/components/schemas/AssetSearchResult'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /market-data/assets/{symbol}/quote:
    get:
      summary: Get real-time quote
      description: Returns the latest price quote for an asset, including bid/ask, currency, confidence level, and data source.
      operationId: getMarketDataQuote
      tags:
        - Market Data
      parameters:
        - name: symbol
          in: path
          required: true
          schema:
            type: string
        - name: market
          in: query
          description: Market hint for disambiguation
          schema:
            type: string
      responses:
        '200':
          description: Price quote
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: success
                  data:
                    $ref: '#/components/schemas/QuoteResponse'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /market-data/assets/{symbol}/bars:
    get:
      summary: Get historical OHLCV bars
      description: |
        Returns historical price bars (OHLCV) for an asset. Currency is always included in the response.

        **Note:** For Nigerian market (NGX/XNSA) assets, only daily closing prices are available from the data provider.
        A `dataQuality` object is included in the response when limitations apply.
      operationId: getMarketDataBars
      tags:
        - Market Data
      parameters:
        - name: symbol
          in: path
          required: true
          schema:
            type: string
        - name: timeframe
          in: query
          required: true
          description: Bar timeframe
          schema:
            type: string
            enum:
              - 1Min
              - 5Min
              - 15Min
              - 30Min
              - 1Hour
              - 1Day
              - 1Week
              - 1Month
        - name: market
          in: query
          description: Market hint for disambiguation
          schema:
            type: string
        - name: start
          in: query
          description: Start date-time (ISO 8601)
          schema:
            type: string
            format: date-time
        - name: end
          in: query
          description: End date-time (ISO 8601)
          schema:
            type: string
            format: date-time
        - name: limit
          in: query
          description: Maximum number of bars
          schema:
            type: integer
            default: 100
            maximum: 10000
        - name: adjustment
          in: query
          description: Price adjustment type
          schema:
            type: string
            enum:
              - raw
              - split
              - dividend
              - all
            default: raw
      responses:
        '200':
          description: Historical bars
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: success
                  data:
                    $ref: '#/components/schemas/BarsResponse'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /market-data/assets/{symbol}/snapshot:
    get:
      summary: Get full asset snapshot
      description: Returns a comprehensive snapshot including latest trade, bid/ask quote, daily bar, previous close, and change calculations.
      operationId: getMarketDataSnapshot
      tags:
        - Market Data
      parameters:
        - name: symbol
          in: path
          required: true
          schema:
            type: string
        - name: market
          in: query
          description: Market hint for disambiguation
          schema:
            type: string
      responses:
        '200':
          description: Asset snapshot
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: success
                  data:
                    $ref: '#/components/schemas/SnapshotResponse'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /wealth/accounts/{account_id}/profile:
    get:
      tags:
        - Investor Profile
      summary: Get investor profile
      description: |
        Retrieve the comprehensive investor profile including demographics, employment,
        tax, insurance, estate planning, investment preferences, and partner information.
        If no profile exists, a new one is auto-created with default values.
      operationId: getInvestorProfile
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The investor account ID
      responses:
        '200':
          description: Investor profile retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InvestorProfile'
              examples:
                complete_profile:
                  summary: Profile with multiple sections populated
                  value:
                    id: ipro_01j9x8m2k7qpzwv3t5r6y8n0ab
                    object: investor_profile
                    livemode: false
                    metadata: {}
                    account_id: inv_01j9x8m2k7qpzwv3t5r6y8n0cd
                    completeness_score: 75
                    last_assessed_at: '2025-01-15T10:00:00Z'
                    demographics:
                      marital_status: married
                      number_of_dependents: 2
                      expected_retirement_age: 65
                      state_of_residence: CA
                    employment:
                      employment_status: employed_full_time
                      employer_name: Tech Corp
                      annual_gross_income: '150000.00'
                    investment_preferences:
                      investment_style: passive
                      esg_screening: true
                      shariah_compliant: false
                      rebalancing_preference: quarterly
                    created_at: '2024-01-01T10:00:00Z'
                    updated_at: '2025-01-15T10:00:00Z'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
    put:
      tags:
        - Investor Profile
      summary: Update investor profile
      description: |
        Update one or more sections of the investor profile.
        All sections are optional — only provided sections will be updated using merge semantics
        (existing fields within a section are preserved unless explicitly overwritten).
      operationId: updateInvestorProfile
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The investor account ID
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateProfileRequest'
            examples:
              update_demographics:
                summary: Update demographics section
                value:
                  demographics:
                    marital_status: married
                    number_of_dependents: 2
                    expected_retirement_age: 65
              update_investment_preferences:
                summary: Update investment preferences
                value:
                  investment_preferences:
                    investment_style: passive
                    esg_screening: true
                    shariah_compliant: true
                    excluded_sectors:
                      - tobacco
                      - gambling
                    rebalancing_preference: quarterly
              update_multiple_sections:
                summary: Update multiple sections at once
                value:
                  employment:
                    employment_status: employed_full_time
                    employer_name: Tech Corp
                    annual_gross_income: '150000.00'
                  tax:
                    filing_status: married_filing_jointly
                    federal_tax_bracket: 0.32
      responses:
        '200':
          description: Profile updated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InvestorProfile'
        '400':
          $ref: '#/components/responses/BadRequestError'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /wealth/accounts/{account_id}/profile/snapshots:
    post:
      tags:
        - Investor Profile
      summary: Create profile snapshot
      description: |
        Create an immutable snapshot of the investor profile.
        Typically triggered when generating a Financial Plan or IPS to preserve
        the profile state at that point in time for audit purposes.
      operationId: createProfileSnapshot
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The investor account ID
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                trigger:
                  type: string
                  enum:
                    - financial_plan
                    - ips
                    - manual
                  default: manual
                  description: What triggered this snapshot creation
                artifact_id:
                  type: string
                  description: Prefixed public id of the related Financial Plan or IPS.
            examples:
              manual_snapshot:
                summary: Manual snapshot
                value:
                  trigger: manual
              ips_snapshot:
                summary: Snapshot triggered by IPS generation
                value:
                  trigger: ips
                  artifact_id: ips_a1b2c3d4e5f6
      responses:
        '201':
          description: Snapshot created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProfileSnapshot'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
    get:
      tags:
        - Investor Profile
      summary: List profile snapshots
      description: Retrieve a list of profile snapshots for audit and historical analysis.
      operationId: listProfileSnapshots
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The investor account ID
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
          description: Maximum number of snapshots to return
        - name: trigger
          in: query
          required: false
          schema:
            type: string
            enum:
              - financial_plan
              - ips
              - manual
          description: Filter by snapshot trigger type
      responses:
        '200':
          description: List of profile snapshots
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/ProfileSnapshot'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /wealth/accounts/{account_id}/profile/snapshots/{snapshot_id}:
    get:
      tags:
        - Investor Profile
      summary: Get profile snapshot detail
      description: Retrieve a specific profile snapshot with the full data payload captured at that point in time.
      operationId: getProfileSnapshot
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The investor account ID
        - name: snapshot_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The snapshot ID
      responses:
        '200':
          description: Snapshot detail retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProfileSnapshotDetail'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /wealth/accounts/{account_id}/dependents:
    post:
      tags:
        - Dependents
      summary: Create a dependent
      description: |
        Add a dependent (child, spouse, parent, etc.) to the investor's profile for financial planning purposes.
        Dependents can be optionally linked to financial goals (e.g., an education goal for a child).
      operationId: createDependent
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The investor account ID
        - name: Idempotency-Key
          in: header
          required: false
          schema:
            type: string
            maxLength: 128
          description: Unique key for idempotent operation
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateDependentRequest'
            examples:
              child:
                summary: Add a child dependent
                value:
                  first_name: Emma
                  last_name: Smith
                  relationship: child
                  date_of_birth: '2015-03-15'
                  has_education_plans: true
                  estimated_education_cost: '150000.00'
                  covered_by_health_insurance: true
              parent:
                summary: Add a parent dependent
                value:
                  first_name: Margaret
                  relationship: parent
                  date_of_birth: '1955-08-22'
                  has_special_needs: false
                  notes: May need long-term care in 5-10 years
      responses:
        '201':
          description: Dependent created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Dependent'
        '400':
          $ref: '#/components/responses/BadRequestError'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
    get:
      tags:
        - Dependents
      summary: List dependents
      description: Retrieve all dependents for an investor account with optional filters.
      operationId: listDependents
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The investor account ID
        - name: status
          in: query
          required: false
          schema:
            type: string
            enum:
              - active
              - inactive
              - deceased
          description: Filter by dependent status
        - name: relationship
          in: query
          required: false
          schema:
            type: string
            enum:
              - child
              - spouse
              - partner
              - parent
              - grandchild
              - sibling
              - other
          description: Filter by relationship type
        - name: has_education_plans
          in: query
          required: false
          schema:
            type: boolean
          description: Filter dependents with education plans
      responses:
        '200':
          description: List of dependents
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DependentListResponse'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /wealth/accounts/{account_id}/dependents/{dependent_id}:
    get:
      tags:
        - Dependents
      summary: Get dependent details
      description: Retrieve details of a specific dependent including any linked goal information.
      operationId: getDependent
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The investor account ID
        - name: dependent_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The dependent ID
      responses:
        '200':
          description: Dependent details retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Dependent'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
    put:
      tags:
        - Dependents
      summary: Update dependent
      description: Update dependent information. Only provided fields are updated.
      operationId: updateDependent
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The investor account ID
        - name: dependent_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The dependent ID
        - name: Idempotency-Key
          in: header
          required: false
          schema:
            type: string
            maxLength: 128
          description: Unique key for idempotent operation
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateDependentRequest'
            examples:
              update_education:
                summary: Update education plans
                value:
                  has_education_plans: true
                  estimated_education_cost: '200000.00'
              link_goal:
                summary: Link dependent to a goal
                value:
                  linked_goal_id: 550e8400-e29b-41d4-a716-446655440000
      responses:
        '200':
          description: Dependent updated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Dependent'
        '400':
          $ref: '#/components/responses/BadRequestError'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
    delete:
      tags:
        - Dependents
      summary: Delete dependent
      description: |
        Archive (soft delete) a dependent. The dependent data is retained for historical records
        and existing profile snapshots.
      operationId: deleteDependent
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The investor account ID
        - name: dependent_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The dependent ID
      responses:
        '204':
          description: Dependent archived successfully
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /wealth/accounts/{account_id}/risk-assessments:
    post:
      tags:
        - Risk Assessment
      summary: Submit risk assessment
      description: |
        Submit a completed risk assessment questionnaire.
        Previous active assessments are automatically invalidated (marked as superseded).
        The new assessment is assigned a 1-year expiry by default.
      operationId: submitRiskAssessment
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The investor account ID
        - name: Idempotency-Key
          in: header
          required: false
          schema:
            type: string
            maxLength: 128
          description: Unique key for idempotent operation
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SubmitRiskAssessmentRequest'
            examples:
              moderate_risk:
                summary: Moderate risk questionnaire
                value:
                  questionnaire_id: q_standard_v2
                  questionnaire_version: 2
                  responses:
                    - question_id: q1
                      question_text: How would you react to a 20% portfolio drop?
                      answer_id: a1_c
                      answer_text: Hold and wait for recovery
                      score: 6
                    - question_id: q2
                      question_text: What is your investment time horizon?
                      answer_id: a2_d
                      answer_text: 10-20 years
                      score: 8
                  past_market_behavior:
                    experienced_major_downturn: true
                    action_during_downturn: held
                    regret_level: none
                  investment_experience: moderate
                  years_investing: 8
      responses:
        '201':
          description: Risk assessment submitted and scored
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RiskAssessment'
        '400':
          $ref: '#/components/responses/BadRequestError'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
    get:
      tags:
        - Risk Assessment
      summary: List risk assessments
      description: Retrieve all risk assessments for an investor (historical), ordered by most recent first.
      operationId: listRiskAssessments
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The investor account ID
        - name: status
          in: query
          required: false
          schema:
            type: string
            enum:
              - active
              - expired
              - superseded
          description: Filter by assessment status
      responses:
        '200':
          description: List of risk assessments
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RiskAssessmentListResponse'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /wealth/accounts/{account_id}/risk-assessments/current:
    get:
      tags:
        - Risk Assessment
      summary: Get current risk assessment
      description: Retrieve the active (non-expired) risk assessment with full questionnaire responses.
      operationId: getCurrentRiskAssessment
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The investor account ID
      responses:
        '200':
          description: Current risk assessment retrieved
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RiskAssessmentDetail'
        '204':
          description: No active risk assessment found
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /wealth/accounts/{account_id}/risk-assessments/summary:
    get:
      tags:
        - Risk Assessment
      summary: Get risk assessment summary
      description: |
        Get a quick summary of the investor's risk profile status including
        whether a valid assessment exists, the current score, and whether reassessment is needed.
      operationId: getRiskAssessmentSummary
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The investor account ID
      responses:
        '200':
          description: Risk assessment summary
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RiskAssessmentSummary'
              examples:
                valid_assessment:
                  summary: Active assessment with moderate risk
                  value:
                    has_valid_assessment: true
                    current_risk_score: 6
                    current_risk_tolerance: moderate
                    expires_at: '2026-01-15T10:00:00Z'
                    needs_reassessment: false
                needs_reassessment:
                  summary: Expired assessment
                  value:
                    has_valid_assessment: false
                    current_risk_score: null
                    current_risk_tolerance: null
                    expires_at: null
                    needs_reassessment: true
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /wealth/accounts/{account_id}/risk-assessments/{assessment_id}:
    get:
      tags:
        - Risk Assessment
      summary: Get risk assessment details
      description: Retrieve a specific risk assessment with full questionnaire responses and scoring breakdown.
      operationId: getRiskAssessment
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The investor account ID
        - name: assessment_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The risk assessment ID
      responses:
        '200':
          description: Risk assessment details retrieved
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RiskAssessmentDetail'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /wealth/accounts/{account_id}/goals:
    post:
      tags:
        - Goals
      summary: Create a goal
      description: Creates a new financial goal for the investor account.
      operationId: createGoal
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The investor account ID
        - name: Idempotency-Key
          in: header
          required: false
          schema:
            type: string
            maxLength: 128
          description: Unique key for idempotent operation
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateGoalRequest'
            examples:
              retirement_goal:
                summary: Retirement goal
                value:
                  name: Retirement Fund
                  goal_type: retirement
                  target_amount: '500000.00'
                  target_date: '2045-01-01'
                  priority: 1
                  monthly_contribution: '500.00'
              emergency_fund:
                summary: Emergency fund
                value:
                  name: Emergency Fund
                  goal_type: emergency
                  target_amount: '30000.00'
                  priority: 2
                  initial_amount: '5000.00'
                  monthly_contribution: '200.00'
      responses:
        '201':
          description: Goal created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Goal'
        '400':
          $ref: '#/components/responses/BadRequestError'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
    get:
      tags:
        - Goals
      summary: List goals
      description: Retrieves all financial goals for the investor account.
      operationId: listGoals
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The investor account ID
        - name: status
          in: query
          required: false
          schema:
            type: string
            enum:
              - active
              - completed
              - archived
          description: Filter by goal status
        - name: goal_type
          in: query
          required: false
          schema:
            type: string
            enum:
              - retirement
              - education
              - emergency
              - wealth_growth
              - home_purchase
              - custom
          description: Filter by goal type
        - name: include_projections
          in: query
          required: false
          schema:
            type: boolean
            default: false
          description: Include goal progress and projections
      responses:
        '200':
          description: Goals retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/GoalList'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /wealth/accounts/{account_id}/goals/{goal_id}:
    get:
      tags:
        - Goals
      summary: Get a goal
      description: Retrieves a specific financial goal.
      operationId: getGoal
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The investor account ID
        - name: goal_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The goal ID
        - name: include_projections
          in: query
          required: false
          schema:
            type: boolean
            default: false
          description: Include goal progress and projections
      responses:
        '200':
          description: Goal retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Goal'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
    put:
      tags:
        - Goals
      summary: Update a goal
      description: Updates an existing financial goal. Only provided fields are updated.
      operationId: updateGoal
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The investor account ID
        - name: goal_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The goal ID
        - name: Idempotency-Key
          in: header
          required: false
          schema:
            type: string
            maxLength: 128
          description: Unique key for idempotent operation
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateGoalRequest'
            examples:
              update_progress:
                summary: Update goal progress
                value:
                  current_amount: '75000.00'
                  monthly_contribution: '600.00'
              complete_goal:
                summary: Mark goal as completed
                value:
                  status: completed
      responses:
        '200':
          description: Goal updated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Goal'
        '400':
          $ref: '#/components/responses/BadRequestError'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
    delete:
      tags:
        - Goals
      summary: Delete a goal
      description: |
        Deletes a financial goal. This is a soft delete - the goal status is set to 'archived'.
        Use PUT with status='archived' for the same effect.
      operationId: deleteGoal
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The investor account ID
        - name: goal_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The goal ID
      responses:
        '204':
          description: Goal deleted successfully
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /wealth/accounts/{account_id}/life-events:
    post:
      tags:
        - Life Events
      summary: Create a life event
      description: Creates a new planned major life event for the investor account.
      operationId: createLifeEvent
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The investor account ID
        - name: Idempotency-Key
          in: header
          required: false
          schema:
            type: string
            maxLength: 128
          description: Unique key for idempotent operation
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateLifeEventRequest'
            examples:
              college:
                summary: College education
                value:
                  name: College for Sarah
                  event_type: college
                  expected_date: '2030-09-01'
                  estimated_cost: '100000.00'
                  notes: 4-year university tuition and expenses
              home_purchase:
                summary: Home purchase
                value:
                  name: First Home Purchase
                  event_type: home_purchase
                  expected_date: '2027-06-01'
                  estimated_cost: '80000.00'
                  currency: USD
                  notes: Down payment target
      responses:
        '201':
          description: Life event created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LifeEvent'
        '400':
          $ref: '#/components/responses/BadRequestError'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
    get:
      tags:
        - Life Events
      summary: List life events
      description: Retrieves all planned life events for the investor account.
      operationId: listLifeEvents
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The investor account ID
        - name: status
          in: query
          required: false
          schema:
            type: string
            enum:
              - active
              - completed
              - archived
          description: Filter by event status
        - name: event_type
          in: query
          required: false
          schema:
            type: string
            enum:
              - college
              - wedding
              - home_purchase
              - retirement
              - major_purchase
              - career_change
              - custom
          description: Filter by event type
      responses:
        '200':
          description: Life events retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LifeEventList'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /wealth/accounts/{account_id}/life-events/{event_id}:
    get:
      tags:
        - Life Events
      summary: Get a life event
      description: Retrieves a specific planned life event.
      operationId: getLifeEvent
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The investor account ID
        - name: event_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The life event ID
      responses:
        '200':
          description: Life event retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LifeEvent'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
    put:
      tags:
        - Life Events
      summary: Update a life event
      description: Updates an existing life event. Only provided fields are updated.
      operationId: updateLifeEvent
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The investor account ID
        - name: event_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The life event ID
        - name: Idempotency-Key
          in: header
          required: false
          schema:
            type: string
            maxLength: 128
          description: Unique key for idempotent operation
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateLifeEventRequest'
            examples:
              update_cost:
                summary: Update estimated cost
                value:
                  estimated_cost: '120000.00'
              complete_event:
                summary: Mark event as completed
                value:
                  status: completed
              link_goal:
                summary: Link to a goal
                value:
                  linked_goal_id: 550e8400-e29b-41d4-a716-446655440000
      responses:
        '200':
          description: Life event updated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LifeEvent'
        '400':
          $ref: '#/components/responses/BadRequestError'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
    delete:
      tags:
        - Life Events
      summary: Delete a life event
      description: |
        Deletes a life event. This is a soft delete - the event status is set to 'archived'.
        Use PUT with status='archived' for the same effect.
      operationId: deleteLifeEvent
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The investor account ID
        - name: event_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The life event ID
      responses:
        '204':
          description: Life event deleted successfully
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /wealth/accounts/{account_id}/external-accounts:
    post:
      tags:
        - External Accounts
      summary: Create an external account
      description: |
        Creates a new external account for net worth tracking.
        External accounts represent assets and liabilities held outside the platform 
        (e.g., bank accounts, real estate, mortgages, other investments).
      operationId: createExternalAccount
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The investor account ID
        - name: Idempotency-Key
          in: header
          required: false
          schema:
            type: string
            maxLength: 128
          description: Unique key for idempotent operation
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateExternalAccountRequest'
            examples:
              checking_account:
                summary: Bank checking account
                value:
                  name: Chase Checking
                  account_type: checking
                  is_asset: true
                  balance: '15000.00'
                  institution: JPMorgan Chase
              mortgage:
                summary: Home mortgage
                value:
                  name: Home Mortgage
                  account_type: mortgage
                  is_asset: false
                  balance: '350000.00'
                  institution: Wells Fargo
                  notes: 30-year fixed at 6.5%
              real_estate:
                summary: Real estate asset
                value:
                  name: Primary Residence
                  account_type: real_estate
                  is_asset: true
                  balance: '550000.00'
                  notes: Estimated market value
      responses:
        '201':
          description: External account created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ExternalAccount'
        '400':
          $ref: '#/components/responses/BadRequestError'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
    get:
      tags:
        - External Accounts
      summary: List external accounts
      description: Retrieves all external accounts for the investor.
      operationId: listExternalAccounts
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The investor account ID
        - name: status
          in: query
          required: false
          schema:
            type: string
            enum:
              - active
              - archived
          description: Filter by account status
        - name: is_asset
          in: query
          required: false
          schema:
            type: boolean
          description: Filter by asset (true) or liability (false)
        - name: account_type
          in: query
          required: false
          schema:
            type: string
            enum:
              - checking
              - savings
              - investment
              - brokerage
              - retirement_401k
              - retirement_ira_traditional
              - retirement_ira_roth
              - retirement_403b
              - retirement_457b
              - retirement_pension
              - retirement
              - hsa
              - fsa
              - plan_529
              - utma_ugma
              - trust
              - real_estate
              - vehicle
              - business_equity
              - collectibles
              - crypto
              - other_asset
              - mortgage
              - home_equity_loan
              - home_equity_loc
              - auto_loan
              - student_loan
              - personal_loan
              - loan
              - credit_card
              - medical_debt
              - tax_debt
              - other_liability
          description: Filter by account type
      responses:
        '200':
          description: External accounts retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ExternalAccountList'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /wealth/accounts/{account_id}/external-accounts/{external_account_id}:
    get:
      tags:
        - External Accounts
      summary: Get an external account
      description: Retrieves a specific external account.
      operationId: getExternalAccount
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The investor account ID
        - name: external_account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The external account ID
      responses:
        '200':
          description: External account retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ExternalAccount'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
    put:
      tags:
        - External Accounts
      summary: Update an external account
      description: Updates an existing external account. Only provided fields are updated.
      operationId: updateExternalAccount
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The investor account ID
        - name: external_account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The external account ID
        - name: Idempotency-Key
          in: header
          required: false
          schema:
            type: string
            maxLength: 128
          description: Unique key for idempotent operation
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateExternalAccountRequest'
            examples:
              update_balance:
                summary: Update account balance
                value:
                  balance: '16500.00'
              archive_account:
                summary: Archive account
                value:
                  status: archived
      responses:
        '200':
          description: External account updated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ExternalAccount'
        '400':
          $ref: '#/components/responses/BadRequestError'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
    delete:
      tags:
        - External Accounts
      summary: Delete an external account
      description: |
        Deletes an external account. This is a soft delete - the account status is set to 'archived'.
        Use PUT with status='archived' for the same effect.
      operationId: deleteExternalAccount
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The investor account ID
        - name: external_account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The external account ID
      responses:
        '204':
          description: External account deleted successfully
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /wealth/accounts/{account_id}/financial-plan:
    put:
      tags:
        - Financial Plan
      summary: Create or update financial plan
      description: |
        Creates or updates the holistic financial plan for an account.
        The financial plan captures goals, life events, external accounts, income, expenses, and investment outlook.
        This is an idempotent operation - creates if not exists, updates if exists.
      operationId: upsertFinancialPlan
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The investor account ID
        - name: Idempotency-Key
          in: header
          required: false
          schema:
            type: string
            maxLength: 128
          description: Unique key for idempotent operation
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/FinancialPlanRequest'
            examples:
              complete_plan:
                summary: Complete financial plan
                value:
                  goals:
                    - name: Retirement Fund
                      goal_type: retirement
                      target_amount: '500000.00'
                      target_date: '2045-01-01'
                      priority: 1
                      monthly_contribution: '500.00'
                    - name: Emergency Fund
                      goal_type: emergency
                      target_amount: '30000.00'
                      priority: 2
                      monthly_contribution: '200.00'
                  life_events:
                    - name: College for Sarah
                      event_type: college
                      expected_date: '2030-09-01'
                      estimated_cost: '100000.00'
                  external_accounts:
                    - name: Chase Checking
                      account_type: checking
                      is_asset: true
                      balance: '15000.00'
                    - name: Mortgage
                      account_type: mortgage
                      is_asset: false
                      balance: '350000.00'
                  income:
                    total_monthly_income: '12000.00'
                    sources:
                      - name: Salary
                        type: salary
                        amount: '10000.00'
                        frequency: monthly
                      - name: Rental Income
                        type: rental
                        amount: '2000.00'
                        frequency: monthly
                  expenses:
                    total_monthly_expenses: '8000.00'
                    categories:
                      - name: Housing
                        type: housing
                        amount: '3000.00'
                        frequency: monthly
                        is_essential: true
                  investment_outlook:
                    expected_return_rate: '7.00'
                    inflation_assumption: '2.50'
                    risk_capacity: moderate
                    tax_bracket: '24'
      responses:
        '200':
          description: Financial plan created or updated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FinancialPlan'
        '400':
          $ref: '#/components/responses/BadRequestError'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
    get:
      tags:
        - Financial Plan
      summary: Get financial plan
      description: Retrieves the current financial plan for an account including all goals, events, and financial data.
      operationId: getFinancialPlan
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The investor account ID
        - name: include_projections
          in: query
          required: false
          schema:
            type: boolean
            default: false
          description: Include goal projections and progress calculations
      responses:
        '200':
          description: Financial plan retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FinancialPlan'
              examples:
                with_goals:
                  summary: Financial plan with goals
                  value:
                    id: fp_01j9x8m2k7qpzwv3t5r6y8n0ab
                    object: financial_plan
                    livemode: false
                    metadata: {}
                    account_id: inv_01j9x8m2k7qpzwv3t5r6y8n0cd
                    version: 1
                    goals:
                      - id: gl_01j9x8m2k7qpzwv3t5r6y8n0ef
                        object: goal
                        livemode: false
                        metadata: {}
                        name: Retirement Fund
                        goal_type: retirement
                        target_amount: '500000.00'
                        target_date: '2045-01-01'
                        current_amount: '50000.00'
                        progress_percent: '10.00'
                        amount_remaining: '450000.00'
                        monthly_contribution: '500.00'
                        projected_completion_date: '2044-06-15'
                        on_track: true
                        status: active
                    life_events: []
                    external_accounts: []
                    income:
                      total_monthly_income: '12000.00'
                      sources: []
                    expenses:
                      total_monthly_expenses: '8000.00'
                      categories: []
                    investment_outlook:
                      expected_return_rate: '7.00'
                      inflation_assumption: '2.50'
                      risk_capacity: moderate
                    status: active
                    created_at: '2024-01-15T10:30:00Z'
                    updated_at: '2025-01-15T14:00:00Z'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /wealth/accounts/{account_id}/financial-plan/summary:
    get:
      tags:
        - Financial Plan
      summary: Get financial health summary
      description: |
        Returns a summary of the investor's overall financial health including
        net worth, goal progress, cash flow, and savings rate.
      operationId: getFinancialPlanSummary
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The investor account ID
      responses:
        '200':
          description: Financial health summary retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FinancialPlanSummary'
              examples:
                healthy_finances:
                  summary: Healthy financial summary
                  value:
                    financial_plan_id: fp_a1b2c3d4e5f6
                    total_net_worth: '275000.00'
                    total_assets: '625000.00'
                    total_liabilities: '350000.00'
                    total_goal_progress: '35.00'
                    goals_on_track: 3
                    goals_at_risk: 1
                    monthly_cash_flow: '4000.00'
                    savings_rate: '33.33'
                    investment_portfolio_value: '125000.00'
                    generated_at: '2025-01-15T16:00:00Z'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /wealth/accounts/{account_id}/investment-policy:
    put:
      tags:
        - Investment Policy
      summary: Create or update investment policy statement
      description: |
        Creates or updates the Investment Policy Statement (IPS) for an account.
        The IPS defines risk profile, time horizon, investment objectives, target allocation, and constraints.
        This is an idempotent operation - creates if not exists, creates a new version if exists.
        Previous versions are marked as superseded.
      operationId: upsertInvestmentPolicy
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The investor account ID
        - name: Idempotency-Key
          in: header
          required: false
          schema:
            type: string
            maxLength: 128
          description: Unique key for idempotent operation
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/InvestmentPolicyStatementRequest'
            examples:
              moderate_investor:
                summary: Moderate risk investor IPS
                value:
                  risk_profile:
                    risk_tolerance: moderate
                    risk_score: 6
                    volatility_tolerance: medium
                  time_horizon:
                    years: 15
                    category: long_term
                  investment_objectives:
                    primary: capital_appreciation
                    secondary:
                      - income_generation
                      - tax_efficiency
                    target_annual_return: '7.00'
                  target_allocation:
                    equities:
                      target_percent: '50.00'
                      min_percent: '40.00'
                      max_percent: '60.00'
                      sub_allocations:
                        us_large_cap: '30.00'
                        us_small_cap: '10.00'
                        international: '10.00'
                    fixed_income:
                      target_percent: '25.00'
                      min_percent: '20.00'
                      max_percent: '30.00'
                    treasury:
                      target_percent: '20.00'
                      min_percent: '15.00'
                      max_percent: '25.00'
                    alternatives:
                      target_percent: '5.00'
                      min_percent: '0.00'
                      max_percent: '10.00'
                  constraints:
                    liquidity_requirements:
                      minimum_cash_percent: '5.00'
                      emergency_fund_months: 6
                    tax_considerations:
                      tax_loss_harvesting: true
                      tax_bracket: '24'
                      prefer_tax_advantaged: true
                    restrictions:
                      excluded_sectors:
                        - tobacco
                        - gambling
                      no_individual_stocks: true
                      esg_screening: true
                      esg_criteria:
                        - environmental
                        - social
                    rebalancing_policy:
                      frequency: quarterly
                      threshold_percent: '5.00'
                      tax_aware: true
                  effective_date: '2025-01-15'
      responses:
        '200':
          description: Investment policy statement created or updated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InvestmentPolicyStatement'
        '400':
          description: Bad request - validation error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                allocation_error:
                  summary: Target allocation doesn't sum to 100%
                  value:
                    code: BLUM-400-012
                    message: Target allocation must sum to 100%
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
    get:
      tags:
        - Investment Policy
      summary: Get investment policy statement
      description: Retrieves the current (or specified version) investment policy statement for an account.
      operationId: getInvestmentPolicy
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The investor account ID
        - name: version
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
          description: Get specific version (default is latest active)
        - name: include_history
          in: query
          required: false
          schema:
            type: boolean
            default: false
          description: Include version history
      responses:
        '200':
          description: Investment policy statement retrieved successfully
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/InvestmentPolicyStatement'
                  - type: object
                    properties:
                      version_history:
                        type: array
                        items:
                          type: object
                          properties:
                            version:
                              type: integer
                            effective_date:
                              type: string
                              format: date
                            updated_at:
                              type: string
                              format: date-time
              examples:
                with_history:
                  summary: IPS with version history
                  value:
                    id: ips_01j9x8m2k7qpzwv3t5r6y8n0ab
                    object: investment_policy_statement
                    livemode: false
                    metadata: {}
                    account_id: inv_01j9x8m2k7qpzwv3t5r6y8n0cd
                    version: 3
                    risk_profile:
                      risk_tolerance: moderate
                      risk_score: 6
                    time_horizon:
                      years: 15
                      category: long_term
                    investment_objectives:
                      primary: capital_appreciation
                      secondary:
                        - income_generation
                    target_allocation:
                      equities:
                        target_percent: '50.00'
                        min_percent: '40.00'
                        max_percent: '60.00'
                      fixed_income:
                        target_percent: '25.00'
                        min_percent: '20.00'
                        max_percent: '30.00'
                      treasury:
                        target_percent: '20.00'
                        min_percent: '15.00'
                        max_percent: '25.00'
                      alternatives:
                        target_percent: '5.00'
                        min_percent: '0.00'
                        max_percent: '10.00'
                    constraints:
                      rebalancing_policy:
                        frequency: quarterly
                        threshold_percent: '5.00'
                    effective_date: '2025-01-15'
                    status: active
                    created_at: '2023-01-01T10:00:00Z'
                    updated_at: '2025-01-15T10:00:00Z'
                    version_history:
                      - version: 1
                        effective_date: '2023-01-01'
                        updated_at: '2023-01-01T10:00:00Z'
                      - version: 2
                        effective_date: '2024-01-01'
                        updated_at: '2024-01-01T10:00:00Z'
                      - version: 3
                        effective_date: '2025-01-15'
                        updated_at: '2025-01-15T10:00:00Z'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          description: Investment policy not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                not_found:
                  value:
                    code: BLUM-404-011
                    message: Investment policy not found
  /wealth/accounts/{account_id}/investment-policy/validate:
    post:
      tags:
        - Investment Policy
      summary: Validate portfolio against IPS
      description: |
        Checks if a portfolio complies with the Investment Policy Statement.
        Returns compliance status, deviations, violations, and recommended actions.
      operationId: validateInvestmentPolicy
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The investor account ID
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - portfolio_id
              properties:
                portfolio_id:
                  type: string
                  description: Prefixed public id of the portfolio to validate.
            examples:
              validate_request:
                value:
                  portfolio_id: port_a1b2c3d4e5f6
      responses:
        '200':
          description: Validation completed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/IpsValidationResult'
              examples:
                non_compliant:
                  summary: Portfolio with allocation drift
                  value:
                    is_compliant: false
                    validation_results:
                      allocation_compliance:
                        compliant: false
                        deviations:
                          - asset_class: equities
                            target_percent: '50.00'
                            current_percent: '62.00'
                            deviation: '12.00'
                            within_bands: false
                          - asset_class: fixed_income
                            target_percent: '25.00'
                            current_percent: '20.00'
                            deviation: '-5.00'
                            within_bands: true
                      restriction_compliance:
                        compliant: true
                        violations: []
                      liquidity_compliance:
                        compliant: true
                        current_cash_percent: '8.00'
                        required_cash_percent: '5.00'
                    recommended_actions:
                      - action_type: rebalance
                        description: Reduce equity allocation by 12%
                        priority: high
                    validated_at: '2025-01-15T16:00:00Z'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /wealth/accounts/{account_id}/portfolios:
    get:
      tags:
        - Portfolio Management
      summary: List portfolios for an account
      description: Retrieves all portfolios owned by the investor under the tenant.
      operationId: listPortfolios
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: Portfolios retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PortfolioListResponse'
              examples:
                default:
                  summary: Portfolios list
                  value:
                    object: list
                    url: /v1/wealth/portfolios?investor=inv_01j9x8m2k7qpzwv3t5r6y8n0ab
                    has_more: false
                    data:
                      - id: pf_01j9x8m2k7qpzwv3t5r6y8n0ab
                        object: portfolio
                        livemode: false
                        metadata: {}
                        name: Retirement Portfolio
                        currency: USD
                        status: active
                        created_at: '2024-01-10T10:00:00Z'
                        updated_at: '2025-01-10T10:00:00Z'
                      - id: pf_01j9x8m2k7qpzwv3t5r6y8n0cd
                        object: portfolio
                        livemode: false
                        metadata: {}
                        name: Growth Portfolio
                        currency: USD
                        status: paused
                        created_at: '2023-05-03T13:30:00Z'
                        updated_at: '2025-01-05T09:00:00Z'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /wealth/accounts/{account_id}/portfolios/{portfolio_id}/summary:
    get:
      tags:
        - Portfolio Management
      summary: Get portfolio summary
      description: |
        Returns a comprehensive portfolio overview including valuation, allocation breakdown,
        rebalancing status, linked strategy, and associated goals.
      operationId: getPortfolioSummary
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: portfolio_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: refresh_prices
          in: query
          required: false
          schema:
            type: boolean
            default: false
          description: Fetch live market prices (adds latency)
      responses:
        '200':
          description: Portfolio summary retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PortfolioSummary'
              examples:
                balanced_portfolio:
                  summary: Balanced portfolio summary
                  value:
                    portfolio_id: port_a1b2c3d4e5f6
                    account_id: 3d0b0e65-35d3-4dcd-8df7-10286ebb4b4b
                    name: Main Portfolio
                    currency: USD
                    valuation:
                      total_value: '125000.00'
                      cash_value: '10000.00'
                      positions_value: '115000.00'
                      unrealized_gain_loss: '15000.00'
                      unrealized_gain_loss_percent: '13.64'
                      as_of: '2025-01-15T16:00:00Z'
                    allocation:
                      by_asset_class:
                        - asset_class: equities
                          value: '62500.00'
                          percent: '50.00'
                        - asset_class: fixed_income
                          value: '31250.00'
                          percent: '25.00'
                        - asset_class: treasury
                          value: '25000.00'
                          percent: '20.00'
                        - asset_class: alternatives
                          value: '6250.00'
                          percent: '5.00'
                      by_sector:
                        - sector: technology
                          value: '25000.00'
                          percent: '20.00'
                        - sector: healthcare
                          value: '18750.00'
                          percent: '15.00'
                    rebalancing_status:
                      needs_rebalancing: false
                      last_rebalanced_at: '2024-10-01T10:00:00Z'
                      next_scheduled: '2025-01-15'
                      max_deviation_percent: '3.50'
                    strategy_application:
                      strategy_id: strat_123456
                      strategy_version_id: sv_789012
                      applied_at: '2024-01-01T10:00:00Z'
                      status: active
                    linked_goals:
                      - id: gl_01j9x8m2k7qpzwv3t5r6y8n0ab
                        name: Retirement Fund
                    created_at: '2023-01-15T10:30:00Z'
                    updated_at: '2025-01-15T10:30:00Z'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /wealth/accounts/{account_id}/portfolios/{portfolio_id}/holdings:
    get:
      tags:
        - Portfolio Management
      summary: Get portfolio holdings
      description: Returns detailed breakdown of all positions in the portfolio.
      operationId: getPortfolioHoldings
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: portfolio_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: refresh_prices
          in: query
          required: false
          schema:
            type: boolean
            default: false
          description: Fetch live market prices
        - name: include_lots
          in: query
          required: false
          schema:
            type: boolean
            default: false
          description: Include tax lot details
        - name: group_by
          in: query
          required: false
          schema:
            type: string
            enum:
              - asset_class
              - sector
              - none
            default: none
          description: Group holdings by category
      responses:
        '200':
          description: Portfolio holdings retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PortfolioHoldings'
              examples:
                diversified_holdings:
                  summary: Diversified portfolio holdings
                  value:
                    portfolio_id: port_a1b2c3d4e5f6
                    currency: USD
                    as_of: '2025-01-15T16:00:00Z'
                    cash:
                      balance: '10000.00'
                      available: '9500.00'
                      reserved: '500.00'
                    holdings:
                      - position_id: pos_001
                        asset_id: asset_vti
                        symbol: VTI
                        name: Vanguard Total Stock Market ETF
                        asset_class: equities
                        sector: diversified
                        quantity: '100.00'
                        average_cost_basis: '200.00'
                        total_cost_basis: '20000.00'
                        current_price: '225.00'
                        market_value: '22500.00'
                        unrealized_pl: '2500.00'
                        unrealized_pl_percent: '12.50'
                        weight_percent: '18.00'
                        price_source: ALPACA
                        price_confidence: REAL_TIME
                        price_timestamp: '2025-01-15T15:59:00Z'
                      - position_id: pos_002
                        asset_id: asset_bnd
                        symbol: BND
                        name: Vanguard Total Bond Market ETF
                        asset_class: fixed_income
                        sector: bonds
                        quantity: '200.00'
                        average_cost_basis: '75.00'
                        total_cost_basis: '15000.00'
                        current_price: '78.00'
                        market_value: '15600.00'
                        unrealized_pl: '600.00'
                        unrealized_pl_percent: '4.00'
                        weight_percent: '12.48'
                        price_source: ALPACA
                        price_confidence: REAL_TIME
                        price_timestamp: '2025-01-15T15:59:00Z'
                    totals:
                      total_value: '125000.00'
                      total_cost_basis: '100000.00'
                      total_unrealized_pl: '25000.00'
                      total_unrealized_pl_percent: '25.00'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /wealth/accounts/{account_id}/portfolios/{portfolio_id}/performance:
    get:
      tags:
        - Portfolio Management
      summary: Get portfolio performance
      description: |
        Returns time-weighted returns, risk metrics, and optional benchmark comparison.
      operationId: getPortfolioPerformance
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: portfolio_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: period
          in: query
          required: false
          schema:
            type: string
            enum:
              - 1d
              - 1w
              - 1m
              - 3m
              - 6m
              - ytd
              - 1y
              - 3y
              - 5y
              - all
            default: 1y
          description: Performance period
        - name: start_date
          in: query
          required: false
          schema:
            type: string
            format: date
          description: Custom start date (overrides period)
        - name: end_date
          in: query
          required: false
          schema:
            type: string
            format: date
          description: Custom end date
        - name: benchmark
          in: query
          required: false
          schema:
            type: string
          description: Benchmark symbol for comparison (e.g., SPY)
      responses:
        '200':
          description: Portfolio performance retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PortfolioPerformance'
              examples:
                one_year_performance:
                  summary: One year performance with benchmark
                  value:
                    portfolio_id: port_a1b2c3d4e5f6
                    period:
                      start_date: '2024-01-15'
                      end_date: '2025-01-15'
                      label: 1y
                    returns:
                      time_weighted_return: '12.50'
                      money_weighted_return: '11.80'
                      total_return: '15000.00'
                      annualized_return: '12.50'
                    benchmark_comparison:
                      benchmark_symbol: SPY
                      benchmark_name: S&P 500 ETF
                      benchmark_return: '10.20'
                      alpha: '2.30'
                      tracking_error: '3.50'
                    risk_metrics:
                      volatility: '14.50'
                      sharpe_ratio: '0.86'
                      max_drawdown: '-8.20'
                      max_drawdown_date: '2024-08-05'
                      beta: '0.95'
                    period_breakdown:
                      starting_value: '100000.00'
                      ending_value: '125000.00'
                      net_contributions: '10000.00'
                      net_withdrawals: '0.00'
                      investment_gains: '15000.00'
                      dividends_received: '2500.00'
                      fees_paid: '250.00'
                    value_history:
                      - date: '2024-01-15'
                        value: '100000.00'
                      - date: '2024-07-15'
                        value: '110000.00'
                      - date: '2025-01-15'
                        value: '125000.00'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /wealth/accounts/{account_id}/portfolios/{portfolio_id}/rebalancing:
    get:
      tags:
        - Portfolio Management
      summary: Get rebalancing analysis
      description: |
        Analyzes portfolio drift from target allocation and provides rebalancing recommendations.
        Includes tax impact analysis if positions have gains/losses.
      operationId: getRebalancingAnalysis
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: portfolio_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: Rebalancing analysis retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RebalancingAnalysis'
              examples:
                needs_rebalancing:
                  summary: Portfolio requiring rebalance
                  value:
                    portfolio_id: port_a1b2c3d4e5f6
                    analysis_timestamp: '2025-01-15T16:00:00Z'
                    needs_rebalancing: true
                    rebalancing_reason: allocation_drift
                    current_allocation:
                      equities:
                        target: '50.00'
                        actual: '58.00'
                        drift: '8.00'
                      fixed_income:
                        target: '25.00'
                        actual: '22.00'
                        drift: '-3.00'
                      treasury:
                        target: '20.00'
                        actual: '17.00'
                        drift: '-3.00'
                      alternatives:
                        target: '5.00'
                        actual: '3.00'
                        drift: '-2.00'
                    recommended_trades:
                      - action: sell
                        symbol: VTI
                        asset_class: equities
                        quantity: '25.00'
                        notional: '5625.00'
                        reason: Reduce equity overweight
                      - action: buy
                        symbol: BND
                        asset_class: fixed_income
                        quantity: '30.00'
                        notional: '2340.00'
                        reason: Increase fixed income allocation
                    tax_impact:
                      estimated_short_term_gains: '500.00'
                      estimated_long_term_gains: '1200.00'
                      tax_loss_harvesting_available: true
                      harvestable_losses: '300.00'
                    last_rebalanced_at: '2024-10-01T10:00:00Z'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
    post:
      tags:
        - Portfolio Management
      summary: Execute portfolio rebalance
      description: |
        Executes portfolio rebalancing trades via the Strategy Engine.
        Creates a TradePlan and Execution for audit trail.
        Requires Idempotency-Key header.
      operationId: executeRebalance
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: portfolio_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: Idempotency-Key
          in: header
          required: true
          schema:
            type: string
            maxLength: 128
          description: Unique key for idempotent operation
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RebalanceRequest'
            examples:
              full_rebalance:
                summary: Full tax-aware rebalance
                value:
                  execution_type: full
                  tax_aware: true
              custom_rebalance:
                summary: Custom rebalance with exclusions
                value:
                  execution_type: full
                  tax_aware: true
                  exclude_positions:
                    - pos_123
                    - pos_456
      responses:
        '202':
          description: Rebalance initiated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RebalanceResponse'
              examples:
                initiated:
                  value:
                    rebalance_id: reb_a1b2c3d4e5f6
                    portfolio_id: port_a1b2c3d4e5f6
                    status: pending
                    execution_type: full
                    trade_plan_id: tp_789012345678
                    estimated_trades: 4
                    estimated_completion: '2025-01-15T16:30:00Z'
                    created_at: '2025-01-15T16:00:00Z'
        '400':
          $ref: '#/components/responses/BadRequestError'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
        '409':
          description: Portfolio has active rebalancing in progress
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                conflict:
                  value:
                    code: BLUM-409-010
                    message: Portfolio has active rebalancing in progress
  /wealth/accounts/{account_id}/auto-invest:
    post:
      tags:
        - Auto-Invest
      summary: Create auto-invest schedule
      description: |
        Creates a new automated investment schedule for recurring deposits and investments.
        Supports various frequencies (weekly, biweekly, monthly, quarterly) and allocation rules.
      operationId: createAutoInvestSchedule
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: Idempotency-Key
          in: header
          required: false
          schema:
            type: string
            maxLength: 128
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AutoInvestScheduleRequest'
            examples:
              monthly_ips_allocation:
                summary: Monthly investment following IPS
                value:
                  name: Monthly Investment
                  portfolio_id: port_a1b2c3d4e5f6
                  funding_source_id: fs_123456789
                  amount: '500.00'
                  currency: USD
                  frequency: monthly
                  schedule:
                    day_of_month: 15
                    time: '09:30'
                  allocation_rule: ips_target
                  start_date: '2025-02-15'
                  notifications:
                    on_execution: true
                    on_failure: true
              weekly_custom_allocation:
                summary: Weekly with custom allocation
                value:
                  name: Weekly Tech Investment
                  portfolio_id: port_a1b2c3d4e5f6
                  funding_source_id: fs_123456789
                  amount: '100.00'
                  currency: USD
                  frequency: weekly
                  schedule:
                    day_of_week: 1
                    time: '10:00'
                  allocation_rule: custom
                  custom_allocation:
                    VTI: '60.00'
                    QQQ: '40.00'
                  start_date: '2025-02-03'
      responses:
        '201':
          description: Auto-invest schedule created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AutoInvestSchedule'
              examples:
                created:
                  value:
                    id: ais_01j9x8m2k7qpzwv3t5r6y8n0ab
                    object: auto_invest_schedule
                    created: 1747776000
                    livemode: false
                    metadata: {}
                    account_id: inv_01j9x8m2k7qpzwv3t5r6y8n0cd
                    portfolio_id: pf_01j9x8m2k7qpzwv3t5r6y8n0ef
                    name: Monthly Investment
                    amount: '500.00'
                    currency: USD
                    frequency: monthly
                    schedule:
                      day_of_month: 15
                      time: '09:30'
                    allocation_rule: ips_target
                    funding_source_id: fs_01j9x8m2k7qpzwv3t5r6y8n0gh
                    start_date: '2025-02-15'
                    next_execution: '2025-02-15T09:30:00Z'
                    status: active
                    notifications:
                      on_execution: true
                      on_failure: true
                    updated_at: '2025-01-15T10:00:00Z'
        '400':
          description: Bad request - validation error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                below_minimum:
                  value:
                    code: BLUM-400-014
                    message: Auto-invest amount below minimum
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
    get:
      tags:
        - Auto-Invest
      summary: List auto-invest schedules
      description: Returns all auto-invest schedules for an account.
      operationId: listAutoInvestSchedules
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: status
          in: query
          required: false
          schema:
            type: string
            enum:
              - active
              - paused
              - completed
              - cancelled
          description: Filter by status
        - name: portfolio_id
          in: query
          required: false
          schema:
            type: string
            format: uuid
          description: Filter by portfolio
      responses:
        '200':
          description: Auto-invest schedules retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AutoInvestScheduleList'
              examples:
                multiple_schedules:
                  value:
                    object: list
                    url: /v1/wealth/auto-invest/schedules?investor=inv_01j9x8m2k7qpzwv3t5r6y8n0ab
                    has_more: false
                    data:
                      - id: ais_01j9x8m2k7qpzwv3t5r6y8n0ab
                        object: auto_invest_schedule
                        livemode: false
                        metadata: {}
                        name: Monthly Investment
                        amount: '500.00'
                        frequency: monthly
                        next_execution: '2025-02-15T09:30:00Z'
                        status: active
                      - id: ais_01j9x8m2k7qpzwv3t5r6y8n0cd
                        object: auto_invest_schedule
                        livemode: false
                        metadata: {}
                        name: Weekly Tech
                        amount: '100.00'
                        frequency: weekly
                        next_execution: '2025-01-20T10:00:00Z'
                        status: active
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /wealth/accounts/{account_id}/auto-invest/{schedule_id}:
    get:
      tags:
        - Auto-Invest
      summary: Get auto-invest schedule details
      description: Returns detailed information about a specific auto-invest schedule.
      operationId: getAutoInvestSchedule
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: schedule_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: Auto-invest schedule retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AutoInvestSchedule'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          description: Auto-invest schedule not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                not_found:
                  value:
                    code: BLUM-404-012
                    message: Auto-invest schedule not found
    patch:
      tags:
        - Auto-Invest
      summary: Update auto-invest schedule
      description: Updates an existing auto-invest schedule. Only provided fields are updated.
      operationId: updateAutoInvestSchedule
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: schedule_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                amount:
                  type: string
                schedule:
                  type: object
                allocation_rule:
                  type: string
                custom_allocation:
                  type: object
                end_date:
                  type: string
                  format: date
                notifications:
                  type: object
            examples:
              update_amount:
                value:
                  amount: '750.00'
      responses:
        '200':
          description: Auto-invest schedule updated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AutoInvestSchedule'
        '400':
          $ref: '#/components/responses/BadRequestError'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
    delete:
      tags:
        - Auto-Invest
      summary: Delete auto-invest schedule
      description: Cancels and deletes an auto-invest schedule.
      operationId: deleteAutoInvestSchedule
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: schedule_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '204':
          description: Auto-invest schedule deleted successfully
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /wealth/accounts/{account_id}/auto-invest/{schedule_id}/pause:
    post:
      tags:
        - Auto-Invest
      summary: Pause auto-invest schedule
      description: Pauses an active auto-invest schedule. Can be resumed later.
      operationId: pauseAutoInvestSchedule
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: schedule_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: Auto-invest schedule paused successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AutoInvestSchedule'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /wealth/accounts/{account_id}/auto-invest/{schedule_id}/resume:
    post:
      tags:
        - Auto-Invest
      summary: Resume auto-invest schedule
      description: Resumes a paused auto-invest schedule.
      operationId: resumeAutoInvestSchedule
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: schedule_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: Auto-invest schedule resumed successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AutoInvestSchedule'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /wealth/accounts/{account_id}/portfolios/{portfolio_id}/drip:
    put:
      tags:
        - Auto-Invest
      summary: Configure dividend reinvestment (DRIP)
      description: |
        Configures dividend reinvestment settings for a portfolio.
        Supports reinvesting in the same security, following portfolio allocation, or custom allocation.
        Also supports cash sweep to auto-invest idle cash above a threshold.
      operationId: configureDrip
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: portfolio_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DripConfigurationRequest'
            examples:
              same_security:
                summary: Reinvest in same security
                value:
                  enabled: true
                  reinvestment_rule: same_security
                  minimum_amount: '10.00'
              portfolio_allocation:
                summary: Reinvest following portfolio allocation
                value:
                  enabled: true
                  reinvestment_rule: portfolio_allocation
                  minimum_amount: '25.00'
                  cash_sweep_enabled: true
                  cash_sweep_threshold: '100.00'
      responses:
        '200':
          description: DRIP configuration updated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DripConfiguration'
              examples:
                configured:
                  value:
                    id: drp_01j9x8m2k7qpzwv3t5r6y8n0ab
                    object: drip_configuration
                    created: 1747776000
                    livemode: false
                    metadata: {}
                    portfolio_id: pf_01j9x8m2k7qpzwv3t5r6y8n0cd
                    enabled: true
                    reinvestment_rule: same_security
                    minimum_amount: '10.00'
                    cash_sweep_enabled: false
                    status: active
                    updated_at: '2025-01-15T10:00:00Z'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
    get:
      tags:
        - Auto-Invest
      summary: Get DRIP configuration
      description: Returns the dividend reinvestment configuration for a portfolio.
      operationId: getDripConfiguration
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: portfolio_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: DRIP configuration retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DripConfiguration'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /wealth/accounts/{account_id}/insights:
    get:
      tags:
        - Insights & Recommendations
      summary: Get personalized insights
      description: |
        Returns AI-generated personalized insights about the investor's portfolio and financial situation.
        Insights include opportunities, risks, tax optimization, and rebalancing recommendations.
      operationId: getInsights
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: category
          in: query
          required: false
          schema:
            type: string
            enum:
              - all
              - opportunity
              - risk
              - tax
              - rebalancing
            default: all
          description: Filter by insight category
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 50
            default: 10
          description: Maximum number of insights to return
      responses:
        '200':
          description: Insights retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InsightList'
              examples:
                multiple_insights:
                  summary: Various insights
                  value:
                    object: list
                    url: /v1/wealth/insights?investor=inv_01j9x8m2k7qpzwv3t5r6y8n0ab
                    has_more: false
                    data:
                      - id: ins_01j9x8m2k7qpzwv3t5r6y8n0ab
                        object: insight
                        livemode: false
                        metadata: {}
                        category: tax
                        title: Tax Optimization Opportunity
                        summary: You have $2,500 in unrealized losses that could offset gains
                        priority: high
                        impact_estimate: $625 tax savings
                        action:
                          type: tax_loss_harvest
                          description: Harvest losses in VTI position
                          cta_label: View Details
                        details:
                          position_symbol: XLF
                          unrealized_loss: '-2500.00'
                          wash_sale_eligible: true
                          replacement_suggestions:
                            - VFH
                            - IYF
                        expires_at: '2025-12-31T23:59:59Z'
                        status: active
                      - id: ins_01j9x8m2k7qpzwv3t5r6y8n0cd
                        object: insight
                        livemode: false
                        metadata: {}
                        category: opportunity
                        title: Outperforming Benchmark
                        summary: Your portfolio is outperforming the S&P 500 by 2.3% YTD
                        priority: informational
                        details:
                          portfolio_return_ytd: '12.5'
                          benchmark_return_ytd: '10.2'
                          alpha: '2.3'
                        status: active
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /wealth/accounts/{account_id}/recommendations:
    get:
      tags:
        - Insights & Recommendations
      summary: Get investment recommendations
      description: |
        Returns AI-powered investment recommendations based on the investor's IPS, goals, and market conditions.
        Includes allocation adjustments, security suggestions, and strategy recommendations.
      operationId: getRecommendations
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: type
          in: query
          required: false
          schema:
            type: string
            enum:
              - allocation
              - security
              - strategy
              - all
            default: all
          description: Filter by recommendation type
        - name: goal_id
          in: query
          required: false
          schema:
            type: string
            format: uuid
          description: Filter by specific goal
      responses:
        '200':
          description: Recommendations retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RecommendationList'
              examples:
                allocation_recommendations:
                  summary: Allocation recommendations
                  value:
                    object: list
                    url: /v1/wealth/recommendations?investor=inv_01j9x8m2k7qpzwv3t5r6y8n0ab
                    has_more: false
                    data:
                      - id: rec_01j9x8m2k7qpzwv3t5r6y8n0ab
                        object: recommendation
                        livemode: false
                        metadata: {}
                        type: allocation
                        title: Increase International Exposure
                        rationale: Your portfolio is underweight international equities compared to target allocation and global diversification best practices
                        confidence: high
                        expected_impact:
                          risk_adjusted_return_improvement: '0.3'
                          diversification_score_improvement: '5'
                        suggested_actions:
                          - action: buy
                            symbol: VXUS
                            name: Vanguard Total International Stock ETF
                            target_allocation: '10'
                            current_allocation: '5'
                      - id: rec_01j9x8m2k7qpzwv3t5r6y8n0cd
                        object: recommendation
                        livemode: false
                        metadata: {}
                        type: security
                        title: Consider Lower Cost ETF
                        rationale: You can reduce expense ratios by switching to a lower-cost equivalent ETF
                        confidence: medium
                        expected_impact:
                          risk_adjusted_return_improvement: '0.1'
                        suggested_actions:
                          - action: sell
                            symbol: SPY
                            name: SPDR S&P 500 ETF
                          - action: buy
                            symbol: VOO
                            name: Vanguard S&P 500 ETF
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /wealth/accounts/{account_id}/tax-optimization:
    get:
      tags:
        - Insights & Recommendations
      summary: Get tax optimization suggestions
      description: |
        Returns tax-aware investment suggestions including tax loss harvesting opportunities,
        long-term holding recommendations, and asset location optimization.
      operationId: getTaxOptimization
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: tax_year
          in: query
          required: false
          schema:
            type: integer
          description: Tax year (default is current year)
      responses:
        '200':
          description: Tax optimization suggestions retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TaxOptimization'
              examples:
                tax_opportunities:
                  summary: Tax optimization opportunities
                  value:
                    account_id: 3d0b0e65-35d3-4dcd-8df7-10286ebb4b4b
                    tax_year: 2025
                    generated_at: '2025-01-15T16:00:00Z'
                    tax_summary:
                      estimated_short_term_gains: '5000.00'
                      estimated_long_term_gains: '15000.00'
                      realized_losses_ytd: '2000.00'
                      harvestable_losses: '3500.00'
                    opportunities:
                      - opportunity_id: opp_001
                        type: tax_loss_harvest
                        title: Tax Loss Harvesting
                        description: Sell positions with unrealized losses to offset gains
                        estimated_tax_savings: '875.00'
                        positions:
                          - position_id: pos_xlf
                            symbol: XLF
                            unrealized_gain_loss: '-1500.00'
                            holding_period: short_term
                            wash_sale_risk: false
                            replacement_options:
                              - VFH
                              - IYF
                      - opportunity_id: opp_002
                        type: long_term_holding
                        title: Hold for Long-Term Treatment
                        description: Position approaching long-term capital gains threshold
                        estimated_tax_savings: '400.00'
                        positions:
                          - position_id: pos_aapl
                            symbol: AAPL
                            unrealized_gain_loss: '2000.00'
                            holding_period: short_term
                            days_until_long_term: 45
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /wealth/accounts/{account_id}/assistant/chat:
    post:
      tags:
        - Insights & Recommendations
      summary: AI assistant chat
      description: |
        Send a message to the AI assistant for investment-related questions.
        Returns a synchronous JSON response with the assistant's answer and optional action suggestions.
      operationId: assistantChat
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AssistantChatRequest'
            examples:
              allocation_question:
                summary: Question about allocation
                value:
                  message: What's my current allocation and should I rebalance?
                  context:
                    portfolio_id: port_a1b2c3d4e5f6
                    include_positions: true
              performance_question:
                summary: Question about performance
                value:
                  message: How has my portfolio performed compared to the S&P 500 this year?
                  context:
                    portfolio_id: port_a1b2c3d4e5f6
                    include_performance: true
              general_question:
                summary: General investment question
                value:
                  message: What is the next billion-dollar company?
      responses:
        '200':
          description: Assistant response generated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AssistantChatResponse'
              examples:
                allocation_response:
                  summary: Response about allocation
                  value:
                    response_id: resp_a1b2c3d4e5f6
                    message: |-
                      Based on your Investment Policy Statement, your target allocation is 50% equities, 25% bonds, 20% treasury, and 5% alternatives. Currently, your portfolio shows:

                      - Equities: 58% (+8% over target)
                      - Bonds: 22% (-3% under target)
                      - Treasury: 17% (-3% under target)
                      - Alternatives: 3% (-2% under target)

                      Your equity allocation has drifted beyond the 5% threshold in your IPS. I recommend rebalancing to bring your portfolio back in line with your target allocation.
                    suggestions:
                      - type: action
                        label: View Rebalancing Trades
                        action_url: /wealth/accounts/{account_id}/portfolios/{portfolio_id}/rebalancing
                    context_used:
                      - portfolio_summary
                      - ips
                      - positions
                    created_at: '2025-01-15T16:00:00Z'
        '400':
          $ref: '#/components/responses/BadRequestError'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /wealth/accounts/{account_id}/statements:
    get:
      tags:
        - Reports
      summary: Get account statement
      description: |
        Generates an account statement for a specified period.
        Includes portfolio summary, activity (deposits, withdrawals, trades, dividends), and end-of-period holdings.
        Supports JSON and PDF formats.
      operationId: getAccountStatement
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: period
          in: query
          required: false
          schema:
            type: string
            enum:
              - monthly
              - quarterly
              - annual
              - custom
            default: monthly
          description: Statement period type
        - name: start_date
          in: query
          required: false
          schema:
            type: string
            format: date
          description: Start date for custom period
        - name: end_date
          in: query
          required: false
          schema:
            type: string
            format: date
          description: End date for custom period
        - name: format
          in: query
          required: false
          schema:
            type: string
            enum:
              - json
              - pdf
            default: json
          description: Response format
      responses:
        '200':
          description: Account statement generated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AccountStatement'
              examples:
                quarterly_statement:
                  summary: Q4 2024 statement
                  value:
                    statement_id: stmt_a1b2c3d4e5f6
                    account_id: 3d0b0e65-35d3-4dcd-8df7-10286ebb4b4b
                    period:
                      start_date: '2024-10-01'
                      end_date: '2024-12-31'
                      label: Q4 2024
                    summary:
                      beginning_value: '100000.00'
                      ending_value: '110000.00'
                      net_change: '10000.00'
                      net_change_percent: '10.00'
                      contributions: '5000.00'
                      withdrawals: '0.00'
                      investment_returns: '5000.00'
                      fees: '125.00'
                    activity:
                      deposits:
                        - date: '2024-10-15'
                          amount: '2500.00'
                          method: ACH
                        - date: '2024-11-15'
                          amount: '2500.00'
                          method: ACH
                      withdrawals: []
                      trades:
                        - date: '2024-10-16'
                          symbol: VTI
                          action: buy
                          quantity: '10.00'
                          price: '245.00'
                          amount: '2450.00'
                      dividends:
                        - date: '2024-12-15'
                          symbol: VTI
                          amount: '125.00'
                      fees:
                        - date: '2024-12-31'
                          type: management_fee
                          amount: '125.00'
                    holdings_end_of_period:
                      - symbol: VTI
                        quantity: '200.00'
                        market_value: '50000.00'
                      - symbol: BND
                        quantity: '400.00'
                        market_value: '32000.00'
                    generated_at: '2025-01-15T10:00:00Z'
            application/pdf:
              schema:
                type: string
                format: binary
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /wealth/accounts/{account_id}/reports/pnl:
    get:
      tags:
        - Reports
      summary: Get P&L report
      description: |
        Returns a detailed profit and loss breakdown for the account.
        Includes realized and unrealized gains/losses, dividend income, and breakdowns by position and asset class.
      operationId: getPnlReport
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: start_date
          in: query
          required: false
          schema:
            type: string
            format: date
          description: Report start date
        - name: end_date
          in: query
          required: false
          schema:
            type: string
            format: date
          description: Report end date
        - name: realized_only
          in: query
          required: false
          schema:
            type: boolean
            default: false
          description: Only show realized P&L
      responses:
        '200':
          description: P&L report generated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PnlReport'
              examples:
                annual_pnl:
                  summary: Annual P&L report
                  value:
                    account_id: 3d0b0e65-35d3-4dcd-8df7-10286ebb4b4b
                    period:
                      start_date: '2024-01-01'
                      end_date: '2024-12-31'
                    summary:
                      total_pnl: '25000.00'
                      realized_pnl: '10000.00'
                      unrealized_pnl: '15000.00'
                      dividend_income: '3000.00'
                      interest_income: '500.00'
                      fees_paid: '300.00'
                    realized_gains_losses:
                      short_term_gains: '3000.00'
                      short_term_losses: '-500.00'
                      long_term_gains: '8000.00'
                      long_term_losses: '-500.00'
                      net_realized: '10000.00'
                    by_position:
                      - symbol: AAPL
                        realized_pnl: '2500.00'
                        unrealized_pnl: '5000.00'
                        dividend_income: '500.00'
                      - symbol: VTI
                        realized_pnl: '4000.00'
                        unrealized_pnl: '8000.00'
                        dividend_income: '1500.00'
                      - symbol: BND
                        realized_pnl: '500.00'
                        unrealized_pnl: '2000.00'
                        dividend_income: '1000.00'
                    by_asset_class:
                      - asset_class: equities
                        pnl: '20000.00'
                        pnl_percent: '15.00'
                      - asset_class: fixed_income
                        pnl: '5000.00'
                        pnl_percent: '8.00'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
  /wealth/accounts/{account_id}/reports/benchmark:
    get:
      tags:
        - Reports
      summary: Get benchmark comparison report
      description: |
        Compares portfolio performance against one or more benchmarks.
        Includes alpha, beta, correlation, and tracking error metrics.
      operationId: getBenchmarkReport
      parameters:
        - name: account_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: benchmarks
          in: query
          required: false
          schema:
            type: string
          description: Comma-separated benchmark symbols (e.g., "SPY,AGG")
        - name: period
          in: query
          required: false
          schema:
            type: string
            enum:
              - 1m
              - 3m
              - 6m
              - ytd
              - 1y
              - 3y
              - 5y
            default: 1y
          description: Comparison period
      responses:
        '200':
          description: Benchmark comparison report generated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BenchmarkReport'
              examples:
                multi_benchmark:
                  summary: Comparison against SPY and AGG
                  value:
                    account_id: 3d0b0e65-35d3-4dcd-8df7-10286ebb4b4b
                    period: 1y
                    portfolio_return: '12.50'
                    comparisons:
                      - benchmark: SPY
                        name: S&P 500 ETF
                        return: '10.20'
                        alpha: '2.30'
                        correlation: '0.92'
                        beta: '0.95'
                        tracking_error: '3.50'
                      - benchmark: AGG
                        name: Bloomberg US Aggregate Bond
                        return: '5.10'
                        alpha: '7.40'
                        correlation: '0.35'
                        beta: '0.20'
                        tracking_error: '12.00'
                    chart_data:
                      dates:
                        - '2024-01-15'
                        - '2024-04-15'
                        - '2024-07-15'
                        - '2024-10-15'
                        - '2025-01-15'
                      portfolio:
                        - 100
                        - 103.5
                        - 107.2
                        - 109.8
                        - 112.5
                      benchmarks:
                        SPY:
                          - 100
                          - 102.8
                          - 105.5
                          - 108.1
                          - 110.2
                        AGG:
                          - 100
                          - 101.2
                          - 102.5
                          - 103.8
                          - 105.1
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '404':
          $ref: '#/components/responses/NotFoundError'
components:
  securitySchemes:
    BluumApiKeyAuth:
      type: http
      scheme: basic
      description: |
        HTTP Basic Authentication using the **API Key** as username and **API Secret** as password.
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: |
        JWT token from Clerk authentication
  schemas:
    NewAccountRequest:
      description: |
        flat investor creation body. Regulatory fields live at
        the top level; only `address`, `signed_agreements[]`, and
        `trusted_contact` are nested (each is an independent sub-object).
      type: object
      required:
        - account_type
        - first_name
        - last_name
        - date_of_birth
        - email
        - phone
        - address
        - tax_id
        - tax_id_type
        - country_of_tax_residence
        - country_of_citizenship
        - country_of_birth
        - funding_source
        - annual_income
        - liquid_net_worth
        - is_control_person
        - is_affiliated_exchange_or_finra
        - is_politically_exposed
        - immediate_family_exposed
        - employment_status
        - signed_agreements
      properties:
        account_type:
          type: string
          enum:
            - individual
            - joint
            - corporate
          example: individual
        management_type:
          type: string
          enum:
            - self_directed
            - advised
          default: self_directed
        tax_advantaged:
          type: boolean
          default: false
        tax_designation:
          type: string
          nullable: true
        first_name:
          type: string
          example: Jane
        middle_name:
          type: string
          nullable: true
        last_name:
          type: string
          example: Doe
        date_of_birth:
          type: string
          format: date
          example: '1990-01-01'
        email:
          type: string
          format: email
          example: jane@example.com
        phone:
          type: string
          example: '+15555550123'
        address:
          type: object
          required:
            - street
            - city
            - country
          properties:
            street:
              type: array
              items:
                type: string
              minItems: 1
              description: One or more street lines (the array form is required even for single-line addresses).
              example:
                - 123 Market St
            unit:
              type: string
              nullable: true
            city:
              type: string
              example: Berkeley
            state:
              type: string
              description: Required for US tax residents. Optional otherwise.
              example: CA
            postal_code:
              type: string
              description: Required for US tax residents (5 digits, optionally `-4 digits`). Optional otherwise.
              example: '94704'
            country:
              type: string
              description: ISO 3166-1 alpha-2 country code.
              example: US
        tax_id:
          type: string
          example: 401-23-4567
        tax_id_type:
          type: string
          enum:
            - SSN
            - ITIN
            - EIN
            - SIN
            - NINO
            - TFN
            - VAT
            - TIN
            - OTHER
        tax_id_country:
          type: string
          description: ISO 3166-1 alpha-2 of the tax-id issuing country.
          nullable: true
        country_of_tax_residence:
          type: string
          example: US
        country_of_citizenship:
          type: string
          example: US
        country_of_birth:
          type: string
          example: US
        funding_source:
          type: array
          items:
            type: string
            enum:
              - employment_income
              - investments
              - inheritance
              - business_income
              - savings
              - family
              - other
          example:
            - employment_income
        annual_income:
          type: object
          properties:
            min:
              type: string
            max:
              type: string
        liquid_net_worth:
          type: object
          properties:
            min:
              type: string
            max:
              type: string
        total_net_worth:
          type: object
          properties:
            min:
              type: string
            max:
              type: string
        permanent_resident:
          type: boolean
          nullable: true
        visa_type:
          type: string
          nullable: true
        visa_expiration_date:
          type: string
          format: date
          nullable: true
        is_control_person:
          type: boolean
        is_affiliated_exchange_or_finra:
          type: boolean
        is_affiliated_exchange_or_iiroc:
          type: boolean
          nullable: true
        is_politically_exposed:
          type: boolean
        immediate_family_exposed:
          type: boolean
        affiliated_company:
          type: object
          nullable: true
          properties:
            company_name:
              type: string
            company_address:
              type: string
            company_compliance_email:
              type: string
        employment_status:
          type: string
          enum:
            - employed
            - unemployed
            - student
            - retired
        employer_name:
          type: string
          nullable: true
        employer_address:
          type: string
          nullable: true
        employment_position:
          type: string
          nullable: true
        signed_agreements:
          type: array
          minItems: 2
          description: |
            Audit trail for each regulated acknowledgement the user clicked.
            Must contain at least `investor_agreement` and
            `margin_disclosure_acknowledged`; non-US tax residents must
            additionally include `w8ben_certification`.
          items:
            type: object
            required:
              - type
              - signed_at
              - ip_address
            properties:
              type:
                type: string
                enum:
                  - investor_agreement
                  - margin_disclosure_acknowledged
                  - w8ben_certification
                example: investor_agreement
              signed_at:
                type: string
                format: date-time
                description: ISO-8601 timestamp when the user clicked Accept.
              ip_address:
                type: string
                description: Client IP address at the time of click.
        trusted_contact:
          $ref: '#/components/schemas/TrustedContact'
        metadata:
          type: object
          additionalProperties:
            type: string
    Account:
      $ref: '#/components/schemas/Investor'
    ComplianceStatus:
      description: |
        Compliance-workflow status returned by
        `GET /v1/investors/{investor_id}/compliance`. Wraps the latest
        workflow with envelope keys (`object: 'compliance_workflow'`,
        `livemode`). `status` is the Buildmarkets-native external vocab
        (`running` / `awaiting_review` / `approved` / `declined` /
        `suspended` / `expired`); `workflow_status` is the internal
        UPPER_CASE value retained for partners that want the raw enum.
      type: object
      required:
        - object
        - livemode
        - investor_id
        - workflow_status
        - workflow_type
        - checks
        - created_at
        - updated_at
      additionalProperties: true
      properties:
        object:
          type: string
          enum:
            - compliance_workflow
        livemode:
          type: boolean
        investor_id:
          type: string
          description: Prefixed public id of the investor.
          example: inv_01j9x8m2k7qpzwv3t5r6y8n0ab
        workflow_status:
          type: string
          enum:
            - IN_PROGRESS
            - PENDING_REVIEW
            - APPROVED
            - REJECTED
            - SUSPENDED
            - EXPIRED
          description: Internal Alpaca-aligned UPPER_CASE workflow status.
          example: APPROVED
        status:
          type: string
          enum:
            - running
            - awaiting_review
            - approved
            - declined
            - suspended
            - expired
          description: Buildmarkets-native external workflow status.
          example: approved
        workflow_type:
          type: string
          enum:
            - kyc
            - kyb
            - periodic_review
          description: Type of compliance workflow.
          example: kyc
        risk_level:
          type: string
          enum:
            - low
            - medium
            - high
            - prohibited
            - null
          nullable: true
          description: Assessed risk level. Null while checks are still in progress.
          example: low
        checks:
          type: array
          description: Individual compliance check results.
          items:
            type: object
            properties:
              type:
                type: string
                enum:
                  - identity_verification
                  - tax_id_verification
                  - screening
                  - risk_assessment
                  - business_verification
                description: The type of compliance check.
                example: identity_verification
              status:
                type: string
                enum:
                  - pending
                  - clear
                  - review_required
                  - failed
                  - error
                description: Result of the check.
                example: clear
              completed_at:
                type: string
                format: date-time
                nullable: true
                description: When this check completed. Null if still pending.
                example: '2026-03-15T10:05:00.000Z'
        created_at:
          type: string
          format: date-time
          description: When the compliance workflow was initiated.
          example: '2026-03-15T10:00:00.000Z'
        updated_at:
          type: string
          format: date-time
          description: When the compliance workflow was last updated.
          example: '2026-03-15T10:05:00.000Z'
    DocumentUploadRequest:
      type: object
      required:
        - file
        - document_type
      properties:
        file:
          type: string
          format: binary
          description: The binary content of the document file (e.g., PDF or JPG).
        document_type:
          type: string
          enum:
            - id_verification
            - proof_of_address
            - w9_form
          description: The type of document being uploaded.
    DocumentResponse:
      description: |
        Document resource returned by `/v1/documents` endpoints. Uses the
        flat document shape: `document_id` is the public id, `owner_type` /
        `owner_id` are polymorphic ownership refs (INVESTOR / USER /
        TENANT). `purpose` indicates what the doc is for (KYC, KYB, EDD,
        TAX, FUNDING_VERIFICATION, AGREEMENT, OTHER).
      type: object
      required:
        - document_id
        - object
        - owner_type
        - owner_id
        - document_type
        - file_name
        - mime_type
        - status
        - uploaded_at
      properties:
        document_id:
          type: string
          example: doc_01j9x8m2k7qpzwv3t5r6y8n0ab
        object:
          type: string
          enum:
            - document
        owner_type:
          type: string
          enum:
            - tenant
            - investor
            - user
        owner_id:
          type: string
          description: UUID of the owning entity (raw, not prefix-encoded).
        purpose:
          type: string
          enum:
            - kyc
            - kyb
            - edd
            - tax
            - funding_verification
            - agreement
            - account_statement
            - trade_confirmation
            - other
          nullable: true
        document_type:
          type: string
          description: Free-form classifier (e.g. PASSPORT, BANK_STATEMENT, CIP_RESULT).
          example: id_verification
        file_name:
          type: string
          example: id-front.png
        mime_type:
          type: string
          example: image/png
        file_size:
          type: integer
          nullable: true
        status:
          type: string
          enum:
            - uploaded
            - processing
            - accepted
            - rejected
            - expired
        expires_at:
          type: string
          format: date-time
          nullable: true
        uploaded_at:
          type: string
          format: date-time
        metadata:
          type: object
          nullable: true
          additionalProperties: true
    OrderRequest:
      type: object
      required:
        - symbol
        - side
        - type
        - time_in_force
      properties:
        symbol:
          type: string
          description: The ticker symbol of the asset (e.g., AAPL).
          example: AAPL
        market:
          type: string
          description: Market identifier (e.g., "NASDAQ", "NYSE"). Optional.
          example: NASDAQ
        isin:
          type: string
          description: International Securities Identification Number. Optional.
          example: US0378331005
        figi:
          type: string
          description: Financial Instrument Global Identifier. Optional.
          example: BBG000B9XRY4
        class:
          type: string
          description: |
            Optional asset class hint (e.g. `bond`, `equity`, `treasury`).
            Mirrors the `class` field on the asset detail response. When
            `bond`, the resolver accepts the `symbol` field as a CUSIP on
            fallback — ticker collisions like ABBNVX (two distinct ABB
            Finance bonds sharing the same ticker) cannot be disambiguated
            by symbol alone.
          example: bond
        country:
          type: string
          description: Optional ISO country code (e.g. `us`) to help disambiguate cross-listed assets.
          example: us
        quantity:
          type: string
          description: Quantity of shares to trade (required if notional not provided, required for sell orders).
          example: '5'
        notional:
          type: string
          description: Dollar amount to trade (required if quantity not provided, only for buy market orders).
          example: '1000.00'
        side:
          type: string
          enum:
            - buy
            - sell
          description: Whether to buy or sell the asset.
          example: buy
        type:
          type: string
          enum:
            - market
            - limit
            - stop
            - stop_limit
            - trailing_stop
          description: |
            Order type:
            - market: Executes immediately at current market price
            - limit: Sets a specific price limit
            - stop: Stop loss order that triggers at stop price
            - stop_limit: Stop order with a limit price
            - trailing_stop: Trailing stop order
          example: limit
        time_in_force:
          type: string
          enum:
            - day
            - gtc
            - opg
            - cls
            - ioc
            - fok
          description: |
            How long the order remains active:
            - day: Expires at end of trading day
            - gtc: Good Till Cancelled - remains active until filled or cancelled
            - opg: Opening - executes at market open
            - cls: Closing - executes at market close
            - ioc: Immediate or Cancel - fills immediately or cancels
            - fok: Fill or Kill - fills completely or cancels
          example: day
        limit_price:
          type: string
          description: Price limit for limit/stop_limit orders (required when type is 'limit' or 'stop_limit').
          example: '175.00'
        stop_price:
          type: string
          description: Stop price for stop/stop_limit orders (required when type is 'stop' or 'stop_limit').
          example: '170.00'
        trail_percent:
          type: string
          description: Trail percentage for trailing stop orders (required for trailing_stop if trail_price not provided).
          example: '2.5'
        trail_price:
          type: string
          description: Trail price for trailing stop orders (required for trailing_stop if trail_percent not provided).
          example: '5.00'
        extended_hours:
          type: boolean
          default: false
          description: Whether to allow extended hours trading.
          example: false
        client_order_id:
          type: string
          description: Optional client-provided identifier for tracking the order.
          example: limitorder123
        commission:
          type: string
          description: Commission amount to charge (optional).
          example: '1.00'
        commission_type:
          type: string
          enum:
            - notional
            - per_share
            - bps
          description: |
            Commission calculation method:
            - notional: Charge commission on a per order basis (default)
            - per_share: Charge commission on a per-share/contract basis, pro rated
            - bps: Percent commission in basis points (up to 2 decimal places)
          example: notional
        wallet_currency:
          type: string
          enum:
            - USD
            - NGN
            - GBP
            - EUR
            - KES
          description: |
            Wallet currency to fund or receive trade proceeds. When omitted,
            defaults to USD (default wallet).
          example: NGN
    Order:
      description: |
        Trading order resource. Flat shape: `quantity` not `qty`,
        `failure_reason` not `reject_reason`, `investor_id` not `account_id`,
        Buildmarkets-native status vocab. Drops the custodian's `submitted_at` (the envelope
        `created` field is the canonical creation timestamp).
      allOf:
        - $ref: '#/components/schemas/ResourceEnvelope'
        - type: object
          properties:
            investor_id:
              type: string
              description: Prefixed public id of the investor.
              example: inv_01j9x8m2k7qpzwv3t5r6y8n0ab
            symbol:
              type: string
              example: AAPL
            class:
              type: string
              description: Asset class name (e.g. equity, bond, etf).
              example: equity
            currency:
              type: string
              example: USD
            quantity:
              type: string
              description: Quantity of shares ordered (for quantity-based orders).
              example: '5'
            notional:
              type: string
              description: Notional amount ordered (for notional-based orders).
              example: '1000.00'
            side:
              type: string
              enum:
                - buy
                - sell
            type:
              type: string
              enum:
                - market
                - limit
                - stop
                - stop_limit
                - trailing_stop
            time_in_force:
              type: string
              description: |
                FIX-standard time-in-force; not Alpaca-coined.
              enum:
                - day
                - gtc
                - opg
                - cls
                - ioc
                - fok
            limit_price:
              type: string
            stop_price:
              type: string
            trail_percent:
              type: string
            trail_price:
              type: string
            extended_hours:
              type: boolean
            client_order_id:
              type: string
            status:
              type: string
              description: Buildmarkets-native order status.
              enum:
                - pending
                - filled
                - partial
                - cancelled
                - failed
              example: pending
            filled_quantity:
              type: string
              example: '0'
            remaining_quantity:
              type: string
              example: '5'
            average_price:
              type: string
            commission:
              type: string
            commission_type:
              type: string
              enum:
                - notional
                - per_share
                - bps
            filled_at:
              type: string
              format: date-time
              nullable: true
            cancelled_at:
              type: string
              format: date-time
              nullable: true
            failure_reason:
              type: string
              nullable: true
            settlement_date:
              type: string
              format: date
              nullable: true
              description: |
                Settlement date Alpaca will use for bond orders, when
                known. Buildmarkets does not specify or override this — Alpaca
                chooses based on the bond's subtype. Null for non-bond
                orders or until Alpaca confirms.
              example: '2026-05-22'
            bond:
              $ref: '#/components/schemas/OrderBondExecutionDetails'
    AssetSearchResult:
      type: object
      description: Asset information including metadata and current price data
      properties:
        id:
          type: string
          description: Unique identifier for the asset
          example: b0b6dd9d-8b9b-48b9-bbb8-bbbb49bb1bbb
        class:
          type: string
          enum:
            - equity
            - etf
            - bond
            - bill
            - note
            - mutual_fund
            - derivative
            - cryptocurrency
            - commodity
            - real_estate
            - cash
          description: |
            Canonical instrument class. Combine with `country` for the full picture
            (e.g. `class=equity` + `country=us` corresponds to a US stock).
          example: equity
        country:
          type: string
          nullable: true
          description: ISO 3166-1 alpha-2 country code (lower-case). Null for country-agnostic instruments.
          example: us
        asset_class:
          type: string
          enum:
            - us_equity
            - crypto
            - us_option
            - ng_equity
            - ng_bond
            - ng_etf
          deprecated: true
          description: |
            **Deprecated.** Combined legacy classifier. Use `class` + `country` instead.
            Populated for backwards-compat during Phase 1 of the asset-class refactor;
            scheduled for removal once partners migrate.
          example: us_equity
        market:
          type: string
          description: |
            Market/exchange code (ISO 10383 MIC):
            - XNAS: NASDAQ
            - XNYS: NYSE
            - BATS: BATS Global Markets
            - ARCA: NYSE Arca
            - OTC: OTC Markets
            - XNSA: Nigerian Stock Exchange
          example: XNAS
        symbol:
          type: string
          description: Asset ticker symbol. For fixed-income assets this is the bond ticker when Alpaca provides one (corporates, e.g. "ABBNVX"); treasuries, which have no ticker, fall back to the CUSIP. The CUSIP is always available as `id` and under `bond.cusip`.
          example: AAPL
        name:
          type: string
          description: Full name of the asset
          example: Apple Inc.
        status:
          type: string
          enum:
            - active
            - inactive
          description: Asset status
          example: active
        tradable:
          type: boolean
          description: Whether the asset is currently tradable
          example: true
        marginable:
          type: boolean
          description: Whether the asset can be traded on margin
          example: true
        shortable:
          type: boolean
          description: Whether the asset can be shorted
          example: true
        easy_to_borrow:
          type: boolean
          description: Whether the asset is easy to borrow for shorting
          example: true
        fractionable:
          type: boolean
          description: Whether the asset can be traded in fractional shares
          example: true
        fractional_eh_enabled:
          type: boolean
          description: Whether the asset supports fractional trading during extended hours (pre/post market)
          example: true
        price:
          type: number
          description: Current/last traded price (optional, when available)
          example: 178.5
        change:
          type: number
          description: Price change from previous close (optional)
          example: 1.5
        changePercent:
          type: number
          description: Percentage change from previous close (optional)
          example: 0.85
        previousClose:
          type: number
          description: Previous day's closing price (optional)
          example: 177
        bidPrice:
          type: number
          description: Current best bid price (optional)
          example: 178.48
        askPrice:
          type: number
          description: Current best ask price (optional)
          example: 178.52
        currency:
          type: string
          description: Currency code for asset pricing (ISO 4217)
          example: USD
        price_timestamp:
          type: string
          format: date-time
          nullable: true
          description: When the price was recorded by its source. Use this to judge price recency.
          example: '2026-05-29T20:00:00.000Z'
        last_synced_at:
          type: string
          format: date-time
          nullable: true
          description: When the asset row was last refreshed from its provider. Null for live (never-persisted) results.
          example: '2026-06-01T02:12:31.000Z'
        bond:
          $ref: '#/components/schemas/BondAttributes'
      required:
        - id
        - class
        - country
        - market
        - symbol
        - name
        - status
        - tradable
        - marginable
        - shortable
        - easy_to_borrow
        - fractionable
        - fractional_eh_enabled
        - currency
    ChartResponse:
      type: object
      properties:
        symbol:
          type: string
          description: Asset ticker symbol
          example: AAPL
        bars:
          type: array
          items:
            $ref: '#/components/schemas/ChartBar'
          description: Array of historical bars
        nextPageToken:
          type: string
          nullable: true
          description: Token for pagination to get next page of results.
          example: eyJpZCI6IjIwMjUtMDEtMTVUMTY6MDA6MDBaIiwiY3JlYXRlZEF0IjoiMjAyNS0wMS0xNVQxNjowMDowMFoifQ
      required:
        - symbol
        - bars
    ChartBar:
      type: object
      properties:
        timestamp:
          type: string
          format: date-time
          description: Bar timestamp (ISO 8601 format)
          example: '2025-01-15T16:00:00Z'
        open:
          type: number
          description: Opening price
          example: 150.25
        high:
          type: number
          description: Highest price
          example: 152.5
        low:
          type: number
          description: Lowest price
          example: 149.8
        close:
          type: number
          description: Closing price
          example: 151.75
        volume:
          type: integer
          description: Trading volume
          example: 5000000
        tradeCount:
          type: integer
          description: Number of trades (optional)
          example: 12500
        volumeWeightedAveragePrice:
          type: number
          description: Volume weighted average price (optional)
          example: 151.2
      required:
        - timestamp
        - open
        - high
        - low
        - close
        - volume
    Wallet:
      description: |
        A wallet holds a balance for a specific currency within an investor
        account. Envelope-wrapped.
      allOf:
        - $ref: '#/components/schemas/ResourceEnvelope'
        - type: object
          required:
            - currency
            - balance
            - available_balance
            - reserved_balance
            - status
          properties:
            currency:
              type: string
              minLength: 3
              maxLength: 3
              example: USD
            balance:
              type: string
              description: Total balance (available + reserved).
            available_balance:
              type: string
            reserved_balance:
              type: string
            cash_withdrawable:
              type: string
              description: Amount of cash available for withdrawal from the custodian brokerage account. Defaults to "0" when no custodian account exists yet.
              example: '5000.00'
            buying_power:
              type: string
              description: Available buying power from the custodian brokerage account. Defaults to "0" when no custodian account exists yet.
              example: '10000.00'
            equity:
              type: string
              description: Total equity value from the custodian brokerage account. Defaults to "0" when no custodian account exists yet.
              example: '8500.00'
            status:
              type: string
              enum:
                - active
                - suspended
                - closed
    Transaction:
      description: |
        A cash movement on the investor's account: a `deposit`, a
        `withdrawal`, a `buy` / `sell` trade settlement from a filled
        order, or an `activity` (non-trade account activity — dividends,
        fees, interest, fixed-income maturity, journals, withholdings,
        corporate actions). Envelope-wrapped.
      allOf:
        - $ref: '#/components/schemas/ResourceEnvelope'
        - type: object
          required:
            - investor_id
            - wallet_id
            - type
            - status
            - amount
            - currency
            - method
          properties:
            investor_id:
              type: string
              description: Prefixed public id of the owning investor.
            wallet_id:
              type: string
              description: |
                Prefixed public id of the wallet. Empty string for
                `activity` rows (custodian activities aren't scoped to
                a Buildmarkets wallet).
            type:
              type: string
              enum:
                - deposit
                - withdrawal
                - buy
                - sell
                - activity
            status:
              type: string
              description: |
                Funding status for deposit/withdrawal, `completed` for
                trade cash movements, or the lowercased activity status
                (typically `executed`) for activity rows.
            amount:
              type: string
              description: |
                Positive amount in wallet currency for deposit / withdrawal /
                trade rows. Activity rows carry the signed net amount
                (positive = credit, negative = debit).
            currency:
              type: string
              minLength: 3
              maxLength: 3
            method:
              type: string
              description: |
                Funding rail (e.g. `ach`, `wire`), `order` for buy/sell
                cash, or `activity` for custodian activity rows.
            description:
              type: string
              nullable: true
            completed_at:
              type: string
              format: date-time
              nullable: true
            failed_at:
              type: string
              format: date-time
              nullable: true
            failure_reason:
              type: string
              nullable: true
            activity_type:
              type: string
              description: |
                Activity tag (`FIMAT`, `CDIV`, `SDIV`, `DIVNRA`, `FEE`,
                `INT`, `JNLC`, `JNLS`, `ACATC`, `ACATS`, corporate-action
                tags, etc.). Present only when `type === activity`.
            activity_subtype:
              type: string
              nullable: true
              description: Activity subtype, when one applies (e.g. `REG`, `TAF`, `OCC`). Present only when `type === activity`.
            symbol:
              type: string
              description: |
                Ticker symbol of the asset traded. Present only when
                `type` is `buy` or `sell`, sourced from the originating
                order.
              example: AAPL
            quantity:
              type: string
              description: |
                Requested order quantity (decimal string, up to 9 d.p.).
                Present only for `buy` / `sell` rows.
              example: '5'
            filled_quantity:
              type: string
              description: |
                Filled quantity (decimal string, up to 9 d.p.). Present
                only for `buy` / `sell` rows.
              example: '5'
            average_price:
              type: string
              description: |
                Average fill price per share in the wallet currency.
                Present only for `buy` / `sell` rows.
              example: '151.05'
            notional:
              type: string
              description: |
                Notional / cost basis of the trade in the wallet
                currency (gross, before commission). Present only for
                `buy` / `sell` rows.
              example: '755.25'
            commission:
              type: string
              description: |
                Commission charged on the trade in the wallet currency.
                Present only for `buy` / `sell` rows.
              example: '0.00'
            net_amount:
              type: string
              description: |
                Net cash impact in the wallet currency after commission
                (positive for buy debits, positive for sell credits).
                Present only for `buy` / `sell` rows.
              example: '755.25'
    Position:
      description: Envelope-wrapped position resource.
      allOf:
        - $ref: '#/components/schemas/ResourceEnvelope'
        - type: object
          properties:
            investor_id:
              type: string
              description: Prefixed public id of the owning investor.
              example: inv_01j9x8m2k7qpzwv3t5r6y8n0ab
            symbol:
              type: string
              example: AAPL
            asset_id:
              type: string
            class:
              type: string
              enum:
                - equity
                - etf
                - bond
                - bill
                - note
                - mutual_fund
                - derivative
                - cryptocurrency
                - commodity
                - real_estate
                - cash
              description: Canonical instrument class of the held asset.
              example: equity
            country:
              type: string
              nullable: true
              description: ISO 3166-1 alpha-2 country code (lower-case). Null for country-agnostic instruments.
              example: us
            asset_class:
              type: string
              deprecated: true
              nullable: true
              description: |
                **Deprecated.** Combined legacy classifier (`us_equity`, `ng_bond`, ...).
                Populated for backwards-compat during Phase 1 of the asset-class refactor.
                Use `class` + `country` instead.
              example: us_equity
            currency:
              type: string
              example: USD
            quantity:
              type: string
              example: '10.5'
            average_cost_basis:
              type: string
              example: '175.50'
            total_cost_basis:
              type: string
              example: '1842.75'
            current_price:
              type: string
              example: '180.00'
            market_value:
              type: string
              example: '1890.00'
            unrealized_pl:
              type: string
              example: '47.25'
            unrealized_pl_percent:
              type: string
              example: '2.56'
            price_source:
              type: string
              enum:
                - ALPACA
                - NAYA
                - DATABASE
                - UNAVAILABLE
            price_confidence:
              type: string
              enum:
                - REAL_TIME
                - DELAYED
                - END_OF_DAY
                - STALE
                - UNAVAILABLE
            price_timestamp:
              type: string
              format: date-time
              nullable: true
            last_transaction_at:
              type: string
              format: date-time
              nullable: true
            updated_at:
              type: string
              format: date-time
    LinkTokenResponse:
      type: object
      properties:
        status:
          type: string
          example: success
        data:
          type: object
          properties:
            link_token:
              type: string
              description: Plaid Link token for initializing Plaid Link
              example: link-production-abc123def456
            hosted_link_url:
              type: string
              format: uri
              nullable: true
              description: |
                Hosted Link URL (only present when enable_hosted_link was set to true).
                Direct users to this URL to start the Plaid-hosted bank linking flow.
                After completion, Plaid redirects back to your application.
              example: https://hosted.plaid.com/link/abc123def456
    FundingSource:
      description: |
        A connected funding source (bank account) that can be used for
        deposits and withdrawals. Envelope-wrapped.
      allOf:
        - $ref: '#/components/schemas/ResourceEnvelope'
        - type: object
          properties:
            type:
              type: string
              enum:
                - plaid
                - manual
            status:
              type: string
              enum:
                - active
                - disconnected
                - error
            bank_name:
              type: string
              nullable: true
            mask:
              type: string
              nullable: true
            provider_id:
              type: string
              description: Plaid `item_id` for Plaid sources.
            account_name:
              type: string
              nullable: true
            account_type:
              type: string
              nullable: true
            account_subtype:
              type: string
              nullable: true
            account_holder_name:
              type: string
              nullable: true
              description: Legal name of the account holder.
            bank_account_type:
              type: string
              nullable: true
              enum:
                - CHECKING
                - SAVINGS
              description: Type of bank account.
            account_number:
              type: string
              nullable: true
              description: Masked account number (last 4 digits visible).
            routing_number:
              type: string
              nullable: true
              description: Bank routing number (ABA for US banks).
            swift_code:
              type: string
              nullable: true
              description: SWIFT/BIC code for international wires.
            iban:
              type: string
              nullable: true
              description: Masked IBAN (last 4 digits visible).
            wire_routing_kind:
              type: string
              nullable: true
              description: 'Routing code type: aba, sort_code, ifsc, etc.'
            bank_code:
              type: string
              nullable: true
              description: Bank-specific code (used in some regions).
            beneficiary_address:
              type: string
              nullable: true
              description: Beneficiary address as a single string (legacy field).
            address_line_1:
              type: string
              nullable: true
              description: Street address for wire payout beneficiary.
            payout_country:
              type: string
              nullable: true
              description: ISO 3166-1 alpha-2 country code for wire payout beneficiary.
            payout_currency:
              type: string
              nullable: true
              description: ISO 4217 currency code for wire payout beneficiary.
            payout_city:
              type: string
              nullable: true
              description: City for wire payout beneficiary.
            payout_region:
              type: string
              nullable: true
              description: State or region for wire payout beneficiary.
            payout_postal_code:
              type: string
              nullable: true
              description: Postal code for wire payout beneficiary.
            wire_payout_complete:
              type: boolean
              description: Whether enough fields are populated for a wire payout via the custodian.
            metadata:
              type: object
              description: Arbitrary key-value metadata attached to the funding source.
            updated_at:
              type: string
              format: date-time
    ConnectFundingSourceRequest:
      oneOf:
        - $ref: '#/components/schemas/ConnectPlaidRequest'
        - $ref: '#/components/schemas/ConnectManualRequest'
      discriminator:
        propertyName: type
        mapping:
          plaid: '#/components/schemas/ConnectPlaidRequest'
          manual: '#/components/schemas/ConnectManualRequest'
    Webhook:
      description: Envelope-wrapped webhook subscription.
      allOf:
        - $ref: '#/components/schemas/ResourceEnvelope'
        - type: object
          required:
            - event_types
            - name
            - url
          properties:
            event_types:
              type: array
              items:
                $ref: '#/components/schemas/EventType'
            name:
              type: string
            url:
              type: string
              format: uri
            description:
              type: string
              nullable: true
            status:
              type: string
              enum:
                - ACTIVE
                - INACTIVE
              default: ACTIVE
            secret:
              type: string
              nullable: true
              description: Secret for webhook signature verification (HMAC).
            updated_at:
              type: string
              format: date-time
    CreateWebhookRequest:
      type: object
      required:
        - eventTypeNames
        - name
        - url
      properties:
        eventTypeNames:
          type: array
          items:
            type: string
          description: Array of webhook event type names (at least one required)
        name:
          type: string
          description: Human-readable name for the webhook
        url:
          type: string
          format: uri
          description: Webhook URL endpoint
        description:
          type: string
          nullable: true
          description: Optional description for the webhook
    EventType:
      type: object
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string
          description: Dot-notation name of the event (e.g., "order.filled")
        category:
          type: string
          description: Event category (e.g., "order", "kyc")
        description:
          type: string
          description: Human-readable description of the event
        displayName:
          type: string
          nullable: true
          description: Human-readable name for display
    CreateDepositRequest:
      type: object
      required:
        - amount
        - method
      properties:
        amount:
          type: string
          pattern: ^\d+(\.\d{1,2})?$
          description: The deposit amount as a decimal string with up to 2 decimal places.
          example: '1000.00'
        currency:
          type: string
          minLength: 3
          maxLength: 3
          default: USD
          description: The currency code (ISO 4217). Defaults to USD.
          example: USD
        method:
          type: string
          enum:
            - ach
            - manual_bank_transfer
            - wire
            - international_wire
            - mobile_money
            - card
          description: |
            The funding method for the deposit:
            - `ach`: ACH bank transfer
            - `manual_bank_transfer`: Manual wire/ACH to Buildmarkets' bank account
            - `wire`: Wire transfer
            - `international_wire`: International wire transfer
            - `mobile_money`: Mobile money collection (e.g. MTN MoMo, Airtel Money)
            - `card`: Debit/credit card payment
          example: manual_bank_transfer
        description:
          type: string
          maxLength: 500
          description: Optional description for the deposit.
          example: Initial funding for investment account
        metadata:
          type: object
          description: |
            Method-specific options passed to the funding provider. Fields vary by method:
            - `mobile_money`: `phone` (required, E.164) — the mobile money number to debit.
            - `card`: `redirect_url` (recommended) — URL to redirect after 3DS/payment page.
          properties:
            phone:
              type: string
              description: Mobile money phone number in E.164 format. Required for `mobile_money` deposits.
              example: '+233123456789'
            redirect_url:
              type: string
              format: uri
              description: Redirect URL after card payment. Recommended for `card` deposits.
              example: https://app.example.com/deposit/callback
        manual_options:
          $ref: '#/components/schemas/ManualDepositOptions'
        wire_options:
          $ref: '#/components/schemas/WireDepositOptions'
    DepositResponse:
      description: Envelope-wrapped deposit resource.
      allOf:
        - $ref: '#/components/schemas/ResourceEnvelope'
        - type: object
          properties:
            investor_id:
              type: string
              description: Prefixed public id of the owning investor.
              example: inv_01j9x8m2k7qpzwv3t5r6y8n0ab
            wallet_id:
              type: string
              description: Prefixed public id of the destination wallet.
              example: wlt_01j9x8m2k7qpzwv3t5r6y8n0cd
            funding_source_id:
              type: string
              nullable: true
              description: Prefixed public id of the funding source (when applicable).
            method:
              type: string
              enum:
                - ach
                - manual_bank_transfer
                - wire
                - international_wire
            status:
              type: string
              enum:
                - pending
                - processing
                - completed
                - cancelled
                - failed
              description: Buildmarkets-native transfer status.
            amount:
              type: string
            currency:
              type: string
            description:
              type: string
              nullable: true
            method_details:
              type: object
              nullable: true
              description: |
                Provider-specific transfer details. Shape varies by method:
                - **ach**: `{ provider_name, transfer_id, alpaca_status }`
                - **manual_bank_transfer**: `{ reference_code, bank_details: { bank_name, bank_address, account_name, account_number, routing_number, swift_code, instructions }, expires_at }`
                - **international_wire**: `{ provider_name, funding_details }`
              properties:
                provider_name:
                  type: string
                  description: Name of the funding provider (e.g. "alpaca").
                transfer_id:
                  type: string
                  description: External provider transfer ID. Present for ACH deposits.
                alpaca_status:
                  type: string
                  description: Alpaca-native transfer status (e.g. QUEUED, APPROVAL_PENDING, COMPLETE). Present for ACH deposits.
                reference_code:
                  type: string
                  description: Unique reference code for manual bank transfers.
                bank_details:
                  type: object
                  nullable: true
                  description: Bank account details for manual bank transfers.
                  properties:
                    bank_name:
                      type: string
                    bank_address:
                      type: string
                      nullable: true
                    account_name:
                      type: string
                    account_number:
                      type: string
                      description: Masked account number (e.g. ****1234).
                    routing_number:
                      type: string
                    swift_code:
                      type: string
                      nullable: true
                    instructions:
                      type: string
                expires_at:
                  type: string
                  description: ISO date-time after which a manual bank transfer deposit reference expires.
            initiated_at:
              type: string
              format: date-time
              nullable: true
            received_at:
              type: string
              format: date-time
              nullable: true
            completed_at:
              type: string
              format: date-time
              nullable: true
            expires_at:
              type: string
              format: date-time
              nullable: true
            failure_reason:
              type: string
              nullable: true
    DepositListResponse:
      description: List envelope of deposit resources.
      allOf:
        - $ref: '#/components/schemas/ListEnvelope'
        - type: object
          properties:
            data:
              type: array
              items:
                $ref: '#/components/schemas/DepositResponse'
    CreateWithdrawalRequest:
      type: object
      required:
        - amount
        - method
      properties:
        amount:
          type: string
          pattern: ^\d+(\.\d{1,2})?$
          description: The withdrawal amount as a decimal string with up to 2 decimal places.
          example: '500.00'
        currency:
          type: string
          minLength: 3
          maxLength: 3
          default: USD
          description: The currency code (ISO 4217). Defaults to USD.
          example: USD
        method:
          type: string
          enum:
            - ach
            - wire
            - international_wire
          description: |
            The funding method for the withdrawal:
            - `ach`: ACH bank transfer
            - `wire`: Wire transfer
            - `international_wire`: International wire transfer
          example: ach
        description:
          type: string
          maxLength: 500
          nullable: true
          description: Optional description for the withdrawal.
          example: Monthly withdrawal to checking account
        funding_source_id:
          type: string
          description: |
            Prefixed public id (`fs_…`) or UUID of the investor's active funding source.
            Required when `method` is `ach`, `wire`, or `international_wire`; wire payouts use the funding source's beneficiary profile.
        wire_options:
          $ref: '#/components/schemas/WireWithdrawalOptions'
    WithdrawalResponse:
      description: Envelope-wrapped withdrawal resource.
      allOf:
        - $ref: '#/components/schemas/ResourceEnvelope'
        - type: object
          properties:
            investor_id:
              type: string
              description: Prefixed public id of the owning investor.
            wallet_id:
              type: string
              description: Prefixed public id of the source wallet.
            funding_source_id:
              type: string
              nullable: true
            method:
              type: string
              enum:
                - ach
                - wire
                - international_wire
            status:
              type: string
              enum:
                - pending
                - processing
                - completed
                - cancelled
                - failed
              description: Buildmarkets-native transfer status.
            amount:
              type: string
            currency:
              type: string
            description:
              type: string
              nullable: true
            method_details:
              type: object
              nullable: true
              description: |
                Provider-specific transfer details. Shape varies by method:
                - **ach**: `{ provider_name, transfer_id, alpaca_status }`
                - **international_wire**: `{ provider_name, recipient_bank_action, alpaca_bank_id }`
              properties:
                provider_name:
                  type: string
                  description: Name of the funding provider (e.g. "alpaca").
                transfer_id:
                  type: string
                  description: External provider transfer ID.
                alpaca_status:
                  type: string
                  description: Alpaca-native transfer status (e.g. QUEUED, APPROVAL_PENDING, COMPLETE).
            destination_details:
              type: object
              nullable: true
            initiated_at:
              type: string
              format: date-time
              nullable: true
            completed_at:
              type: string
              format: date-time
              nullable: true
            failure_reason:
              type: string
              nullable: true
    WithdrawalListResponse:
      description: List envelope of withdrawal resources.
      allOf:
        - $ref: '#/components/schemas/ListEnvelope'
        - type: object
          properties:
            data:
              type: array
              items:
                $ref: '#/components/schemas/WithdrawalResponse'
    SubmitComplianceCheckRequest:
      type: object
      required:
        - workflow_id
        - check_type
        - provider_payload
      properties:
        workflow_id:
          type: string
          description: The compliance workflow ID returned in the `compliance_checks` array during account creation.
          example: a1b2c3d4-e5f6-7890-abcd-ef1234567890
        check_type:
          type: string
          enum:
            - identity_verification
            - tax_id_verification
            - screening
            - business_verification
          description: |
            The type of compliance check being submitted. Must match one of the checks returned during account creation.
          example: identity_verification
        provider_payload:
          type: object
          additionalProperties: true
          description: |
            Provider-specific callback/completion payload. Contents depend on the provider:
            - **Persona**: Include the inquiry/transaction completion data (e.g., `event_type`, `inquiry_id`, `status`).
            - **Dojah**: Include the widget completion data (e.g., `verification_status`, `reference_id`).
    ComplianceWorkflowResponse:
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: Unique identifier for the compliance workflow.
        status:
          type: string
          enum:
            - in_progress
            - pending_review
            - approved
            - rejected
            - suspended
            - expired
          description: |
            Current status of the workflow:
            - `in_progress`: One or more checks are still pending.
            - `pending_review`: All checks complete, but manual review is needed (HIGH risk).
            - `approved`: All checks passed and workflow is approved.
            - `rejected`: One or more checks failed or risk level is PROHIBITED.
        risk_level:
          type: string
          nullable: true
          enum:
            - low
            - medium
            - high
            - prohibited
          description: Assessed risk level after all checks complete.
        checks:
          type: array
          items:
            type: object
            properties:
              check_type:
                type: string
              status:
                type: string
              provider:
                type: string
              external_id:
                type: string
                nullable: true
              started_at:
                type: string
                format: date-time
                nullable: true
              completed_at:
                type: string
                format: date-time
                nullable: true
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
    ErrorResponse:
      type: object
      properties:
        code:
          type: string
          description: A custom error code for troubleshooting.
          example: BLUM-400-001
        message:
          type: string
          description: Human-readable error message.
          example: Invalid quantity. Must be a positive integer.
    MarketResponse:
      type: object
      properties:
        code:
          type: string
          description: ISO 10383 MIC code
          example: XNSA
        common_code:
          type: string
          nullable: true
          description: Human-friendly market code
          example: NGX
        name:
          type: string
          description: Full market name
          example: Nigerian Stock Exchange
        country:
          type: string
          description: ISO 2-letter country code
          example: NG
        currency:
          type: string
          description: Primary trading currency (ISO 4217)
          example: NGN
        timezone:
          type: string
          description: IANA timezone
          example: Africa/Lagos
        status:
          type: string
          enum:
            - active
            - inactive
            - holiday
          example: active
        trading_hours:
          type: object
          nullable: true
          properties:
            open:
              type: string
              example: '10:00'
            close:
              type: string
              example: '14:30'
        extended_hours_supported:
          type: boolean
          description: Whether the venue supports pre/post-market trading
        current_status:
          type: object
          nullable: true
          description: Current session status (best-effort; omitted on enrichment failure)
          properties:
            trading_session_status:
              type: string
              enum:
                - PRE_OPEN
                - OPEN
                - EXTENDED
                - HALTED
                - PRE_CLOSE
                - CLOSED
                - REQUEST_REJECTED
            is_open:
              type: boolean
            next_open:
              type: string
              format: date-time
              nullable: true
            next_close:
              type: string
              format: date-time
              nullable: true
      required:
        - code
        - name
        - country
        - currency
        - timezone
        - status
        - extendedHoursSupported
    MarketStatusResponse:
      type: object
      description: Full market state. Aligns with FIX TradSesStatus(340) plus an EXTENDED state for pre/post-market.
      properties:
        code:
          type: string
          example: XNAS
        common_code:
          type: string
          nullable: true
          example: NASDAQ
        name:
          type: string
        timezone:
          type: string
          example: America/New_York
        trading_session_status:
          type: string
          enum:
            - PRE_OPEN
            - OPEN
            - EXTENDED
            - HALTED
            - PRE_CLOSE
            - CLOSED
            - REQUEST_REJECTED
        is_open:
          type: boolean
          description: True only when trading_session_status is OPEN
        next_open:
          type: string
          format: date-time
          nullable: true
        next_close:
          type: string
          format: date-time
          nullable: true
        today:
          type: object
          properties:
            pre_open:
              type: string
              format: date-time
              nullable: true
            regular_open:
              type: string
              format: date-time
              nullable: true
            regular_close:
              type: string
              format: date-time
              nullable: true
            post_close:
              type: string
              format: date-time
              nullable: true
            is_holiday:
              type: boolean
            holiday_name:
              type: string
              nullable: true
            is_early_close:
              type: boolean
            early_close_at:
              type: string
              format: date-time
              nullable: true
        active_halts:
          type: array
          items:
            $ref: '#/components/schemas/MarketHaltResponse'
        extended_hours_supported:
          type: boolean
      required:
        - code
        - timezone
        - trading_session_status
        - is_open
        - today
        - active_halts
        - extended_hours_supported
    MarketCalendarResponse:
      type: object
      properties:
        code:
          type: string
          example: XNAS
        common_code:
          type: string
          nullable: true
          example: NASDAQ
        year:
          type: integer
          example: 2026
        trading_hours:
          type: object
          nullable: true
          properties:
            open:
              type: string
              example: '09:30'
            close:
              type: string
              example: '16:00'
        holidays:
          type: array
          items:
            type: object
            properties:
              date:
                type: string
                format: date
                example: '2026-07-03'
              name:
                type: string
                example: Independence Day
              type:
                type: string
                enum:
                  - FULL
                  - EARLY
                description: FULL = market closed all day, EARLY = early close
              early_close:
                type: string
                nullable: true
                description: Early close time (only for EARLY type)
                example: '13:00'
            required:
              - date
              - name
              - type
      required:
        - code
        - year
        - holidays
    QuoteResponse:
      type: object
      properties:
        symbol:
          type: string
          example: AAPL
        market:
          type: string
          description: MIC code of the market
          example: XNAS
        market_name:
          type: string
          description: Common market name
          example: NASDAQ
        price:
          type: number
          description: |
            Primary price. For equities, the last traded price. For bonds,
            the clean price quoted as percentage of par (e.g. `99.875`
            means 99.875% of face value).
          example: 185.5
        bid_price:
          type: number
          description: Current best bid price. For bonds, % of par.
        ask_price:
          type: number
          description: Current best ask price. For bonds, % of par.
        currency:
          type: string
          description: Price currency (ISO 4217)
          example: USD
        timestamp:
          type: string
          format: date-time
          description: When the price was recorded
        source:
          type: string
          description: Data provider
          enum:
            - ALPACA
            - NAYA
            - DATABASE
        confidence:
          type: string
          description: Price data freshness
          enum:
            - REAL_TIME
            - DELAYED
            - END_OF_DAY
            - STALE
            - UNAVAILABLE
        bond:
          $ref: '#/components/schemas/BondPriceDetails'
      required:
        - symbol
        - market
        - price
        - currency
        - timestamp
        - source
        - confidence
    BarsResponse:
      type: object
      properties:
        symbol:
          type: string
          example: AAPL
        market:
          type: string
          example: XNAS
        currency:
          type: string
          description: Price currency (ISO 4217)
          example: USD
        timeframe:
          type: string
          example: 1Day
        bars:
          type: array
          items:
            $ref: '#/components/schemas/BarData'
        data_quality:
          type: object
          nullable: true
          description: Present when the data provider has known limitations
          properties:
            provider:
              type: string
              example: NAYA
            limitations:
              type: array
              items:
                type: string
              example:
                - Only daily closing prices available; open, high, low values reflect the closing price
      required:
        - symbol
        - market
        - currency
        - timeframe
        - bars
    BarData:
      type: object
      properties:
        timestamp:
          type: string
          format: date-time
        open:
          type: number
        high:
          type: number
        low:
          type: number
        close:
          type: number
        volume:
          type: number
        vwap:
          type: number
          description: Volume-weighted average price
        trade_count:
          type: integer
          description: Number of trades in the bar
      required:
        - timestamp
        - open
        - high
        - low
        - close
        - volume
    SnapshotResponse:
      type: object
      properties:
        symbol:
          type: string
          example: AAPL
        market:
          type: string
          example: XNAS
        currency:
          type: string
          example: USD
        latest_trade:
          type: object
          nullable: true
          properties:
            price:
              type: number
            size:
              type: number
            timestamp:
              type: string
              format: date-time
            exchange:
              type: string
        latest_quote:
          type: object
          nullable: true
          properties:
            bid_price:
              type: number
            ask_price:
              type: number
            bid_size:
              type: number
            ask_size:
              type: number
            timestamp:
              type: string
              format: date-time
        daily_bar:
          type: object
          nullable: true
          properties:
            open:
              type: number
            high:
              type: number
            low:
              type: number
            close:
              type: number
            volume:
              type: number
            vwap:
              type: number
            date:
              type: string
              format: date
        prev_daily_bar:
          type: object
          nullable: true
          properties:
            close:
              type: number
            date:
              type: string
              format: date
        change:
          type: number
          description: Price change from previous close
        change_percent:
          type: number
          description: Percentage change from previous close
        source:
          type: string
          enum:
            - ALPACA
            - NAYA
            - DATABASE
        confidence:
          type: string
          enum:
            - REAL_TIME
            - DELAYED
            - END_OF_DAY
            - STALE
            - UNAVAILABLE
        timestamp:
          type: string
          format: date-time
      required:
        - symbol
        - market
        - currency
        - source
        - timestamp
    DemographicsProfile:
      type: object
      description: Demographic information for the investor
      properties:
        marital_status:
          type: string
          enum:
            - single
            - married
            - divorced
            - widowed
            - separated
            - domestic_partnership
        number_of_dependents:
          type: integer
          minimum: 0
        expected_retirement_age:
          type: integer
          minimum: 18
          maximum: 100
        life_expectancy:
          type: integer
          minimum: 18
          maximum: 120
        health_status:
          type: string
          enum:
            - excellent
            - good
            - fair
            - poor
        is_us_citizen:
          type: boolean
        is_us_resident:
          type: boolean
        state_of_residence:
          type: string
          description: US state code (e.g., CA, NY)
          example: CA
    EmploymentProfile:
      type: object
      description: Employment and income information
      properties:
        employment_status:
          type: string
          enum:
            - employed_full_time
            - employed_part_time
            - self_employed
            - unemployed
            - retired
            - student
        employer_name:
          type: string
        job_title:
          type: string
        industry:
          type: string
        years_in_current_job:
          type: integer
          minimum: 0
        annual_gross_income:
          type: string
          description: Annual gross income as decimal string
          example: '150000.00'
        annual_bonus:
          type: string
          description: Expected annual bonus
          example: '25000.00'
        income_growth_rate:
          type: number
          description: Expected annual income growth rate (decimal)
          example: 0.03
        has_stock_options:
          type: boolean
        stock_options_value:
          type: string
          description: Estimated value of stock options
        retirement_account_match:
          type: number
          description: Employer 401k match percentage
          example: 0.06
    RetirementBenefits:
      type: object
      description: Retirement benefits and social security information
      properties:
        has_pension:
          type: boolean
        pension_monthly_amount:
          type: string
          description: Expected monthly pension amount
        pension_start_age:
          type: integer
        social_security_estimate:
          type: string
          description: Estimated monthly Social Security benefit
        social_security_start_age:
          type: integer
          minimum: 62
          maximum: 70
        has_deferred_compensation:
          type: boolean
        deferred_comp_value:
          type: string
    TaxProfile:
      type: object
      description: Tax situation and preferences
      properties:
        filing_status:
          type: string
          enum:
            - single
            - married_filing_jointly
            - married_filing_separately
            - head_of_household
            - qualifying_widow
        federal_tax_bracket:
          type: number
          description: Marginal federal tax bracket (decimal)
          example: 0.32
        state_tax_rate:
          type: number
          description: State income tax rate (decimal)
          example: 0.093
        has_capital_loss_carryforward:
          type: boolean
        capital_loss_carryforward_amount:
          type: string
        tax_loss_harvesting_preference:
          type: boolean
        estimated_quarterly_taxes:
          type: string
    InsuranceProfile:
      type: object
      description: Insurance coverage information
      properties:
        has_life_insurance:
          type: boolean
        life_insurance_coverage:
          type: string
          description: Total life insurance coverage amount
        life_insurance_type:
          type: string
          enum:
            - term
            - whole
            - universal
            - variable
        has_disability_insurance:
          type: boolean
        disability_monthly_benefit:
          type: string
        has_long_term_care:
          type: boolean
        long_term_care_daily_benefit:
          type: string
        has_umbrella_policy:
          type: boolean
        umbrella_coverage_amount:
          type: string
    EstatePlanning:
      type: object
      description: Estate planning status
      properties:
        has_will:
          type: boolean
        has_trust:
          type: boolean
        trust_type:
          type: string
          enum:
            - revocable
            - irrevocable
            - none
        has_power_of_attorney:
          type: boolean
        has_healthcare_directive:
          type: boolean
        beneficiaries_updated:
          type: boolean
        last_estate_review_date:
          type: string
          format: date
        estimated_estate_value:
          type: string
    CashFlowPreferences:
      type: object
      description: Cash flow and spending preferences
      properties:
        monthly_expenses:
          type: string
          description: Average monthly expenses
          example: '8000.00'
        monthly_savings_target:
          type: string
        emergency_fund_months:
          type: integer
          description: Desired months of emergency fund coverage
        discretionary_spending:
          type: string
        major_purchases_planned:
          type: array
          items:
            type: object
            properties:
              description:
                type: string
              amount:
                type: string
              target_date:
                type: string
                format: date
    InvestmentPreferences:
      type: object
      description: User-stated investment constraints and preferences. These are inputs for the AI wealth engine when generating IPS and financial plans.
      properties:
        investment_style:
          type: string
          enum:
            - passive
            - active
            - hybrid
          description: Preferred investment approach
        esg_screening:
          type: boolean
          description: Whether to apply ESG screening to investments
        esg_criteria:
          type: array
          items:
            type: string
          description: Specific ESG criteria to apply (e.g., carbon_neutral, diversity)
        shariah_compliant:
          type: boolean
          description: Whether investments must be Shariah-compliant
        excluded_sectors:
          type: array
          items:
            type: string
          description: Industry sectors to exclude (e.g., tobacco, gambling, weapons)
          example:
            - tobacco
            - gambling
        excluded_securities:
          type: array
          items:
            type: string
          description: Specific ticker symbols to exclude
        excluded_countries:
          type: array
          items:
            type: string
          description: ISO country codes to exclude from investments
        preferred_geographies:
          type: array
          items:
            type: string
          description: Preferred geographic regions for investment
          example:
            - US
            - EU
            - Asia-Pacific
        no_individual_stocks:
          type: boolean
          description: Whether to avoid individual stock picks (prefer funds/ETFs)
        max_single_position_percent:
          type: string
          description: Maximum allocation to a single position (decimal, e.g., "0.10" for 10%)
          example: '0.10'
        max_sector_concentration_percent:
          type: string
          description: Maximum allocation to a single sector (decimal, e.g., "0.25" for 25%)
          example: '0.25'
        currency_preference:
          type: string
          description: Preferred currency for investments (ISO 4217)
          example: USD
        tax_efficiency_priority:
          type: string
          enum:
            - low
            - medium
            - high
          description: How much to prioritize tax-efficient investing
        prefer_tax_advantaged:
          type: boolean
          description: Whether to prefer tax-advantaged account types
        rebalancing_preference:
          type: string
          enum:
            - monthly
            - quarterly
            - semi_annual
            - annual
            - on_threshold
          description: Preferred portfolio rebalancing frequency
    PartnerProfile:
      type: object
      description: Partner/spouse information (if applicable)
      properties:
        first_name:
          type: string
        date_of_birth:
          type: string
          format: date
        employment_status:
          type: string
          enum:
            - employed_full_time
            - employed_part_time
            - self_employed
            - unemployed
            - retired
            - student
        annual_income:
          type: string
        expected_retirement_age:
          type: integer
        has_separate_accounts:
          type: boolean
        combined_filing:
          type: boolean
    InvestorProfile:
      description: Comprehensive investor profile aggregating all profile domains
      allOf:
        - $ref: '#/components/schemas/ResourceEnvelope'
        - type: object
          properties:
            account_id:
              type: string
              readOnly: true
            completeness_score:
              type: number
              minimum: 0
              maximum: 100
              description: Profile completeness percentage (0-100)
              example: 75
            last_assessed_at:
              type: string
              format: date-time
              nullable: true
              description: When the profile was last assessed for completeness
            demographics:
              $ref: '#/components/schemas/DemographicsProfile'
            employment:
              $ref: '#/components/schemas/EmploymentProfile'
            retirement_benefits:
              $ref: '#/components/schemas/RetirementBenefits'
            tax:
              $ref: '#/components/schemas/TaxProfile'
            insurance:
              $ref: '#/components/schemas/InsuranceProfile'
            estate_planning:
              $ref: '#/components/schemas/EstatePlanning'
            cash_flow:
              $ref: '#/components/schemas/CashFlowPreferences'
            investment_preferences:
              $ref: '#/components/schemas/InvestmentPreferences'
            partner:
              $ref: '#/components/schemas/PartnerProfile'
            created_at:
              type: string
              format: date-time
              readOnly: true
            updated_at:
              type: string
              format: date-time
              readOnly: true
    UpdateProfileRequest:
      type: object
      description: Request to update investor profile sections. Only provided sections are updated (merge semantics).
      properties:
        demographics:
          $ref: '#/components/schemas/DemographicsProfile'
        employment:
          $ref: '#/components/schemas/EmploymentProfile'
        retirement_benefits:
          $ref: '#/components/schemas/RetirementBenefits'
        tax:
          $ref: '#/components/schemas/TaxProfile'
        insurance:
          $ref: '#/components/schemas/InsuranceProfile'
        estate_planning:
          $ref: '#/components/schemas/EstatePlanning'
        cash_flow:
          $ref: '#/components/schemas/CashFlowPreferences'
        investment_preferences:
          $ref: '#/components/schemas/InvestmentPreferences'
        partner:
          $ref: '#/components/schemas/PartnerProfile'
    ProfileSnapshot:
      description: Immutable snapshot of investor profile at a point in time
      allOf:
        - $ref: '#/components/schemas/ResourceEnvelope'
        - type: object
          properties:
            profile_id:
              type: string
            version:
              type: integer
              description: Snapshot version number (increments for each new snapshot)
            trigger:
              type: string
              enum:
                - financial_plan
                - ips
                - manual
              description: What triggered this snapshot
            artifact_id:
              type: string
              nullable: true
              description: ID of the related Financial Plan or IPS document
            completeness_score:
              type: number
            created_at:
              type: string
              format: date-time
              readOnly: true
    ProfileSnapshotDetail:
      allOf:
        - $ref: '#/components/schemas/ProfileSnapshot'
        - type: object
          properties:
            data:
              type: object
              description: Full snapshot data including profile, dependents, risk assessment, and goals at time of snapshot
              properties:
                demographics_profile:
                  $ref: '#/components/schemas/DemographicsProfile'
                employment_profile:
                  $ref: '#/components/schemas/EmploymentProfile'
                retirement_benefits:
                  $ref: '#/components/schemas/RetirementBenefits'
                tax_profile:
                  $ref: '#/components/schemas/TaxProfile'
                insurance_profile:
                  $ref: '#/components/schemas/InsuranceProfile'
                estate_planning:
                  $ref: '#/components/schemas/EstatePlanning'
                cash_flow_preferences:
                  $ref: '#/components/schemas/CashFlowPreferences'
                investment_preferences:
                  $ref: '#/components/schemas/InvestmentPreferences'
                partner_profile:
                  $ref: '#/components/schemas/PartnerProfile'
                dependents:
                  type: array
                  items:
                    $ref: '#/components/schemas/Dependent'
                risk_assessment:
                  $ref: '#/components/schemas/RiskAssessment'
                goals_summary:
                  type: array
                  items:
                    type: object
                external_accounts_summary:
                  type: array
                  items:
                    type: object
                snapshot_version:
                  type: string
                profile_completeness_score:
                  type: number
    Dependent:
      description: A dependent (child, spouse, parent, etc.) linked to an investor for financial planning
      allOf:
        - $ref: '#/components/schemas/ResourceEnvelope'
        - type: object
          properties:
            account_id:
              type: string
              readOnly: true
            first_name:
              type: string
              example: Emma
            last_name:
              type: string
              nullable: true
              example: Smith
            relationship:
              type: string
              enum:
                - child
                - spouse
                - partner
                - parent
                - grandchild
                - sibling
                - other
              example: child
            date_of_birth:
              type: string
              format: date
              nullable: true
              example: '2015-03-15'
            financial_support_until:
              type: string
              format: date
              nullable: true
              description: Date until which financial support is expected
            has_education_plans:
              type: boolean
              description: Whether there are education funding plans for this dependent
              example: true
            estimated_education_cost:
              type: string
              nullable: true
              description: Estimated total education cost
              example: '150000.00'
            covered_by_health_insurance:
              type: boolean
            has_special_needs:
              type: boolean
            linked_goal_id:
              type: string
              nullable: true
              description: ID of a linked financial goal (e.g., education fund)
            linked_goal:
              type: object
              nullable: true
              description: Summary of the linked goal (read-only)
              readOnly: true
              properties:
                id:
                  type: string
                  format: uuid
                name:
                  type: string
                goal_type:
                  type: string
                target_amount:
                  type: string
            notes:
              type: string
              nullable: true
            metadata:
              type: object
              nullable: true
              additionalProperties: true
            status:
              type: string
              enum:
                - active
                - inactive
                - deceased
              example: active
            created_at:
              type: string
              format: date-time
              readOnly: true
            updated_at:
              type: string
              format: date-time
              readOnly: true
    CreateDependentRequest:
      type: object
      required:
        - first_name
        - relationship
      properties:
        first_name:
          type: string
          minLength: 1
          maxLength: 100
          example: Emma
        last_name:
          type: string
          maxLength: 100
        relationship:
          type: string
          enum:
            - child
            - spouse
            - partner
            - parent
            - grandchild
            - sibling
            - other
        date_of_birth:
          type: string
          format: date
        financial_support_until:
          type: string
          format: date
        has_education_plans:
          type: boolean
          default: false
        estimated_education_cost:
          type: string
          description: Decimal string amount
        covered_by_health_insurance:
          type: boolean
          default: true
        has_special_needs:
          type: boolean
          default: false
        linked_goal_id:
          type: string
          description: Optional ID of a financial goal to link
        notes:
          type: string
          maxLength: 1000
        metadata:
          type: object
          additionalProperties: true
    UpdateDependentRequest:
      type: object
      properties:
        first_name:
          type: string
          minLength: 1
          maxLength: 100
        last_name:
          type: string
          maxLength: 100
        relationship:
          type: string
          enum:
            - child
            - spouse
            - partner
            - parent
            - grandchild
            - sibling
            - other
        date_of_birth:
          type: string
          format: date
        financial_support_until:
          type: string
          format: date
        has_education_plans:
          type: boolean
        estimated_education_cost:
          type: string
        covered_by_health_insurance:
          type: boolean
        has_special_needs:
          type: boolean
        linked_goal_id:
          type: string
          nullable: true
        notes:
          type: string
          maxLength: 1000
        metadata:
          type: object
          additionalProperties: true
        status:
          type: string
          enum:
            - active
            - inactive
            - deceased
    DependentListResponse:
      description: List envelope of Dependent resources.
      allOf:
        - $ref: '#/components/schemas/ListEnvelope'
        - type: object
          properties:
            data:
              type: array
              items:
                $ref: '#/components/schemas/Dependent'
    RiskAssessment:
      description: A risk assessment capturing the investor's risk tolerance and investment experience
      allOf:
        - $ref: '#/components/schemas/ResourceEnvelope'
        - type: object
          properties:
            account_id:
              type: string
              readOnly: true
            questionnaire_id:
              type: string
              description: ID of the questionnaire template used
            questionnaire_version:
              type: integer
              description: Version of the questionnaire
            computed_risk_score:
              type: integer
              minimum: 1
              maximum: 10
              nullable: true
              description: Computed risk score (1-10, where 10 is highest risk tolerance)
            risk_tolerance:
              type: string
              enum:
                - conservative
                - moderately_conservative
                - moderate
                - moderately_aggressive
                - aggressive
              nullable: true
            volatility_tolerance:
              type: string
              enum:
                - low
                - medium
                - high
              nullable: true
            investment_experience:
              type: string
              enum:
                - none
                - limited
                - moderate
                - extensive
              nullable: true
            years_investing:
              type: integer
              nullable: true
            completed_at:
              type: string
              format: date-time
            expires_at:
              type: string
              format: date-time
              nullable: true
              description: When this assessment expires (typically 1 year)
            status:
              type: string
              enum:
                - active
                - expired
                - superseded
            created_at:
              type: string
              format: date-time
              readOnly: true
    RiskAssessmentDetail:
      allOf:
        - $ref: '#/components/schemas/RiskAssessment'
        - type: object
          properties:
            responses:
              type: array
              description: Individual questionnaire responses
              items:
                $ref: '#/components/schemas/RiskQuestionnaireResponse'
            past_market_behavior:
              $ref: '#/components/schemas/PastMarketBehavior'
    RiskQuestionnaireResponse:
      type: object
      properties:
        question_id:
          type: string
        question_text:
          type: string
        answer_id:
          type: string
        answer_text:
          type: string
        score:
          type: integer
          description: Score contribution from this answer
    PastMarketBehavior:
      type: object
      description: Historical market behavior and reactions
      properties:
        experienced_major_downturn:
          type: boolean
        action_during_downturn:
          type: string
          enum:
            - sold_all
            - sold_some
            - held
            - bought_more
        regret_level:
          type: string
          enum:
            - none
            - some
            - significant
    SubmitRiskAssessmentRequest:
      type: object
      required:
        - questionnaire_id
        - responses
      properties:
        questionnaire_id:
          type: string
          description: ID of the questionnaire template
        questionnaire_version:
          type: integer
          default: 1
        responses:
          type: array
          minItems: 1
          items:
            type: object
            required:
              - question_id
              - answer_id
            properties:
              question_id:
                type: string
              question_text:
                type: string
              answer_id:
                type: string
              answer_text:
                type: string
              score:
                type: integer
        past_market_behavior:
          $ref: '#/components/schemas/PastMarketBehavior'
        investment_experience:
          type: string
          enum:
            - none
            - limited
            - moderate
            - extensive
        years_investing:
          type: integer
          minimum: 0
    RiskAssessmentListResponse:
      description: List envelope of RiskAssessment resources.
      allOf:
        - $ref: '#/components/schemas/ListEnvelope'
        - type: object
          properties:
            data:
              type: array
              items:
                $ref: '#/components/schemas/RiskAssessment'
    RiskAssessmentSummary:
      type: object
      description: Quick summary of the investor's risk profile status
      properties:
        has_valid_assessment:
          type: boolean
          description: Whether there is a non-expired active assessment
        current_risk_score:
          type: integer
          nullable: true
        current_risk_tolerance:
          type: string
          nullable: true
        expires_at:
          type: string
          format: date-time
          nullable: true
        needs_reassessment:
          type: boolean
          description: True if no assessment or assessment is expired/expiring soon
    FinancialPlan:
      description: Holistic financial plan capturing goals, events, accounts, income, expenses, and investment outlook
      allOf:
        - $ref: '#/components/schemas/ResourceEnvelope'
        - type: object
          properties:
            account_id:
              type: string
              description: The investor account this plan belongs to
              readOnly: true
            version:
              type: integer
              description: Version number for plan snapshots
              readOnly: true
            goals:
              type: array
              items:
                $ref: '#/components/schemas/Goal'
              description: Array of financial goals
            life_events:
              type: array
              items:
                $ref: '#/components/schemas/LifeEvent'
              description: Planned major life events
            external_accounts:
              type: array
              items:
                $ref: '#/components/schemas/ExternalAccount'
              description: External accounts for net worth tracking (assets & liabilities)
            income:
              $ref: '#/components/schemas/IncomeProfile'
            expenses:
              $ref: '#/components/schemas/ExpenseProfile'
            investment_outlook:
              $ref: '#/components/schemas/InvestmentOutlook'
            status:
              type: string
              enum:
                - active
                - archived
              default: active
            created_at:
              type: string
              format: date-time
              readOnly: true
            updated_at:
              type: string
              format: date-time
              readOnly: true
    FinancialPlanRequest:
      type: object
      description: Request body for creating/updating a financial plan
      properties:
        goals:
          type: array
          items:
            $ref: '#/components/schemas/GoalInput'
        life_events:
          type: array
          items:
            $ref: '#/components/schemas/LifeEventInput'
        external_accounts:
          type: array
          items:
            $ref: '#/components/schemas/ExternalAccountInput'
        income:
          $ref: '#/components/schemas/IncomeProfile'
        expenses:
          $ref: '#/components/schemas/ExpenseProfile'
        investment_outlook:
          $ref: '#/components/schemas/InvestmentOutlook'
    FinancialPlanSummary:
      type: object
      description: |
        Computed summary of an investor's financial plan. Not a standalone
        resource — `financial_plan_id` is the FK to the parent plan.
      properties:
        financial_plan_id:
          type: string
          nullable: true
        currency:
          type: string
          description: ISO 4217 currency code for all monetary values in this summary
          example: USD
        total_net_worth:
          type: string
          description: Total net worth (assets - liabilities)
        total_assets:
          type: string
        total_liabilities:
          type: string
        total_goal_progress:
          type: string
          description: Overall progress across all goals (percentage)
        goals_on_track:
          type: integer
          description: Number of goals on track
        goals_at_risk:
          type: integer
          description: Number of goals at risk
        monthly_cash_flow:
          type: string
          description: Monthly income minus expenses
        savings_rate:
          type: string
          description: Percentage of income being saved/invested
        investment_portfolio_value:
          type: string
          description: Total value of investment portfolios
        generated_at:
          type: string
          format: date-time
    Goal:
      description: A financial goal for the investor
      allOf:
        - $ref: '#/components/schemas/ResourceEnvelope'
        - type: object
          properties:
            account_id:
              type: string
              description: The investor account this goal belongs to
              readOnly: true
            name:
              type: string
              description: Display name for the goal
              example: Retirement Fund
            goal_type:
              type: string
              enum:
                - retirement
                - education
                - emergency
                - wealth_growth
                - home_purchase
                - custom
            target_amount:
              type: string
              description: Target dollar amount
              example: '500000.00'
            target_date:
              type: string
              format: date
              description: Target completion date
              example: '2045-01-01'
            currency:
              type: string
              pattern: ^[A-Z]{3}$
              default: USD
            priority:
              type: integer
              minimum: 1
              maximum: 10
              description: Priority ranking (1 = highest)
            initial_amount:
              type: string
              description: Initial funded amount
            current_amount:
              type: string
              description: Current amount toward goal
              readOnly: true
            progress_percent:
              type: string
              description: Progress percentage toward target
              readOnly: true
            amount_remaining:
              type: string
              description: Amount still needed
              readOnly: true
            monthly_contribution:
              type: string
              description: Planned monthly contribution
            projected_completion_date:
              type: string
              format: date
              description: Projected date based on contributions and returns
              readOnly: true
            on_track:
              type: boolean
              description: Whether goal is on track to be met
              readOnly: true
            portfolio_id:
              type: string
              description: Optional linked portfolio for this goal
            status:
              type: string
              enum:
                - active
                - completed
                - archived
              default: active
            metadata:
              type: object
              additionalProperties: true
              description: Custom metadata
            created_at:
              type: string
              format: date-time
              readOnly: true
            updated_at:
              type: string
              format: date-time
              readOnly: true
    InvestmentPolicyStatement:
      description: Investment policy statement defining risk profile, objectives, and constraints
      allOf:
        - $ref: '#/components/schemas/ResourceEnvelope'
        - type: object
          properties:
            account_id:
              type: string
              readOnly: true
            version:
              type: integer
              description: Version number (versioned, immutable once published)
              readOnly: true
            risk_profile:
              $ref: '#/components/schemas/RiskProfile'
            time_horizon:
              $ref: '#/components/schemas/TimeHorizon'
            investment_objectives:
              $ref: '#/components/schemas/InvestmentObjectives'
            target_allocation:
              $ref: '#/components/schemas/TargetAllocation'
            constraints:
              $ref: '#/components/schemas/IpsConstraints'
            effective_date:
              type: string
              format: date
            status:
              type: string
              enum:
                - draft
                - active
                - superseded
              readOnly: true
            created_at:
              type: string
              format: date-time
              readOnly: true
            updated_at:
              type: string
              format: date-time
              readOnly: true
    InvestmentPolicyStatementRequest:
      type: object
      description: Request body for creating/updating IPS
      required:
        - risk_profile
        - time_horizon
        - investment_objectives
        - target_allocation
      properties:
        risk_profile:
          $ref: '#/components/schemas/RiskProfile'
        time_horizon:
          $ref: '#/components/schemas/TimeHorizon'
        investment_objectives:
          $ref: '#/components/schemas/InvestmentObjectives'
        target_allocation:
          $ref: '#/components/schemas/TargetAllocation'
        constraints:
          $ref: '#/components/schemas/IpsConstraints'
        effective_date:
          type: string
          format: date
    IpsValidationResult:
      type: object
      description: Result of validating portfolio against IPS
      properties:
        is_compliant:
          type: boolean
        validation_results:
          type: object
          properties:
            allocation_compliance:
              type: object
              properties:
                compliant:
                  type: boolean
                deviations:
                  type: array
                  items:
                    type: object
                    properties:
                      asset_class:
                        type: string
                      target_percent:
                        type: string
                      current_percent:
                        type: string
                      deviation:
                        type: string
                      within_bands:
                        type: boolean
            restriction_compliance:
              type: object
              properties:
                compliant:
                  type: boolean
                violations:
                  type: array
                  items:
                    type: object
                    properties:
                      type:
                        type: string
                      description:
                        type: string
                      symbol:
                        type: string
            liquidity_compliance:
              type: object
              properties:
                compliant:
                  type: boolean
                current_cash_percent:
                  type: string
                required_cash_percent:
                  type: string
        recommended_actions:
          type: array
          items:
            type: object
            properties:
              action_type:
                type: string
                enum:
                  - rebalance
                  - sell_restricted
                  - increase_cash
                  - tax_harvest
              description:
                type: string
              priority:
                type: string
                enum:
                  - high
                  - medium
                  - low
        validated_at:
          type: string
          format: date-time
    PortfolioSummary:
      type: object
      description: Comprehensive portfolio overview
      properties:
        portfolio_id:
          type: string
        account_id:
          type: string
        name:
          type: string
        currency:
          type: string
        valuation:
          type: object
          properties:
            total_value:
              type: string
            cash_value:
              type: string
            positions_value:
              type: string
            unrealized_gain_loss:
              type: string
            unrealized_gain_loss_percent:
              type: string
            as_of:
              type: string
              format: date-time
        allocation:
          type: object
          properties:
            by_asset_class:
              type: array
              items:
                type: object
                properties:
                  asset_class:
                    type: string
                  value:
                    type: string
                  percent:
                    type: string
            by_sector:
              type: array
              items:
                type: object
                properties:
                  sector:
                    type: string
                  value:
                    type: string
                  percent:
                    type: string
        rebalancing_status:
          type: object
          properties:
            needs_rebalancing:
              type: boolean
            last_rebalanced_at:
              type: string
              format: date-time
            next_scheduled:
              type: string
              format: date
            max_deviation_percent:
              type: string
        strategy_application:
          type: object
          properties:
            strategy_id:
              type: string
            strategy_version_id:
              type: string
            applied_at:
              type: string
              format: date-time
            status:
              type: string
        linked_goals:
          type: array
          items:
            type: object
            properties:
              id:
                type: string
                description: Prefixed public id of the linked goal (e.g. `gl_…`).
              name:
                type: string
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
    PortfolioHoldings:
      type: object
      description: Detailed breakdown of portfolio positions
      properties:
        portfolio_id:
          type: string
        currency:
          type: string
        as_of:
          type: string
          format: date-time
        cash:
          type: object
          properties:
            balance:
              type: string
            available:
              type: string
            reserved:
              type: string
        holdings:
          type: array
          items:
            $ref: '#/components/schemas/Holding'
        totals:
          type: object
          properties:
            total_value:
              type: string
            total_cost_basis:
              type: string
            total_unrealized_pl:
              type: string
            total_unrealized_pl_percent:
              type: string
    PortfolioPerformance:
      type: object
      description: Portfolio performance metrics
      properties:
        portfolio_id:
          type: string
        currency:
          type: string
          description: ISO 4217 currency code for all monetary values
          example: USD
        period:
          type: object
          properties:
            start_date:
              type: string
              format: date
            end_date:
              type: string
              format: date
            label:
              type: string
        returns:
          type: object
          properties:
            time_weighted_return:
              type: string
            money_weighted_return:
              type: string
            total_return:
              type: string
            annualized_return:
              type: string
        benchmark_comparison:
          type: object
          properties:
            benchmark_symbol:
              type: string
            benchmark_name:
              type: string
            benchmark_return:
              type: string
            alpha:
              type: string
            tracking_error:
              type: string
        risk_metrics:
          type: object
          properties:
            volatility:
              type: string
            sharpe_ratio:
              type: string
            max_drawdown:
              type: string
            max_drawdown_date:
              type: string
              format: date
            beta:
              type: string
        period_breakdown:
          type: object
          properties:
            starting_value:
              type: string
            ending_value:
              type: string
            net_contributions:
              type: string
            net_withdrawals:
              type: string
            investment_gains:
              type: string
            dividends_received:
              type: string
            fees_paid:
              type: string
        value_history:
          type: array
          items:
            type: object
            properties:
              date:
                type: string
                format: date
              value:
                type: string
    RebalancingAnalysis:
      type: object
      description: Portfolio rebalancing analysis and recommendations
      properties:
        portfolio_id:
          type: string
        currency:
          type: string
          description: ISO 4217 currency code for all monetary values
          example: USD
        analysis_timestamp:
          type: string
          format: date-time
        needs_rebalancing:
          type: boolean
        rebalancing_reason:
          type: string
          enum:
            - allocation_drift
            - scheduled
            - manual
            - ips_change
        current_allocation:
          type: object
          additionalProperties:
            type: object
            properties:
              target:
                type: string
              actual:
                type: string
              drift:
                type: string
        recommended_trades:
          type: array
          items:
            type: object
            properties:
              action:
                type: string
                enum:
                  - buy
                  - sell
              symbol:
                type: string
              asset_class:
                type: string
              quantity:
                type: string
              notional:
                type: string
              reason:
                type: string
        tax_impact:
          type: object
          properties:
            estimated_short_term_gains:
              type: string
            estimated_long_term_gains:
              type: string
            tax_loss_harvesting_available:
              type: boolean
            harvestable_losses:
              type: string
        last_rebalanced_at:
          type: string
          format: date-time
    RebalanceRequest:
      type: object
      description: Request to execute portfolio rebalancing
      properties:
        execution_type:
          type: string
          enum:
            - full
            - custom
          default: full
        tax_aware:
          type: boolean
          default: true
        exclude_positions:
          type: array
          items:
            type: string
          description: Prefixed position ids to exclude from rebalancing.
        custom_trades:
          type: array
          items:
            type: object
            properties:
              action:
                type: string
                enum:
                  - buy
                  - sell
              symbol:
                type: string
              quantity:
                type: string
              notional:
                type: string
          description: Custom trades (only if execution_type=custom)
    RebalanceResponse:
      type: object
      description: Response after initiating rebalance
      properties:
        rebalance_id:
          type: string
        portfolio_id:
          type: string
        status:
          type: string
          enum:
            - pending
            - in_progress
            - completed
            - failed
        execution_type:
          type: string
        trade_plan_id:
          type: string
          description: Links to existing TradePlan via Strategy Engine
        estimated_trades:
          type: integer
        estimated_completion:
          type: string
          format: date-time
        created_at:
          type: string
          format: date-time
    AutoInvestSchedule:
      description: Automated investment schedule
      allOf:
        - $ref: '#/components/schemas/ResourceEnvelope'
        - type: object
          properties:
            account_id:
              type: string
              readOnly: true
            portfolio_id:
              type: string
            name:
              type: string
              example: Monthly Investment
            amount:
              type: string
              description: Amount to invest per execution
            currency:
              type: string
              pattern: ^[A-Z]{3}$
            frequency:
              type: string
              enum:
                - weekly
                - biweekly
                - monthly
                - quarterly
            schedule:
              type: object
              properties:
                day_of_week:
                  type: integer
                  minimum: 0
                  maximum: 6
                  description: For weekly/biweekly (0=Sunday)
                day_of_month:
                  type: integer
                  minimum: 1
                  maximum: 28
                  description: For monthly/quarterly
                time:
                  type: string
                  pattern: ^\d{2}:\d{2}$
                  example: '09:30'
            allocation_rule:
              type: string
              enum:
                - ips_target
                - equal_weight
                - custom
            custom_allocation:
              type: object
              additionalProperties:
                type: string
              description: Symbol to percentage mapping (if rule=custom)
            funding_source_id:
              type: string
            start_date:
              type: string
              format: date
            end_date:
              type: string
              format: date
            next_execution:
              type: string
              format: date-time
              readOnly: true
    AutoInvestScheduleRequest:
      type: object
      description: Request to create/update auto-invest schedule
      required:
        - name
        - portfolio_id
        - amount
        - frequency
        - allocation_rule
        - funding_source_id
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 100
        portfolio_id:
          type: string
        funding_source_id:
          type: string
        amount:
          type: string
          pattern: ^\d+(\.\d{2})?$
        currency:
          type: string
          pattern: ^[A-Z]{3}$
          default: USD
        frequency:
          type: string
          enum:
            - weekly
            - biweekly
            - monthly
            - quarterly
        schedule:
          type: object
          properties:
            day_of_week:
              type: integer
              minimum: 0
              maximum: 6
            day_of_month:
              type: integer
              minimum: 1
              maximum: 28
            time:
              type: string
              pattern: ^\d{2}:\d{2}$
        allocation_rule:
          type: string
          enum:
            - ips_target
            - equal_weight
            - custom
        custom_allocation:
          type: object
          additionalProperties:
            type: string
        start_date:
          type: string
          format: date
        end_date:
          type: string
          format: date
        notifications:
          type: object
          properties:
            on_execution:
              type: boolean
            on_failure:
              type: boolean
    DripConfiguration:
      description: Dividend reinvestment configuration
      allOf:
        - $ref: '#/components/schemas/ResourceEnvelope'
        - type: object
          properties:
            portfolio_id:
              type: string
              readOnly: true
            enabled:
              type: boolean
              default: false
            reinvestment_rule:
              type: string
              enum:
                - same_security
                - portfolio_allocation
                - custom
              description: How to reinvest dividends
            custom_allocation:
              type: object
              additionalProperties:
                type: string
              description: Symbol to percentage mapping (if rule=custom)
            minimum_amount:
              type: string
              description: Minimum dividend amount to trigger reinvestment
              example: '10.00'
            cash_sweep_enabled:
              type: boolean
              default: false
              description: Auto-invest idle cash above threshold
            cash_sweep_threshold:
              type: string
              description: Cash balance that triggers auto-investment
              example: '100.00'
            status:
              type: string
              enum:
                - active
                - paused
              readOnly: true
            created_at:
              type: string
              format: date-time
              readOnly: true
            updated_at:
              type: string
              format: date-time
              readOnly: true
    InsightList:
      description: List envelope of Insight resources.
      allOf:
        - $ref: '#/components/schemas/ListEnvelope'
        - type: object
          properties:
            data:
              type: array
              items:
                $ref: '#/components/schemas/Insight'
    Insight:
      description: AI-generated personalized insight
      allOf:
        - $ref: '#/components/schemas/ResourceEnvelope'
        - type: object
          properties:
            category:
              type: string
              enum:
                - opportunity
                - risk
                - tax
                - rebalancing
            title:
              type: string
              example: Tax Optimization Opportunity
            summary:
              type: string
              example: You have $2,500 in unrealized losses that could offset gains
            priority:
              type: string
              enum:
                - high
                - medium
                - low
                - informational
            impact_estimate:
              type: string
              example: $625 tax savings
            action:
              type: object
              properties:
                type:
                  type: string
                  enum:
                    - tax_loss_harvest
                    - rebalance
                    - increase_contribution
                    - reduce_risk
                    - diversify
                description:
                  type: string
                cta_label:
                  type: string
                  example: View Details
            details:
              type: object
              additionalProperties: true
            expires_at:
              type: string
              format: date-time
            status:
              type: string
              enum:
                - active
                - dismissed
                - expired
    RecommendationList:
      description: List envelope of Recommendation resources.
      allOf:
        - $ref: '#/components/schemas/ListEnvelope'
        - type: object
          properties:
            data:
              type: array
              items:
                $ref: '#/components/schemas/Recommendation'
    TaxOptimization:
      type: object
      description: Tax optimization suggestions
      properties:
        account_id:
          type: string
        tax_year:
          type: integer
        generated_at:
          type: string
          format: date-time
        tax_summary:
          type: object
          properties:
            estimated_short_term_gains:
              type: string
            estimated_long_term_gains:
              type: string
            realized_losses_ytd:
              type: string
            harvestable_losses:
              type: string
        opportunities:
          type: array
          items:
            type: object
            properties:
              opportunity_id:
                type: string
              type:
                type: string
                enum:
                  - tax_loss_harvest
                  - long_term_holding
                  - asset_location
                  - charitable_giving
              title:
                type: string
              description:
                type: string
              estimated_tax_savings:
                type: string
              positions:
                type: array
                items:
                  type: object
                  properties:
                    position_id:
                      type: string
                    symbol:
                      type: string
                    unrealized_gain_loss:
                      type: string
                    holding_period:
                      type: string
                      enum:
                        - short_term
                        - long_term
                    days_until_long_term:
                      type: integer
                    wash_sale_risk:
                      type: boolean
                    replacement_options:
                      type: array
                      items:
                        type: string
    AssistantChatRequest:
      type: object
      required:
        - message
      properties:
        message:
          type: string
          minLength: 1
          maxLength: 2000
        context:
          type: object
          properties:
            portfolio_id:
              type: string
            include_positions:
              type: boolean
              default: false
            include_performance:
              type: boolean
              default: false
    AssistantChatResponse:
      type: object
      properties:
        response_id:
          type: string
        message:
          type: string
        suggestions:
          type: array
          items:
            type: object
            properties:
              type:
                type: string
                enum:
                  - action
                  - info
                  - link
              label:
                type: string
              action_url:
                type: string
        context_used:
          type: array
          items:
            type: string
        created_at:
          type: string
          format: date-time
    AccountStatement:
      type: object
      description: Account statement for a period
      properties:
        statement_id:
          type: string
        account_id:
          type: string
        period:
          type: object
          properties:
            start_date:
              type: string
              format: date
            end_date:
              type: string
              format: date
            label:
              type: string
              example: Q4 2024
        summary:
          type: object
          properties:
            beginning_value:
              type: string
            ending_value:
              type: string
            net_change:
              type: string
            net_change_percent:
              type: string
            contributions:
              type: string
            withdrawals:
              type: string
            investment_returns:
              type: string
            fees:
              type: string
        activity:
          type: object
          properties:
            deposits:
              type: array
              items:
                type: object
            withdrawals:
              type: array
              items:
                type: object
            trades:
              type: array
              items:
                type: object
            dividends:
              type: array
              items:
                type: object
            fees:
              type: array
              items:
                type: object
        holdings_end_of_period:
          type: array
          items:
            $ref: '#/components/schemas/Holding'
        generated_at:
          type: string
          format: date-time
    PnlReport:
      type: object
      description: Profit and loss breakdown
      properties:
        account_id:
          type: string
        period:
          type: object
          properties:
            start_date:
              type: string
              format: date
            end_date:
              type: string
              format: date
        summary:
          type: object
          properties:
            total_pnl:
              type: string
            realized_pnl:
              type: string
            unrealized_pnl:
              type: string
            dividend_income:
              type: string
            interest_income:
              type: string
            fees_paid:
              type: string
        realized_gains_losses:
          type: object
          properties:
            short_term_gains:
              type: string
            short_term_losses:
              type: string
            long_term_gains:
              type: string
            long_term_losses:
              type: string
            net_realized:
              type: string
        by_position:
          type: array
          items:
            type: object
            properties:
              symbol:
                type: string
              realized_pnl:
                type: string
              unrealized_pnl:
                type: string
              dividend_income:
                type: string
        by_asset_class:
          type: array
          items:
            type: object
            properties:
              asset_class:
                type: string
              pnl:
                type: string
              pnl_percent:
                type: string
    BenchmarkReport:
      type: object
      description: Portfolio benchmark comparison
      properties:
        account_id:
          type: string
        period:
          type: string
        portfolio_return:
          type: string
        comparisons:
          type: array
          items:
            type: object
            properties:
              benchmark:
                type: string
                description: Benchmark symbol
              name:
                type: string
              return:
                type: string
              alpha:
                type: string
              correlation:
                type: string
              beta:
                type: string
              tracking_error:
                type: string
        chart_data:
          type: object
          properties:
            dates:
              type: array
              items:
                type: string
                format: date
            portfolio:
              type: array
              items:
                type: number
            benchmarks:
              type: object
              additionalProperties:
                type: array
                items:
                  type: number
    ResourceEnvelope:
      type: object
      description: |
        Resource envelope. Domain fields are spread after the
        envelope keys (`id`, `object`, `created`, `livemode`, `metadata`).
        Some Buildmarkets-original resources may emit only `object` + `livemode`
        without `id` / `created` (e.g. one-off action results).
      required:
        - object
        - livemode
      additionalProperties: true
      properties:
        id:
          type: string
          description: Prefixed public id (e.g. `inv_…`, `ord_…`, `dep_…`).
          example: inv_01j9x8m2k7qpzwv3t5r6y8n0ab
        object:
          type: string
          description: The resource type discriminator.
          example: investor
        created:
          type: integer
          nullable: true
          description: Unix-seconds timestamp of resource creation.
          example: 1747776000
        livemode:
          type: boolean
          description: |
            Whether this resource was created against a live API key.
            Test-mode keys always return `false`.
          example: false
        metadata:
          type: object
          additionalProperties:
            type: string
          description: Partner-set key/value map for cross-referencing.
    ListEnvelope:
      type: object
      description: |
        List envelope. `data` holds the page of items;
        each item is itself wrapped in a ResourceEnvelope.
      required:
        - object
        - url
        - has_more
        - data
      additionalProperties: true
      properties:
        object:
          type: string
          enum:
            - list
        url:
          type: string
          description: The endpoint path that produced this list.
          example: /v1/investors/inv_…/deposits
        has_more:
          type: boolean
          description: Whether more results exist beyond `data`.
          example: false
        data:
          type: array
          items:
            $ref: '#/components/schemas/ResourceEnvelope'
    ComplianceCheckResponse:
      type: object
      properties:
        workflow_id:
          type: string
          description: The compliance workflow this check belongs to.
          example: a1b2c3d4-e5f6-7890-abcd-ef1234567890
        check_type:
          type: string
          enum:
            - identity_verification
            - tax_id_verification
            - screening
            - risk_assessment
            - business_verification
          description: The type of compliance check performed.
          example: identity_verification
        status:
          type: string
          enum:
            - pending
            - clear
            - failed
            - review_required
            - error
          description: |
            Current status of the check:
            - `pending` — Async verification in progress; use `verification_url` or `verification_token` for user completion.
            - `clear` — Verification passed.
            - `failed` — Verification failed.
            - `review_required` — Manual review needed (e.g., potential PEP/sanctions match).
            - `error` — Provider error during verification.
          example: pending
        provider:
          type: string
          nullable: true
          description: The verification provider handling this check (e.g., persona-identity, persona-taxid, dojah).
          example: persona-identity
        external_id:
          type: string
          nullable: true
          description: Provider-specific reference ID for the verification.
          example: inq_abc123def456
        verification_url:
          type: string
          nullable: true
          description: |
            User-facing verification URL for async checks, when available.
          example: https://withpersona.com/verify?inquiry-id=inq_abc123def456
        verification_token:
          type: string
          nullable: true
          description: |
            Provider token or SDK configuration for client-side verification, when available.
          example: null
    Investor:
      description: |
        The investor (account) resource. flat: regulatory fields are
        flat at the top level; only `address`, `signed_agreements[]`, and
        `trusted_contact` retain meaningful nesting. The Alpaca-style
        `contact` / `identity` / `disclosures` block grouping is intentionally
        absent.
      allOf:
        - $ref: '#/components/schemas/ResourceEnvelope'
        - type: object
          properties:
            status:
              type: string
              enum:
                - onboarding
                - under_review
                - awaiting_documents
                - active
                - suspended
                - closed
                - declined
                - setup_failed
              description: Buildmarkets-native account status.
              example: onboarding
            account_type:
              type: string
              enum:
                - individual
                - joint
                - corporate
              example: individual
            management_type:
              type: string
              enum:
                - self_directed
                - advised
              example: self_directed
            tax_advantaged:
              type: boolean
              example: false
            tax_designation:
              type: string
              nullable: true
            account_number:
              type: string
              nullable: true
            currency:
              type: string
              example: USD
            balance:
              type: string
              example: '0.00'
            buying_power:
              type: string
              description: Available buying power from the custodian brokerage account. Defaults to "0" when no custodian account exists yet.
              example: '10000.00'
            cash_withdrawable:
              type: string
              description: Amount of cash available for withdrawal from the custodian brokerage account. Defaults to "0" when no custodian account exists yet.
              example: '5000.00'
            last_equity:
              type: string
              example: '0.00'
            crypto_status:
              type: string
              nullable: true
            trading_type:
              type: string
              enum:
                - cash
                - margin
                - null
              nullable: true
            first_name:
              type: string
              example: Jane
            middle_name:
              type: string
              nullable: true
            last_name:
              type: string
              example: Doe
            date_of_birth:
              type: string
              format: date
              nullable: true
              example: '1990-01-01'
            email:
              type: string
              format: email
              example: jane@example.com
            phone:
              type: string
              nullable: true
              example: '+15555550123'
            address:
              type: object
              description: |
                Address record. `street` is an array of one or more street
                lines (multi-line addresses keep one entry per line).
              properties:
                street:
                  type: array
                  items:
                    type: string
                  example:
                    - 123 Market St
                unit:
                  type: string
                  nullable: true
                city:
                  type: string
                  nullable: true
                state:
                  type: string
                  nullable: true
                postal_code:
                  type: string
                  nullable: true
                country:
                  type: string
                  description: ISO 3166-1 alpha-2.
                  nullable: true
                  example: US
            tax_id_type:
              type: string
              enum:
                - SSN
                - ITIN
                - EIN
                - SIN
                - NINO
                - TFN
                - VAT
                - TIN
                - OTHER
              nullable: true
            country_of_tax_residence:
              type: string
              description: ISO 3166-1 alpha-2.
              nullable: true
            country_of_citizenship:
              type: string
              description: ISO 3166-1 alpha-2.
              nullable: true
            country_of_birth:
              type: string
              description: ISO 3166-1 alpha-2.
              nullable: true
            funding_source:
              type: array
              items:
                type: string
                enum:
                  - employment_income
                  - investments
                  - inheritance
                  - business_income
                  - savings
                  - family
                  - other
            is_control_person:
              type: boolean
            is_affiliated_exchange_or_finra:
              type: boolean
            is_affiliated_exchange_or_iiroc:
              type: boolean
              nullable: true
            is_politically_exposed:
              type: boolean
            immediate_family_exposed:
              type: boolean
            employment_status:
              type: string
              enum:
                - employed
                - unemployed
                - student
                - retired
              nullable: true
            employer_name:
              type: string
              nullable: true
            employer_address:
              type: string
              nullable: true
            employment_position:
              type: string
              nullable: true
            signed_agreements:
              type: array
              items:
                type: object
                required:
                  - type
                  - signed_at
                properties:
                  type:
                    type: string
                    description: |
                      Buildmarkets-native agreement key. Translation to Alpaca's
                      wire keys (customer_agreement / account_agreement /
                      margin_agreement) happens internally.
                    enum:
                      - investor_agreement
                      - margin_disclosure_acknowledged
                      - w8ben_certification
                    example: investor_agreement
                  signed_at:
                    type: string
                    format: date-time
                  ip_address:
                    type: string
                    nullable: true
            trusted_contact:
              type: object
              nullable: true
              properties:
                first_name:
                  type: string
                last_name:
                  type: string
                email:
                  type: string
                  format: email
                phone:
                  type: string
                  nullable: true
            portfolios:
              type: array
              items:
                type: object
                properties:
                  id:
                    type: string
                  name:
                    type: string
                  status:
                    type: string
                  currency:
                    type: string
                    nullable: true
                  createdAt:
                    type: string
                    format: date-time
                  updatedAt:
                    type: string
                    format: date-time
            compliance_checks:
              type: array
              nullable: true
              items:
                $ref: '#/components/schemas/ComplianceCheckResponse'
    ErrorEnvelope:
      type: object
      description: |
        Error envelope. The Buildmarkets-specific `BLUM-XXX-XXX`
        code is carried in `error.code`; `error.type` is the broad
        category clients branch on.
      required:
        - error
      properties:
        error:
          type: object
          required:
            - type
            - code
            - message
          properties:
            type:
              type: string
              enum:
                - invalid_request_error
                - authentication_error
                - permission_error
                - not_found_error
                - conflict_error
                - idempotency_error
                - rate_limit_error
                - api_error
              example: invalid_request_error
            code:
              type: string
              description: The Buildmarkets-specific error code.
              example: BLUM-400-001
            message:
              type: string
              description: Developer-facing message.
            param:
              type: string
              description: Field path of the invalid input.
              example: tax_id
            doc_url:
              type: string
              format: uri
              example: https://docs.bluum.finance/errors/BLUM-400-001
            request_log_url:
              type: string
              format: uri
              description: Deep link to the request log in the partner dashboard.
    TrustedContact:
      description: |
        FINRA-defined "designated trusted contact" record. Per FINRA SR Rule
        4512, partners must give end-users a way to add or update a trusted
        contact post-onboarding. All four fields are required together.
      type: object
      required:
        - first_name
        - last_name
        - email
        - phone
      properties:
        first_name:
          type: string
          example: Mary
        last_name:
          type: string
          example: Doe
        email:
          type: string
          format: email
          example: mary@example.com
        phone:
          type: string
          description: Phone number in E.164 format.
          example: '+15555550199'
    OrderEstimateRequest:
      type: object
      required:
        - symbol
        - side
        - type
      properties:
        symbol:
          type: string
          description: Ticker symbol of the asset to estimate.
          example: AAPL
        market:
          type: string
          description: Optional market disambiguation (same as place order).
        isin:
          type: string
          description: Optional ISIN.
        figi:
          type: string
          description: Optional FIGI.
        side:
          type: string
          enum:
            - buy
            - sell
        type:
          type: string
          enum:
            - market
            - limit
          description: |
            Only `market` and `limit` are supported. Stop, stop-limit, and trailing orders cannot be estimated via this endpoint.
        quantity:
          type: string
          description: |
            Share quantity (required for sell; for market buy, provide either `quantity` or `notional`).
          example: '10'
        notional:
          type: string
          description: Dollar amount for a market buy estimate when `quantity` is omitted; uses the asset reference price. Not supported for sells.
          example: '1000.00'
        limit_price:
          type: string
          description: Required when `type` is `limit` (with `quantity`).
    OrderEstimate:
      description: |
        Pre-trade cost estimate from the routed custodian. Values are indicative only;
        execution price and fees may differ.
      allOf:
        - $ref: '#/components/schemas/ResourceEnvelope'
        - type: object
          properties:
            object:
              type: string
              example: order_estimate
            investor_id:
              type: string
            symbol:
              type: string
            side:
              type: string
              enum:
                - buy
                - sell
            type:
              type: string
              enum:
                - market
                - limit
            currency:
              type: string
              example: USD
            total_estimated_value:
              type: string
              description: Formatted total estimated value (currency precision).
            estimated_price:
              type: string
              nullable: true
            estimated_quantity:
              type: string
              nullable: true
            commission:
              type: string
              nullable: true
            errors:
              type: array
              items:
                type: string
              nullable: true
    OrderBondExecutionDetails:
      type: object
      description: |
        Fixed-income execution detail. Populated only when the underlying
        asset is a bond. Prices are % of par; accrued and face_value are
        in `currency`.
      properties:
        clean_price:
          type: string
          description: Clean price at execution, % of par.
          example: '99.875'
        dirty_price:
          type: string
          description: Dirty price at execution (clean + accrued), % of par.
          example: '100.342'
        accrued_interest:
          type: string
          description: Accrued interest paid to seller per 100 face value.
          example: '0.467'
        face_value:
          type: string
          description: Face value of the trade (matches `quantity`).
          example: '10000'
        yield_at_execution:
          type: string
          description: Yield realized at execution, decimal.
          example: '0.0475'
    BondAttributes:
      type: object
      description: |
        Fixed-income attributes. Populated only when `class` is `bond` /
        `bill` / `note`. Equity / crypto / ETF assets omit this block.
      properties:
        cusip:
          type: string
          description: 9-character CUSIP (US bonds). For non-US bonds the canonical id lives in `isin`.
          example: 00037BAC6
        isin:
          type: string
          description: 12-character ISIN (international identifier).
          example: US00037BAC63
        bond_status:
          type: string
          enum:
            - outstanding
            - pre_issuance
            - matured
          description: Lifecycle state of the issue.
          example: outstanding
        bond_type:
          type: string
          enum:
            - treasury
            - corporate
            - municipal
            - agency
            - sovereign
          description: Bond category.
          example: corporate
        bond_subtype:
          type: string
          description: Treasury subtype (`bill` / `note` / `bond`) or corporate sub-classification.
          example: bond
        maturity_date:
          type: string
          format: date
          description: Date the bond matures and face value is redeemed.
          example: '2042-05-08'
        issue_date:
          type: string
          format: date
          example: '2012-05-08'
        dated_date:
          type: string
          format: date
        first_coupon_date:
          type: string
          format: date
        next_coupon_date:
          type: string
          format: date
        last_coupon_date:
          type: string
          format: date
        coupon_rate:
          type: string
          description: Annual coupon rate as a decimal (e.g. "0.04375" = 4.375%).
          example: '4.375'
        coupon_type:
          type: string
          description: '"fixed" | "zero" | "floating" | ...'
          example: fixed
        coupon_frequency:
          type: integer
          description: Payments per year (1=annual, 2=semi_annual, 4=quarterly, 12=monthly, 0=zero/at_maturity).
          example: 2
        accrual_basis:
          type: string
          description: Day-count convention (`ACT/ACT`, `ACT/360`, `30/360`, ...).
          example: 30/360
        accrued_interest:
          type: number
          description: Accrued interest per 100 face since the last coupon.
          example: 2.795139
        face_value:
          type: string
          description: Par value of one unit, in `currency`.
          example: '1000'
        min_increment:
          type: string
          description: Minimum face-value purchase increment. Orders must be multiples of this.
          example: '2000'
        settlement_period:
          type: integer
          description: T+N business days for settlement (1 for treasuries, 2 for corporates).
          example: 2
        close_price_date:
          type: string
          format: date
          description: Date of the last close price.
          example: '2026-05-29'
        yield_to_maturity:
          type: number
          description: Yield to maturity (annualized decimal).
          example: 5.485755
        yield_to_worst:
          type: number
          description: Yield to worst (annualized decimal).
          example: 5.485755
        callable:
          type: boolean
          example: false
        puttable:
          type: boolean
          example: false
        convertible:
          type: boolean
          example: false
        perpetual:
          type: boolean
          example: false
        next_call_date:
          type: string
          format: date
        next_call_price:
          type: number
        call_type:
          type: string
          example: make_whole
        issuer:
          type: string
          description: Issuing entity. Corporate bonds only — treasuries omit.
          example: ABB Finance (USA) Inc.
        ticker:
          type: string
          description: Bond ticker (Bloomberg-style). Corporate bonds only.
          example: ABBNVX
        sector:
          type: string
          example: Capital Goods
        seniority:
          type: string
          example: Senior
        country_domicile:
          type: string
          description: ISO country of the issuer.
          example: US
        rating:
          type: string
          description: Composite credit rating (currently S&P).
          example: AAA
        sp_rating:
          type: string
          description: S&P rating.
          example: AAA
        sp_outlook:
          type: string
          enum:
            - positive
            - negative
            - stable
            - developing
          example: stable
    DeletedFundingSource:
      description: |
        standard delete response returned by
        `DELETE /v1/investors/{investor_id}/funding-sources/{id}`.
      type: object
      required:
        - id
        - object
        - deleted
      properties:
        id:
          type: string
          example: fs_01j9x8m2k7qpzwv3t5r6y8n0ab
        object:
          type: string
          enum:
            - funding_source
        deleted:
          type: boolean
          enum:
            - true
    CreateLinkTokenRequest:
      type: object
      description: |
        Request body for creating a Link token. 
        Set enable_hosted_link to true to get a hosted_link_url for Plaid Hosted Link flow.
      properties:
        enable_hosted_link:
          type: boolean
          default: false
          description: |
            If true, returns a hosted_link_url that can be used to redirect users 
            to a Plaid-hosted page for bank account linking. 
            When false or omitted, only returns a link_token for SDK-based integration.
          example: true
    ConnectPlaidRequest:
      type: object
      description: Connect a bank account via Plaid by exchanging the public token from Plaid Link
      required:
        - type
        - public_token
      properties:
        type:
          type: string
          enum:
            - plaid
          description: Funding source type
          example: plaid
        public_token:
          type: string
          description: Public token from Plaid Link
          example: public-production-abc123def456
    ConnectManualRequest:
      type: object
      description: Add a bank account manually with bank details
      required:
        - type
        - bank_name
        - account_holder_name
        - account_number
      properties:
        type:
          type: string
          enum:
            - manual
          description: Funding source type
          example: manual
        bank_name:
          type: string
          description: Name of the bank
          example: First National Bank
        account_holder_name:
          type: string
          description: Name of the account holder
          example: Jane Doe
        bank_account_type:
          type: string
          enum:
            - CHECKING
            - SAVINGS
          description: Bank account type
          example: CHECKING
        account_number:
          type: string
          minLength: 4
          description: Bank account number
          example: '1234567890'
        routing_number:
          type: string
          description: 9-digit ABA routing number (US accounts)
          example: '021000021'
        swift_code:
          type: string
          description: SWIFT/BIC code (international accounts)
          example: FNBMUS33
        beneficiary_address:
          type: string
          description: Beneficiary address
          example: 123 Main St, New York, NY 10001
        currency:
          type: string
          description: 3-letter currency code
          example: USD
        country:
          type: string
          description: 2-letter country code
          example: US
        bank_code:
          type: string
          description: Bank code (for non-US accounts)
        address_line_1:
          type: string
          description: Beneficiary street line (wire payout)
        city:
          type: string
          description: Beneficiary city (wire payout)
        region:
          type: string
          description: State / province / region (wire payout)
        postal_code:
          type: string
          description: Postal or ZIP code (wire payout)
        iban:
          type: string
          description: IBAN for jurisdictions that use it (wire payout)
        wire_routing_kind:
          type: string
          maxLength: 32
          description: |
            When `bank_code` carries a non-US routing identifier, set this to the Alpaca routing-code type
            consumed only by the custodian layer (e.g. `sort_code`, `ifsc`). Omit for US ABA (`routing_number`).
        metadata:
          type: object
          additionalProperties:
            type: string
          description: Arbitrary metadata key-value pairs
    Bank:
      type: object
      description: |
        Display name and routing `code` for a bank.
      required:
        - name
        - code
      properties:
        name:
          type: string
          description: Bank display name
          example: Access Bank
        code:
          type: string
          description: Bank code for account routing
          example: '044'
    ComplianceInitiationResponse:
      type: object
      properties:
        workflowId:
          type: string
          format: uuid
          description: The newly created compliance workflow ID.
        status:
          type: string
          enum:
            - IN_PROGRESS
            - APPROVED
            - REJECTED
            - PENDING_REVIEW
          description: Current workflow status. Typically IN_PROGRESS after initiation.
        complianceChecks:
          type: array
          description: Per-check statuses with SDK handoff data for async providers.
          items:
            $ref: '#/components/schemas/ComplianceCheckResponse'
    Disclosure:
      type: object
      required:
        - object
        - id
        - version
        - source
        - kind
        - route
        - step
        - title
        - requires_acknowledgement
      properties:
        object:
          type: string
          enum:
            - disclosure
        id:
          type: string
          description: Stable identifier referenced when recording an acceptance.
          example: hyc_non_shariah_new_customer_ack
        version:
          type: string
          description: |
            Revision tag. Partners detect copy changes by comparing this
            against the version they last presented to the user.
          example: '2026-05-23'
        source:
          type: string
          enum:
            - alpaca
            - bluum
          description: Whether the disclosure originates from Alpaca or from Buildmarkets.
        kind:
          type: string
          enum:
            - verbatim_text
            - pdf_link
            - html
          description: |
            `verbatim_text` — `text` holds copy the partner must render
            word-for-word. `pdf_link` — `url` points to the canonical PDF.
            `html` — `url` points to an HTML page.
        route:
          type: string
          enum:
            - all
            - us
            - international
          description: Onboarding route this disclosure applies to.
        step:
          type: string
          enum:
            - step_6_affiliations
            - step_7_w8_certification
            - step_9_broker_agreements
            - step_12_post_account
            - step_hyc_enrollment
            - step_fixed_income_enrollment
            - platform_signup
          description: |
            The point in the partner UI where this disclosure must be
            surfaced. `step_hyc_enrollment` is the FDIC Sweep program
            enrollment screen. `step_fixed_income_enrollment` is the
            bond / treasury risk disclosure shown before a partner
            allows the user's first fixed-income order.
        title:
          type: string
          description: Human-readable title for partner UIs (not regulated copy).
        text:
          type: string
          nullable: true
          description: |
            Verbatim regulated text the partner must display unchanged.
            Present only when `kind=verbatim_text`. Translations are
            permitted only if they match word-for-word.
        url:
          type: string
          format: uri
          nullable: true
          description: Canonical URL for `pdf_link` / `html` disclosures, or the underlying PDF for `verbatim_text` disclosures that also have a printable form.
        requires_acknowledgement:
          type: boolean
          description: |
            `true` if the partner must capture an explicit click
            ("Accept", "Enroll", or "I Agree") and record it via
            `POST /v1/investors/{investor_id}/disclosures/acceptances`
            or via the `signed_agreements[]` array on account creation.
        agreement_key:
          type: string
          enum:
            - investor_agreement
            - margin_disclosure_acknowledged
            - w8ben_certification
          nullable: true
          description: |
            When this disclosure corresponds to an entry in the
            `signed_agreements[]` array on `POST /v1/investors`, this
            field holds the matching key. Use it to wire the disclosure
            into the create-investor payload so the acknowledgement is
            captured at account-create time.

            Null for Buildmarkets-side-only disclosures and for HYC / fixed
            income acknowledgements — those are persisted via the
            acceptances endpoint instead.
        source_reference:
          type: string
          description: Internal reference (Alpaca spreadsheet row or Buildmarkets doc) — useful for audit.
    DisclosureAcceptance:
      type: object
      required:
        - object
        - id
        - created
        - data
      properties:
        object:
          type: string
          enum:
            - disclosure_acceptance
        id:
          type: string
          description: Stable id for the acceptance record.
        created:
          type: integer
          format: int64
          description: Unix timestamp when the acceptance was recorded.
        livemode:
          type: boolean
        metadata:
          type: object
          additionalProperties:
            type: string
        data:
          type: object
          required:
            - investor_id
            - disclosure_id
            - version
            - signed_at
          properties:
            investor_id:
              type: string
              description: Prefixed investor id (`inv_…`).
            disclosure_id:
              type: string
              description: Disclosure registry id this acceptance is for.
            version:
              type: string
              description: Version of the disclosure the user acknowledged.
            signed_at:
              type: string
              format: date-time
            ip_address:
              type: string
              nullable: true
            user_agent:
              type: string
              nullable: true
            actor_ref:
              type: string
              nullable: true
    EnrollCashSweepRequest:
      type: object
      required:
        - variant
        - apr_tier_name
      properties:
        variant:
          type: string
          enum:
            - non_shariah
            - shariah
          description: Cash sweep variant
        apr_tier_name:
          type: string
          description: APR tier to assign
        disclosure_acceptance:
          type: object
          description: |
            Optional inline disclosure acceptance. If the required HYC
            disclosures have not been previously accepted, include this
            object to accept them as part of the enrollment call.
          properties:
            signed_at:
              type: string
              format: date-time
              description: ISO 8601 datetime when the user accepted
            ip_address:
              type: string
            user_agent:
              type: string
            actor_ref:
              type: string
    CashSweepEnrollmentResponse:
      type: object
      properties:
        id:
          type: string
          description: Prefixed enrollment ID (e.g. `cse_...`)
        object:
          type: string
          enum:
            - cash_sweep_enrollment
        created:
          type: integer
          description: Unix timestamp of creation
        livemode:
          type: boolean
        metadata:
          type: object
        investor_id:
          type: string
        brokerage_account_id:
          type: string
        variant:
          type: string
          enum:
            - non_shariah
            - shariah
        status:
          type: string
          enum:
            - pending_enrollment
            - active
            - pending_unenrollment
            - inactive
        apr_tier_name:
          type: string
          nullable: true
        apr_tier_id:
          type: string
          nullable: true
        account_rate_bps:
          type: integer
          nullable: true
        enrolled_at:
          type: string
          format: date-time
          nullable: true
        unenrolled_at:
          type: string
          format: date-time
          nullable: true
    ReassignTierRequest:
      type: object
      required:
        - apr_tier_name
      properties:
        apr_tier_name:
          type: string
          description: New APR tier name
    InterestHistoryEntry:
      type: object
      properties:
        date:
          type: string
          format: date
        account_id:
          type: string
        apr_tier_name:
          type: string
        apr_tier_id:
          type: string
        currency:
          type: string
        cash_balance:
          type: string
        account_rate_bps:
          type: number
        account_accrued_interest:
          type: string
        correspondent_rate_bps:
          type: number
        correspondent_fee:
          type: string
    InterestHistoryListResponse:
      type: object
      properties:
        object:
          type: string
          enum:
            - list
        url:
          type: string
        has_more:
          type: boolean
        data:
          type: array
          items:
            $ref: '#/components/schemas/InterestHistoryEntry'
    AprTier:
      type: object
      properties:
        id:
          type: string
        currency:
          type: string
        name:
          type: string
        is_default:
          type: boolean
        correspondent_rate_bps:
          type: number
        account_rate_bps:
          type: number
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
        details:
          type: object
          nullable: true
          properties:
            total_accounts:
              type: integer
            total_balance:
              type: string
            as_of:
              type: string
    AprTierListResponse:
      type: object
      properties:
        object:
          type: string
          enum:
            - list
        url:
          type: string
        has_more:
          type: boolean
        data:
          type: array
          items:
            $ref: '#/components/schemas/AprTier'
    ManualDepositOptions:
      type: object
      description: Options for manual bank transfers. Currently no options required.
      example: {}
    WireDepositOptions:
      type: object
      description: Options for wire transfers. (Future implementation)
      example: {}
    WireWithdrawalOptions:
      type: object
      description: Options for wire withdrawals. (Future implementation)
      example: {}
    MarketHaltResponse:
      type: object
      properties:
        id:
          type: string
        symbol:
          type: string
          nullable: true
          description: null indicates a market-wide halt (e.g., MWCB)
        halt_type:
          type: string
          enum:
            - MARKET_WIDE
            - LULD
            - NEWS
            - REGULATORY
            - VOLATILITY
            - TECHNICAL
            - OTHER
        halt_code:
          type: string
          nullable: true
          description: Vendor halt code (e.g., Nasdaq T1/T2/T5/T12/H10/M)
        reason:
          type: string
          nullable: true
        started_at:
          type: string
          format: date-time
        expected_resume_at:
          type: string
          format: date-time
          nullable: true
        source:
          type: string
          enum:
            - ALPACA
            - NGX
            - MANUAL
            - ADMIN
            - NASDAQ_TRADER
      required:
        - id
        - halt_type
        - started_at
        - source
    MarketSessionDay:
      type: object
      properties:
        date:
          type: string
          format: date
        is_open:
          type: boolean
          description: True if the venue trades on this date (regular session)
        is_holiday:
          type: boolean
        is_early_close:
          type: boolean
        holiday_name:
          type: string
          nullable: true
        regular_open:
          type: string
          nullable: true
          description: Local-time HH:mm when regular session opens
        regular_close:
          type: string
          nullable: true
        pre_open:
          type: string
          nullable: true
        post_close:
          type: string
          nullable: true
      required:
        - date
        - is_open
        - is_holiday
        - is_early_close
    BondPriceDetails:
      type: object
      description: |
        Fixed-income pricing extension. Populated only when the underlying
        asset is a bond. Prices are % of par; yields are decimals
        (e.g. `0.0475` = 4.75%).

        **What Alpaca exposes today**: clean price, yield to maturity, yield
        to worst. Accrued interest is applied at settlement but is not
        returned on quote requests; for hold-sizing purposes Buildmarkets
        estimates it internally. Bid/ask quotes, sizes, spreads, and
        benchmark identifiers are not part of Alpaca's fixed-income
        market-data response — those fields are omitted from this block.
      properties:
        clean_price:
          type: number
          description: Price excluding accrued interest, as % of par.
          example: 99.875
        yield_to_maturity:
          type: number
          description: Yield to maturity, annualized, decimal.
          example: 0.0475
        yield_to_worst:
          type: number
          description: Yield to worst (calls considered), decimal.
      required:
        - clean_price
        - yield_to_maturity
    GoalList:
      description: List envelope of Goal resources.
      allOf:
        - $ref: '#/components/schemas/ListEnvelope'
        - type: object
          properties:
            data:
              type: array
              items:
                $ref: '#/components/schemas/Goal'
    CreateGoalRequest:
      type: object
      description: Request body for creating a goal
      required:
        - name
        - goal_type
        - target_amount
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 100
        goal_type:
          type: string
          enum:
            - retirement
            - education
            - emergency
            - wealth_growth
            - home_purchase
            - custom
        target_amount:
          type: string
          pattern: ^\d+(\.\d{2})?$
        target_date:
          type: string
          format: date
        currency:
          type: string
          pattern: ^[A-Z]{3}$
          default: USD
        priority:
          type: integer
          minimum: 1
          maximum: 10
          default: 5
        initial_amount:
          type: string
          pattern: ^\d+(\.\d{2})?$
        monthly_contribution:
          type: string
          pattern: ^\d+(\.\d{2})?$
        portfolio_id:
          type: string
          description: Optional linked portfolio for this goal
        metadata:
          type: object
          additionalProperties: true
    UpdateGoalRequest:
      type: object
      description: Request body for updating a goal (all fields optional)
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 100
        goal_type:
          type: string
          enum:
            - retirement
            - education
            - emergency
            - wealth_growth
            - home_purchase
            - custom
        target_amount:
          type: string
          pattern: ^\d+(\.\d{2})?$
        target_date:
          type: string
          format: date
        currency:
          type: string
          pattern: ^[A-Z]{3}$
        priority:
          type: integer
          minimum: 1
          maximum: 10
        initial_amount:
          type: string
          pattern: ^\d+(\.\d{2})?$
        current_amount:
          type: string
          pattern: ^\d+(\.\d{2})?$
        monthly_contribution:
          type: string
          pattern: ^\d+(\.\d{2})?$
        portfolio_id:
          type: string
          nullable: true
          description: Set to null to unlink from portfolio
        status:
          type: string
          enum:
            - active
            - completed
            - archived
        metadata:
          type: object
          additionalProperties: true
    LifeEvent:
      description: A planned major life event
      allOf:
        - $ref: '#/components/schemas/ResourceEnvelope'
        - type: object
          properties:
            account_id:
              type: string
              description: The investor account this event belongs to
              readOnly: true
            name:
              type: string
              example: College for Sarah
            event_type:
              type: string
              enum:
                - college
                - wedding
                - home_purchase
                - retirement
                - major_purchase
                - career_change
                - custom
            expected_date:
              type: string
              format: date
            estimated_cost:
              type: string
              description: Estimated cost/impact
            currency:
              type: string
              pattern: ^[A-Z]{3}$
              default: USD
            recurring:
              type: boolean
              default: false
            linked_goal_id:
              type: string
              description: Optionally link to a goal
            notes:
              type: string
              maxLength: 500
            status:
              type: string
              enum:
                - active
                - completed
                - archived
              default: active
            created_at:
              type: string
              format: date-time
              readOnly: true
            updated_at:
              type: string
              format: date-time
              readOnly: true
    LifeEventList:
      description: List envelope of LifeEvent resources.
      allOf:
        - $ref: '#/components/schemas/ListEnvelope'
        - type: object
          properties:
            data:
              type: array
              items:
                $ref: '#/components/schemas/LifeEvent'
    CreateLifeEventRequest:
      type: object
      description: Request body for creating a life event
      required:
        - name
        - event_type
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 100
        event_type:
          type: string
          enum:
            - college
            - wedding
            - home_purchase
            - retirement
            - major_purchase
            - career_change
            - custom
        expected_date:
          type: string
          format: date
        estimated_cost:
          type: string
          pattern: ^\d+(\.\d{2})?$
        currency:
          type: string
          pattern: ^[A-Z]{3}$
          default: USD
        recurring:
          type: boolean
          default: false
        linked_goal_id:
          type: string
        notes:
          type: string
          maxLength: 500
    UpdateLifeEventRequest:
      type: object
      description: Request body for updating a life event (all fields optional)
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 100
        event_type:
          type: string
          enum:
            - college
            - wedding
            - home_purchase
            - retirement
            - major_purchase
            - career_change
            - custom
        expected_date:
          type: string
          format: date
        estimated_cost:
          type: string
          pattern: ^\d+(\.\d{2})?$
        currency:
          type: string
          pattern: ^[A-Z]{3}$
        recurring:
          type: boolean
        linked_goal_id:
          type: string
          nullable: true
          description: Set to null to unlink from goal
        notes:
          type: string
          maxLength: 500
        status:
          type: string
          enum:
            - active
            - completed
            - archived
    ExternalAccount:
      description: External account for net worth tracking (assets & liabilities outside the platform)
      allOf:
        - $ref: '#/components/schemas/ResourceEnvelope'
        - type: object
          properties:
            account_id:
              type: string
              description: The investor account this external account belongs to
              readOnly: true
            name:
              type: string
              example: Chase Checking
            account_type:
              type: string
              enum:
                - checking
                - savings
                - investment
                - brokerage
                - retirement_401k
                - retirement_ira_traditional
                - retirement_ira_roth
                - retirement_403b
                - retirement_457b
                - retirement_pension
                - retirement
                - hsa
                - fsa
                - plan_529
                - utma_ugma
                - trust
                - real_estate
                - vehicle
                - business_equity
                - collectibles
                - crypto
                - other_asset
                - mortgage
                - home_equity_loan
                - home_equity_loc
                - auto_loan
                - student_loan
                - personal_loan
                - loan
                - credit_card
                - medical_debt
                - tax_debt
                - other_liability
            is_asset:
              type: boolean
              description: True for assets, false for liabilities
            balance:
              type: string
              description: Current balance/value
            currency:
              type: string
              pattern: ^[A-Z]{3}$
              default: USD
            institution:
              type: string
              description: Financial institution name
            interest_rate:
              type: string
              description: Interest rate (APR/APY) as decimal string
              example: '0.065'
            interest_rate_type:
              type: string
              enum:
                - fixed
                - variable
                - adjustable
            minimum_payment:
              type: string
              description: Minimum monthly payment for liabilities
            payment_due_day:
              type: integer
              minimum: 1
              maximum: 31
              description: Day of month payment is due
            maturity_date:
              type: string
              format: date
              description: Loan maturity or CD maturity date
            original_loan_amount:
              type: string
              description: Original loan principal
            credit_limit:
              type: string
              description: Credit limit for revolving accounts
            property_value:
              type: string
              description: Current market value of associated property (e.g., for mortgage)
            appreciation_rate:
              type: string
              description: Expected annual appreciation rate for the asset
            contribution_limit:
              type: string
              description: Annual contribution limit for tax-advantaged accounts
            employer_match:
              type: string
              description: Employer match percentage for retirement accounts
            vesting_schedule:
              type: object
              description: Vesting schedule for employer contributions
              additionalProperties: true
            notes:
              type: string
            status:
              type: string
              enum:
                - active
                - archived
              default: active
            created_at:
              type: string
              format: date-time
              readOnly: true
            updated_at:
              type: string
              format: date-time
              readOnly: true
    ExternalAccountList:
      description: List envelope of ExternalAccount resources.
      allOf:
        - $ref: '#/components/schemas/ListEnvelope'
        - type: object
          properties:
            data:
              type: array
              items:
                $ref: '#/components/schemas/ExternalAccount'
    CreateExternalAccountRequest:
      type: object
      description: Request body for creating an external account
      required:
        - name
        - account_type
        - is_asset
        - balance
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 100
        account_type:
          type: string
          enum:
            - checking
            - savings
            - investment
            - brokerage
            - retirement_401k
            - retirement_ira_traditional
            - retirement_ira_roth
            - retirement_403b
            - retirement_457b
            - retirement_pension
            - retirement
            - hsa
            - fsa
            - plan_529
            - utma_ugma
            - trust
            - real_estate
            - vehicle
            - business_equity
            - collectibles
            - crypto
            - other_asset
            - mortgage
            - home_equity_loan
            - home_equity_loc
            - auto_loan
            - student_loan
            - personal_loan
            - loan
            - credit_card
            - medical_debt
            - tax_debt
            - other_liability
        is_asset:
          type: boolean
        balance:
          type: string
          pattern: ^\d+(\.\d{2})?$
        currency:
          type: string
          pattern: ^[A-Z]{3}$
          default: USD
        institution:
          type: string
          maxLength: 100
        interest_rate:
          type: string
          pattern: ^\d+(\.\d+)?$
        interest_rate_type:
          type: string
          enum:
            - fixed
            - variable
            - adjustable
        minimum_payment:
          type: string
          pattern: ^\d+(\.\d{2})?$
        payment_due_day:
          type: integer
          minimum: 1
          maximum: 31
        maturity_date:
          type: string
          format: date
        original_loan_amount:
          type: string
          pattern: ^\d+(\.\d{2})?$
        credit_limit:
          type: string
          pattern: ^\d+(\.\d{2})?$
        property_value:
          type: string
          pattern: ^\d+(\.\d{2})?$
        appreciation_rate:
          type: string
          pattern: ^\d+(\.\d+)?$
        contribution_limit:
          type: string
          pattern: ^\d+(\.\d{2})?$
        employer_match:
          type: string
          pattern: ^\d+(\.\d+)?$
        vesting_schedule:
          type: object
          additionalProperties: true
        notes:
          type: string
          maxLength: 500
    UpdateExternalAccountRequest:
      type: object
      description: Request body for updating an external account (all fields optional)
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 100
        account_type:
          type: string
          enum:
            - checking
            - savings
            - investment
            - brokerage
            - retirement_401k
            - retirement_ira_traditional
            - retirement_ira_roth
            - retirement_403b
            - retirement_457b
            - retirement_pension
            - retirement
            - hsa
            - fsa
            - plan_529
            - utma_ugma
            - trust
            - real_estate
            - vehicle
            - business_equity
            - collectibles
            - crypto
            - other_asset
            - mortgage
            - home_equity_loan
            - home_equity_loc
            - auto_loan
            - student_loan
            - personal_loan
            - loan
            - credit_card
            - medical_debt
            - tax_debt
            - other_liability
        is_asset:
          type: boolean
        balance:
          type: string
          pattern: ^\d+(\.\d{2})?$
        currency:
          type: string
          pattern: ^[A-Z]{3}$
        institution:
          type: string
          maxLength: 100
        interest_rate:
          type: string
          pattern: ^\d+(\.\d+)?$
        interest_rate_type:
          type: string
          enum:
            - fixed
            - variable
            - adjustable
        minimum_payment:
          type: string
          pattern: ^\d+(\.\d{2})?$
        payment_due_day:
          type: integer
          minimum: 1
          maximum: 31
        maturity_date:
          type: string
          format: date
        original_loan_amount:
          type: string
          pattern: ^\d+(\.\d{2})?$
        credit_limit:
          type: string
          pattern: ^\d+(\.\d{2})?$
        property_value:
          type: string
          pattern: ^\d+(\.\d{2})?$
        appreciation_rate:
          type: string
          pattern: ^\d+(\.\d+)?$
        contribution_limit:
          type: string
          pattern: ^\d+(\.\d{2})?$
        employer_match:
          type: string
          pattern: ^\d+(\.\d+)?$
        vesting_schedule:
          type: object
          additionalProperties: true
        notes:
          type: string
          maxLength: 500
        status:
          type: string
          enum:
            - active
            - archived
    IncomeProfile:
      type: object
      description: Income sources and amounts
      properties:
        total_monthly_income:
          type: string
          description: Total monthly income
        sources:
          type: array
          items:
            type: object
            properties:
              name:
                type: string
                example: Salary
              type:
                type: string
                enum:
                  - salary
                  - bonus
                  - rental
                  - dividends
                  - interest
                  - business
                  - pension
                  - social_security
                  - other
              amount:
                type: string
              currency:
                type: string
                description: ISO 4217 currency code
                example: USD
              frequency:
                type: string
                enum:
                  - weekly
                  - biweekly
                  - monthly
                  - quarterly
                  - annual
                  - one_time
              is_taxable:
                type: boolean
                default: true
    ExpenseProfile:
      type: object
      description: Expense categories and amounts
      properties:
        total_monthly_expenses:
          type: string
          description: Total monthly expenses
        categories:
          type: array
          items:
            type: object
            properties:
              name:
                type: string
                example: Housing
              type:
                type: string
                enum:
                  - housing
                  - transportation
                  - food
                  - utilities
                  - insurance
                  - healthcare
                  - debt_payment
                  - entertainment
                  - education
                  - savings
                  - other
              amount:
                type: string
              currency:
                type: string
                description: ISO 4217 currency code
                example: USD
              frequency:
                type: string
                enum:
                  - weekly
                  - biweekly
                  - monthly
                  - quarterly
                  - annual
              is_essential:
                type: boolean
                default: true
    InvestmentOutlook:
      type: object
      description: Investment expectations and risk capacity
      properties:
        expected_return_rate:
          type: string
          description: Expected annual return percentage
          example: '7.00'
        inflation_assumption:
          type: string
          description: Assumed inflation rate
          example: '2.50'
        risk_capacity:
          type: string
          enum:
            - low
            - moderate
            - high
          description: Ability to take risk based on financial situation
        tax_bracket:
          type: string
          description: Estimated tax bracket
          example: '24'
        state_of_residence:
          type: string
          description: For state tax considerations
          example: CA
    GoalInput:
      type: object
      description: Input for creating/updating a goal
      required:
        - name
        - goal_type
        - target_amount
      properties:
        id:
          type: string
          format: uuid
          description: Required for updates, omit for new goals
        name:
          type: string
          minLength: 1
          maxLength: 100
        goal_type:
          type: string
          enum:
            - retirement
            - education
            - emergency
            - wealth_growth
            - home_purchase
            - custom
        target_amount:
          type: string
          pattern: ^\d+(\.\d{2})?$
        target_date:
          type: string
          format: date
        currency:
          type: string
          pattern: ^[A-Z]{3}$
          default: USD
        priority:
          type: integer
          minimum: 1
          maximum: 10
        initial_amount:
          type: string
          pattern: ^\d+(\.\d{2})?$
        monthly_contribution:
          type: string
          pattern: ^\d+(\.\d{2})?$
        portfolio_id:
          type: string
        status:
          type: string
          enum:
            - active
            - completed
            - archived
        metadata:
          type: object
          additionalProperties: true
    LifeEventInput:
      type: object
      required:
        - name
        - event_type
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string
          minLength: 1
          maxLength: 100
        event_type:
          type: string
          enum:
            - college
            - wedding
            - home_purchase
            - retirement
            - major_purchase
            - career_change
            - custom
        expected_date:
          type: string
          format: date
        estimated_cost:
          type: string
          pattern: ^\d+(\.\d{2})?$
        currency:
          type: string
          pattern: ^[A-Z]{3}$
        recurring:
          type: boolean
        linked_goal_id:
          type: string
        notes:
          type: string
          maxLength: 500
    ExternalAccountInput:
      type: object
      required:
        - name
        - account_type
        - is_asset
        - balance
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 100
        account_type:
          type: string
          enum:
            - checking
            - savings
            - investment
            - brokerage
            - retirement_401k
            - retirement_ira_traditional
            - retirement_ira_roth
            - retirement_403b
            - retirement_457b
            - retirement_pension
            - retirement
            - hsa
            - fsa
            - plan_529
            - utma_ugma
            - trust
            - real_estate
            - vehicle
            - business_equity
            - collectibles
            - crypto
            - other_asset
            - mortgage
            - home_equity_loan
            - home_equity_loc
            - auto_loan
            - student_loan
            - personal_loan
            - loan
            - credit_card
            - medical_debt
            - tax_debt
            - other_liability
        is_asset:
          type: boolean
        balance:
          type: string
          pattern: ^\d+(\.\d{2})?$
        currency:
          type: string
          pattern: ^[A-Z]{3}$
          default: USD
        institution:
          type: string
          maxLength: 100
        interest_rate:
          type: string
          pattern: ^\d+(\.\d+)?$
        interest_rate_type:
          type: string
          enum:
            - fixed
            - variable
            - adjustable
        minimum_payment:
          type: string
          pattern: ^\d+(\.\d{2})?$
        payment_due_day:
          type: integer
          minimum: 1
          maximum: 31
        maturity_date:
          type: string
          format: date
        original_loan_amount:
          type: string
          pattern: ^\d+(\.\d{2})?$
        credit_limit:
          type: string
          pattern: ^\d+(\.\d{2})?$
        property_value:
          type: string
          pattern: ^\d+(\.\d{2})?$
        appreciation_rate:
          type: string
          pattern: ^\d+(\.\d+)?$
        contribution_limit:
          type: string
          pattern: ^\d+(\.\d{2})?$
        employer_match:
          type: string
          pattern: ^\d+(\.\d+)?$
        vesting_schedule:
          type: object
          additionalProperties: true
        notes:
          type: string
          maxLength: 500
    RiskProfile:
      type: object
      required:
        - risk_tolerance
      properties:
        risk_tolerance:
          type: string
          enum:
            - conservative
            - moderately_conservative
            - moderate
            - moderately_aggressive
            - aggressive
        risk_score:
          type: integer
          minimum: 1
          maximum: 10
          description: Numeric risk score (1 = very conservative, 10 = very aggressive)
        volatility_tolerance:
          type: string
          enum:
            - low
            - medium
            - high
          description: Tolerance for portfolio volatility
    TimeHorizon:
      type: object
      required:
        - years
      properties:
        years:
          type: integer
          minimum: 1
          maximum: 50
          description: Investment time horizon in years
        category:
          type: string
          enum:
            - short_term
            - medium_term
            - long_term
          description: Short (<3yr), medium (3-10yr), long (>10yr)
    InvestmentObjectives:
      type: object
      required:
        - primary
      properties:
        primary:
          type: string
          enum:
            - capital_preservation
            - capital_appreciation
            - income_generation
            - tax_efficiency
            - balanced
        secondary:
          type: array
          items:
            type: string
            enum:
              - capital_preservation
              - capital_appreciation
              - income_generation
              - tax_efficiency
              - balanced
        target_annual_return:
          type: string
          description: Target annual return percentage
          example: '7.00'
    AllocationBand:
      type: object
      required:
        - target_percent
      properties:
        target_percent:
          type: string
          description: Target allocation percentage
          example: '50.00'
        min_percent:
          type: string
          description: Minimum allocation percentage
          example: '40.00'
        max_percent:
          type: string
          description: Maximum allocation percentage
          example: '60.00'
        sub_allocations:
          type: object
          description: Sub-allocations within this asset class
          additionalProperties:
            type: string
          example:
            us_large_cap: '30.00'
            us_small_cap: '10.00'
            international: '10.00'
    TargetAllocation:
      type: object
      description: Target asset allocation with min/max bands
      additionalProperties:
        $ref: '#/components/schemas/AllocationBand'
      example:
        equities:
          target_percent: '50.00'
          min_percent: '40.00'
          max_percent: '60.00'
        fixed_income:
          target_percent: '25.00'
          min_percent: '20.00'
          max_percent: '30.00'
        treasury:
          target_percent: '20.00'
          min_percent: '15.00'
          max_percent: '25.00'
        alternatives:
          target_percent: '5.00'
          min_percent: '0.00'
          max_percent: '10.00'
    IpsConstraints:
      type: object
      description: Investment constraints and guidelines
      properties:
        liquidity_requirements:
          type: object
          properties:
            minimum_cash_percent:
              type: string
              description: Minimum cash allocation percentage
              example: '5.00'
            emergency_fund_months:
              type: integer
              description: Months of expenses to keep liquid
              example: 6
        tax_considerations:
          type: object
          properties:
            tax_loss_harvesting:
              type: boolean
              default: false
            tax_bracket:
              type: string
              example: '24'
            prefer_tax_advantaged:
              type: boolean
              default: true
        restrictions:
          type: object
          properties:
            excluded_sectors:
              type: array
              items:
                type: string
              example:
                - tobacco
                - gambling
            excluded_securities:
              type: array
              items:
                type: string
              description: Specific symbols to exclude
            no_individual_stocks:
              type: boolean
              default: false
            esg_screening:
              type: boolean
              default: false
            esg_criteria:
              type: array
              items:
                type: string
                enum:
                  - environmental
                  - social
                  - governance
            shariah_compliant:
              type: boolean
              default: false
              description: Whether investments must be Shariah-compliant
        rebalancing_policy:
          type: object
          properties:
            frequency:
              type: string
              enum:
                - monthly
                - quarterly
                - semi_annual
                - annual
                - threshold_only
              default: quarterly
            threshold_percent:
              type: string
              description: Drift threshold that triggers rebalancing
              example: '5.00'
            tax_aware:
              type: boolean
              default: true
    PortfolioListItem:
      description: Compact envelope-wrapped portfolio summary used in list responses.
      allOf:
        - $ref: '#/components/schemas/ResourceEnvelope'
        - type: object
          properties:
            name:
              type: string
            currency:
              type: string
            status:
              type: string
            updated_at:
              type: string
              format: date-time
    PortfolioListResponse:
      description: List envelope of PortfolioListItem resources.
      allOf:
        - $ref: '#/components/schemas/ListEnvelope'
        - type: object
          properties:
            data:
              type: array
              items:
                $ref: '#/components/schemas/PortfolioListItem'
    Holding:
      type: object
      properties:
        position_id:
          type: string
        asset_id:
          type: string
        symbol:
          type: string
        name:
          type: string
        currency:
          type: string
          description: ISO 4217 currency code for the asset's trading currency
          example: USD
        asset_class:
          type: string
        sector:
          type: string
        quantity:
          type: string
        average_cost_basis:
          type: string
        total_cost_basis:
          type: string
        current_price:
          type: string
        market_value:
          type: string
        unrealized_pl:
          type: string
        unrealized_pl_percent:
          type: string
        weight_percent:
          type: string
        price_source:
          type: string
          enum:
            - ALPACA
            - NAYA
            - DATABASE
            - MANUAL
        price_confidence:
          type: string
          enum:
            - REAL_TIME
            - DELAYED
            - END_OF_DAY
            - STALE
        price_timestamp:
          type: string
          format: date-time
    AutoInvestScheduleList:
      description: List envelope of AutoInvestSchedule resources.
      allOf:
        - $ref: '#/components/schemas/ListEnvelope'
        - type: object
          properties:
            data:
              type: array
              items:
                $ref: '#/components/schemas/AutoInvestSchedule'
    DripConfigurationRequest:
      type: object
      properties:
        enabled:
          type: boolean
        reinvestment_rule:
          type: string
          enum:
            - same_security
            - portfolio_allocation
            - custom
        custom_allocation:
          type: object
          additionalProperties:
            type: string
        minimum_amount:
          type: string
          pattern: ^\d+(\.\d{2})?$
        cash_sweep_enabled:
          type: boolean
        cash_sweep_threshold:
          type: string
          pattern: ^\d+(\.\d{2})?$
    Recommendation:
      description: AI-powered investment recommendation
      allOf:
        - $ref: '#/components/schemas/ResourceEnvelope'
        - type: object
          properties:
            type:
              type: string
              enum:
                - allocation
                - security
                - strategy
            title:
              type: string
            rationale:
              type: string
            confidence:
              type: string
              enum:
                - high
                - medium
                - low
            expected_impact:
              type: object
              properties:
                risk_adjusted_return_improvement:
                  type: string
                diversification_score_improvement:
                  type: string
            suggested_actions:
              type: array
              items:
                type: object
                properties:
                  action:
                    type: string
                    enum:
                      - buy
                      - sell
                      - hold
                      - increase
                      - decrease
                  symbol:
                    type: string
                  name:
                    type: string
                  target_allocation:
                    type: string
                  current_allocation:
                    type: string
  responses:
    UnauthorizedError:
      description: Authentication information is missing or invalid.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
          example:
            error:
              type: authentication_error
              code: BLUM-401-001
              message: Missing or invalid Authorization header.
    ForbiddenError:
      description: Access to the requested resource is forbidden.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
          example:
            error:
              type: permission_error
              code: BLUM-403-001
              message: Access denied to this resource.
    BadRequestError:
      description: The request was malformed or failed validation.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
          example:
            error:
              type: invalid_request_error
              code: BLUM-400-002
              message: Required field 'symbol' is missing.
              param: symbol
    NotFoundError:
      description: The requested resource could not be found.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
          example:
            error:
              type: not_found_error
              code: BLUM-404-001
              message: Investor not found.
    InternalServerError:
      description: An internal server error occurred.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
          example:
            error:
              type: api_error
              code: BLUM-500-001
              message: An internal server error occurred. Please try again later.
    ConflictError:
      description: The request conflicts with the current state of the resource.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
          example:
            error:
              type: conflict_error
              code: BLUM-409-002
              message: Investor has open positions. Liquidate all positions before closing.
  parameters:
    InvestorIdPath:
      name: investor_id
      in: path
      required: true
      schema:
        type: string
      description: Prefixed public id of the investor (e.g. `inv_…`).
    OrderIdPath:
      name: order_id
      in: path
      required: true
      schema:
        type: string
      description: Prefixed public id of the order (e.g. `ord_…`).
    parameters-InvestorIdPath:
      name: investor_id
      in: path
      required: true
      schema:
        type: string
      description: The prefixed public id of the investor (e.g. `inv_…`).
    components-parameters-InvestorIdPath:
      name: investor_id
      in: path
      required: true
      schema:
        type: string
      description: Prefixed public investor id (`inv_…`).
    cash-sweep_components-parameters-InvestorIdPath:
      name: investor_id
      in: path
      required: true
      description: Investor ID (prefixed, e.g. `inv_...`)
      schema:
        type: string
    transfers_components-parameters-InvestorIdPath:
      name: investor_id
      in: path
      required: true
      schema:
        type: string
      description: The prefixed public id of the investor (e.g. inv_…).
    IdempotencyKey:
      name: Idempotency-Key
      in: header
      required: false
      schema:
        type: string
      description: |
        A unique key to ensure idempotency of the request.
        If a request with the same idempotency key has already been processed,
        the original response will be returned.
    DepositIdPath:
      name: deposit_id
      in: path
      required: true
      schema:
        type: string
      description: The prefixed public id of the deposit (e.g. dep_…).
    WithdrawalIdPath:
      name: withdrawal_id
      in: path
      required: true
      schema:
        type: string
      description: The prefixed public id of the withdrawal (e.g. wd_…).
