openapi: 3.0.3
info:
  title: VOTR Trades API
  description: |
    API endpoint for bulk-enqueueing daily trade data records that combine
    trade-side and shareholder-side information into a single record per item.

    Records are queued for asynchronous processing. Duplicate suppression is
    performed downstream on the compound key `cusip | tradeDate | shareholderAccountNo`.

    ## Authentication
    This API uses OAuth 2.0 Bearer token authentication. Obtain your access token from the
    OAuth Token endpoint before making requests.

    ## Rate Limiting
    API requests are rate-limited per access token to ensure fair usage.

    ## Support
    For support and questions, please visit [VOTR Documentation](https://govotr.github.io/integration-doc/)
  version: 1.0.0
  contact:
    name: VOTR API Support
    url: https://govotr.github.io/integration-doc/
  license:
    name: Proprietary
servers:
  - url: https://shareholders-api-dev.govotr.com/api/v1
    description: Development server
  - url: https://shareholders-api.govotr.com/api/v1
    description: Production server

security:
  - BearerAuth: []

paths:
  /trade:
    post:
      summary: Bulk enqueue daily trade data
      description: |
        OAuth 2.0 protected endpoint to bulk-enqueue daily trade data records that combine
        trade-side and shareholder-side information into a single record per item.

        **Limits:** Maximum 50 records per request. Each record requires `cusip`, `issuer`,
        `tradeDate`, `shareholderAccountNo`, `brokerTxnId`, `ticker`, `tradeQty`, `tradeAction`,
        `securityType`, `securitySubType`, `shareholderName`, `deliveryPreference`,
        `settlementDate`, and `brokerId`.

        **Conditional rules:**
        - When `deliveryPreference = "E-Delivery"`, `shareholderEmail` is required.
        - When `deliveryPreference = "Full Set"`, `shareholderPhysicalAddress` is required and
          must include `addressLine1`, `city`, `state`, `zipCode`, and `country`.
        - `securitySubType` must be a valid sub-type for the chosen `securityType`
          (see the SECURITY_TYPE → SECURITY_SUBTYPE mapping in the platform documentation).

        **Date/time:** All date-time fields (`tradeDate`, `settlementDate`) must be valid
        ISO 8601 strings expressed in **UTC** (e.g. `2024-01-15T00:00:00Z`). Non-UTC offsets
        are rejected.

        Records are queued for asynchronous processing. Duplicate suppression is performed downstream
        on the compound key `cusip | tradeDate | shareholderAccountNo`.
      operationId: enqueueTradeData
      tags:
        - Daily Trade Data
      requestBody:
        required: true
        description: Array of merged trade + shareholder records to enqueue
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/EnqueueTradeDataInput"
            examples:
              eDeliveryMinimal:
                summary: Required fields only with E-Delivery (shareholder email)
                value:
                  tradeDataList:
                    - cusip: "037833100"
                      issuer: "Apple Inc."
                      tradeDate: "2024-01-15T00:00:00Z"
                      shareholderAccountNo: "ACC123456"
                      brokerTxnId: "TXN-2024-0001"
                      ticker: "AAPL"
                      tradeQty: 100
                      tradeAction: "BUY"
                      securityType: "Equities"
                      securitySubType: "Common Stock"
                      shareholderName: "John Doe"
                      shareholderEmail: "shareholder@yopmail.com"
                      deliveryPreference: "E-Delivery"
                      settlementDate: "2024-01-17T00:00:00Z"
                      brokerId: "507f1f77bcf86cd799439011"
              fullSetMinimal:
                summary: Required fields only with Full Set (physical address)
                value:
                  tradeDataList:
                    - cusip: "594918104"
                      issuer: "Microsoft Corp."
                      tradeDate: "2024-01-15T00:00:00Z"
                      shareholderAccountNo: "ACC654321"
                      brokerTxnId: "TXN-2024-0002"
                      ticker: "MSFT"
                      tradeQty: 50
                      tradeAction: "SELL"
                      securityType: "Equities"
                      securitySubType: "Common Stock"
                      shareholderName: "Jane Smith"
                      shareholderPhysicalAddress:
                        addressLine1: "500 Market St"
                        addressLine2: "Suite 200"
                        city: "San Francisco"
                        state: "CA"
                        zipCode: "94105"
                        country: "USA"
                      deliveryPreference: "Full Set"
                      settlementDate: "2024-01-17T00:00:00Z"
                      brokerId: "507f1f77bcf86cd799439011"
              complete:
                summary: Complete with all optional fields
                value:
                  tradeDataList:
                    - cusip: "037833100"
                      issuer: "Apple Inc."
                      tradeDate: "2024-01-15T00:00:00Z"
                      ibdNumber: 1234
                      brokerTxnId: "TXN-2024-0001"
                      ticker: "AAPL"
                      txnStatus: "NEW"
                      tradeQty: 100
                      isin: "US0378331005"
                      sedol: "2046251"
                      tradeAction: "BUY"
                      securityType: "Equities"
                      securitySubType: "Common Stock"
                      shareholderAccountNo: "ACC123456"
                      shareholderEmail: "shareholder@yopmail.com"
                      shareholderName: "John Doe"
                      shareholderPhysicalAddress: null
                      shareholderHouseholdingFlag: false
                      managerCode: "MGR001"
                      repCode: "REP001"
                      deliveryPreference: "E-Delivery"
                      fileId: "FILE123"
                      settlementDate: "2024-01-17T00:00:00Z"
                      brokerId: "507f1f77bcf86cd799439011"
      responses:
        "200":
          description: Trade data accepted and queued for processing
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EnqueueTradeDataResponse"
              example:
                message: "Daily trade data bulk inserted successfully"
                status: true
                data:
                  status: "success"
        "400":
          description: Bad Request - Validation error or invalid input data
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                tradeDataListOverLimit:
                  summary: tradeDataList over the allowed size
                  value:
                    status: false
                    error: "Validation failed"
                    message: "Maximum 50 trade data items allowed per request"
                tradeDataListEmpty:
                  summary: tradeDataList is empty
                  value:
                    status: false
                    error: "Validation failed"
                    message: "At least one trade data item is required"
                missingRequiredField:
                  summary: Missing required field
                  value:
                    status: false
                    error: "Validation failed"
                    message: "CUSIP is required"
                invalidTradeAction:
                  summary: Invalid tradeAction value
                  value:
                    status: false
                    error: "Validation failed"
                    message: "Trade action must be either BUY or SELL"
                invalidSecuritySubType:
                  summary: Sub-type not valid for the chosen security type
                  value:
                    status: false
                    error: "Validation failed"
                    message: "securitySubType is not valid for the given securityType"
                invalidSettlementDate:
                  summary: Invalid settlementDate format
                  value:
                    status: false
                    error: "Validation failed"
                    message: "Settlement date must be in ISO 8601 format"
                shareholderEmailRequired:
                  summary: shareholderEmail required for E-Delivery
                  value:
                    status: false
                    error: "Validation failed"
                    message: "shareholderEmail is required when deliveryPreference is E-Delivery"
                shareholderAddressRequired:
                  summary: shareholderPhysicalAddress required for Full Set
                  value:
                    status: false
                    error: "Validation failed"
                    message: "shareholderPhysicalAddress with addressLine1, city, state, zipCode, and country is required when deliveryPreference is Full Set"
                invalidEmail:
                  summary: Invalid shareholderEmail format
                  value:
                    status: false
                    error: "Validation failed"
                    message: "Please provide a valid email address"
        "401":
          description: Unauthorized - Invalid or missing OAuth token
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              example:
                status: false
                error: "Unauthorized"
                message: "Invalid or missing Bearer token"
        "429":
          description: Too Many Requests - Rate limit exceeded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              example:
                status: false
                error: "Rate limit exceeded"
                message: "Too many requests. Please try again later."
        "500":
          description: Internal Server Error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              example:
                status: false
                error: "Internal server error"
                message: "An unexpected error occurred. Please try again later."

components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: |
        OAuth 2.0 Bearer token authentication.
        Obtain your access token from the OAuth endpoint before making requests.

        Example: `Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...`

  schemas:
    EnqueueTradeDataInput:
      type: object
      required:
        - tradeDataList
      properties:
        tradeDataList:
          type: array
          minItems: 1
          maxItems: 50
          description: Array of merged trade + shareholder records (1-50 items per request)
          items:
            $ref: "#/components/schemas/EnqueueTradeDataItem"

    EnqueueTradeDataItem:
      type: object
      required:
        - cusip
        - issuer
        - tradeDate
        - shareholderAccountNo
        - brokerTxnId
        - ticker
        - tradeQty
        - tradeAction
        - securityType
        - securitySubType
        - shareholderName
        - deliveryPreference
        - settlementDate
        - brokerId
      description: |
        Merged trade + shareholder record. `securitySubType` must be a valid sub-type for
        the chosen `securityType`.

        **Conditional rules:**
        - When `deliveryPreference = "E-Delivery"`, `shareholderEmail` is required.
        - When `deliveryPreference = "Full Set"`, `shareholderPhysicalAddress` is required
          and must include `addressLine1`, `city`, `state`, `zipCode`, and `country`.
      properties:
        cusip:
          type: string
          description: CUSIP identifier for the security
          example: "037833100"
        issuer:
          type: string
          description: Name of the issuing company
          example: "Apple Inc."
        tradeDate:
          type: string
          format: date-time
          description: |
            Date when the trade occurred. Must be a valid ISO 8601 date-time string
            in **UTC** (e.g. `2024-01-15T00:00:00Z`). Non-UTC offsets are rejected.
          example: "2024-01-15T00:00:00Z"
        ibdNumber:
          type: integer
          minimum: 1000
          maximum: 9999
          nullable: true
          description: Introducing broker dealer number (4-digit integer)
          example: 1234
        brokerTxnId:
          type: string
          description: Broker-side transaction identifier
          example: "TXN-2024-0001"
        ticker:
          type: string
          description: Ticker symbol for the security
          example: "AAPL"
        txnStatus:
          type: string
          nullable: true
          description: Free-form transaction status as supplied by the broker
          example: "NEW"
        tradeQty:
          type: number
          minimum: 0
          description: Quantity of shares traded (must be ≥ 0)
          example: 100
        isin:
          type: string
          nullable: true
          description: ISIN identifier for the security
          example: "US0378331005"
        sedol:
          type: string
          nullable: true
          description: SEDOL identifier for the security
          example: "2046251"
        tradeAction:
          type: string
          enum:
            - BUY
            - SELL
          description: Trade action performed
          example: "BUY"
        securityType:
          type: string
          enum:
            - Open-End Fund
            - UIT
            - Municipal Fund
            - Closed-End Fund
            - Equities
            - Equity Linked
            - Units
            - Debt
            - Alternative Investment
            - CD
            - GSE Bond
            - Federal Agency Bond
            - Unregistered Security
            - REMIC
          description: Top-level security classification
          example: "Equities"
        securitySubType:
          type: string
          enum:
            - ETF
            - Mutual Fund
            - Money Market Fund
            - Variable Annuity
            - "529"
            - Listed CEF
            - Common Stock
            - IPO
            - Preferred Stock
            - Reg A
            - Warrants
            - Rights
            - SPAC
            - Corporate Bond
            - Note
            - Debenture
            - MTN
            - ETN
            - ADR
            - GO Bond
            - Revenue Bond
            - Commodity ETF
            - REIT
            - Equity Linked
            - Index Linked
            - Fixed
            - Non-Callable
            - Step Rate
            - FNMA
            - FHLMC
            - FFCB
            - FHLB
            - GNMA
            - TVA
            - Private Placement
            - GSE Issued
            - Privately Issued
          description: Security sub-type. Must be valid for the chosen `securityType`.
          example: "Common Stock"
        shareholderAccountNo:
          type: string
          description: Account number of the shareholder
          example: "ACC123456"
        shareholderEmail:
          type: string
          format: email
          nullable: true
          description: |
            Email address of the shareholder. Required when `deliveryPreference = "E-Delivery"`.
          example: "shareholder@yopmail.com"
        shareholderName:
          type: string
          description: Name of the shareholder
          example: "John Doe"
        shareholderPhysicalAddress:
          allOf:
            - $ref: "#/components/schemas/EnqueueTradeDataAddress"
          description: |
            Physical mailing address of the shareholder. Required when
            `deliveryPreference = "Full Set"`, in which case `addressLine1`, `city`, `state`,
            `zipCode`, and `country` must all be provided.
        shareholderHouseholdingFlag:
          type: boolean
          nullable: true
          description: Householding flag
          example: true
        managerCode:
          type: string
          nullable: true
          description: Manager code associated with the trade
          example: "MGR001"
        repCode:
          type: string
          nullable: true
          description: Representative code associated with the trade
          example: "REP001"
        deliveryPreference:
          type: string
          enum:
            - E-Delivery
            - Full Set
          description: Preferred delivery method for communications
          example: "E-Delivery"
        fileId:
          type: string
          nullable: true
          description: Associated file identifier
          example: "FILE123"
        type:
          type: string
          nullable: true
          description: Free-form record type label
        parentType:
          type: string
          nullable: true
          description: Parent record type, when applicable
        reasonForCancelation:
          type: string
          nullable: true
          description: Reason for cancellation, when applicable
        settlementDate:
          type: string
          format: date-time
          description: |
            Settlement date for the trade. Must be a valid ISO 8601 date-time string
            in **UTC** (e.g. `2024-01-17T00:00:00Z`). Non-UTC offsets are rejected.
          example: "2024-01-17T00:00:00Z"
        brokerId:
          type: string
          description: ObjectId of the associated clearing broker
          example: "507f1f77bcf86cd799439011"

    EnqueueTradeDataAddress:
      type: object
      nullable: true
      description: |
        Shareholder physical mailing address. All fields are nullable on their own;
        however, when `deliveryPreference = "Full Set"` on the parent record, the
        `addressLine1`, `city`, `state`, `zipCode`, and `country` fields must all be
        provided.
      properties:
        addressLine1:
          type: string
          maxLength: 100
          nullable: true
          description: Address line 1 (max 100 characters)
          example: "123 Main St"
        addressLine2:
          type: string
          maxLength: 100
          nullable: true
          description: Address line 2 (max 100 characters)
          example: "Apt 4B"
        city:
          type: string
          maxLength: 50
          nullable: true
          description: City (max 50 characters)
          example: "New York"
        state:
          type: string
          maxLength: 50
          nullable: true
          description: State or province (max 50 characters)
          example: "NY"
        zipCode:
          type: string
          maxLength: 10
          nullable: true
          description: ZIP or postal code (max 10 characters)
          example: "10001"
        country:
          type: string
          maxLength: 50
          nullable: true
          description: Country (max 50 characters)
          example: "USA"

    EnqueueTradeDataResponse:
      type: object
      properties:
        message:
          type: string
          description: Human-readable response message
          example: "Daily trade data bulk inserted successfully"
        status:
          type: boolean
          description: Indicates whether the request was accepted
          example: true
        data:
          type: object
          properties:
            status:
              type: string
              description: Internal status indicator
              example: "success"

    Error:
      type: object
      properties:
        status:
          type: boolean
          description: Always `false` for error responses
          example: false
        error:
          type: string
          description: Error type or category
          example: "Validation failed"
        message:
          type: string
          description: Detailed error message
          example: "Missing required field: cusip"

tags:
  - name: Daily Trade Data
    description: Operations for submitting daily trade data
