Forum · AsyncAPI Specification

Forum WebSocket Feed

Version 1.0

Real-time market data and private account updates via WebSocket. ## Connection Connect to `wss://api.forum.market/ws/v1` to establish a WebSocket connection. You must send a `subscribe` command within **10 seconds** of connecting or the connection will be closed. ## Connection Limits - **32 connections per IP address** - **10 inbound messages per second** per connection (exceeding this disconnects the client) ## Ping/Pong The server sends a WebSocket ping every **30 seconds**. You must respond with a pong within 10 seconds or the connection is terminated. ## Subscription Management Subscriptions are **additive** — sending a new subscribe command does not replace existing subscriptions. Use the `unsubscribe` command to remove subscriptions. ### Subscribe ```json { "id": 1, "cmd": "subscribe", "params": { "channels": ["bookUpdates", "tickerUpdates"], "tickers": ["OPENAI"] } } ``` ### Unsubscribe ```json { "id": 2, "cmd": "unsubscribe", "params": { "channels": ["tickerUpdates"], "tickers": ["OPENAI"] } } ``` ### List Subscriptions ```json { "id": 3, "cmd": "listSubscriptions" } ``` ## Authentication Private channels (`userOrders`, `userFills`, `userPositions`, `userAccount`) require authentication. ### In-Band HMAC Auth (recommended) ```json { "id": 1, "cmd": "auth", "params": { "key": "", "timestamp": "", "signature": "" } } ``` The signature signs the string: `timestamp + "GET" + "/ws/v1"`. ### URL-Based Auth ``` wss://api.forum.market/ws/v1?key=×tamp=&signature= ``` ### Auth Response Success: `{ "event": "authOk" }` Failure: `{ "type": "error", "error": { "code": "INVALID_SIGNATURE", "message": "..." } }`

View Spec View on GitHub CompanyTradingExchangePerpetual FuturesMarket DataAttention EconomyFintechWebSocketReal TimeAsyncAPIWebhooksEvents

Channels

subscribe
Subscribe to one or more channels for the specified tickers. Subscriptions are additive — they do not replace existing subscriptions.
unsubscribe
Unsubscribe from one or more channels for the specified tickers.
listSubscriptions
List all current subscriptions on this connection.
auth
Authenticate the connection for private channel access using HMAC-SHA256. The signature signs: `timestamp + "GET" + "/ws/v1"`.
logout
Log out the authenticated user and remove all private channel subscriptions.
errors
General error responses sent when a command fails validation or cannot be processed.
bookUpdates
Real-time order book updates. On subscribe, the server sends a full book snapshot, then incremental updates. **Sequence numbers:** Each message includes `data.seq` for gap detection. Verify that `seq` increments by 1. If a gap is detected, re-subscribe to get a fresh snapshot. **Quantity model:** The `qty` field is the **absolute size** at a price level. A `qty` of `0` means the level has been removed.
tickerUpdates
Level 1 market data updates including last price, best bid/ask, volume, funding rates, and index data.
trades
Real-time public trade feed. Each message represents a single executed trade.
indexUpdates
Live attention index value updates, including changes to underlying metrics.
fundingEvents
Funding events. Emitted daily when funding occurs.
candleUpdates1m
Live 1-minute candlestick updates. The `active` field indicates whether the candle is still open.
candleUpdates5m
Live 5-minute candlestick updates. The `active` field indicates whether the candle is still open.
candleUpdates1d
Live 1-day candlestick updates. The `active` field indicates whether the candle is still open.
heartbeat
Application-level heartbeat. Emitted every 1 second per subscribed ticker. Useful for low-volume markets to confirm the connection and server are alive.
userOrders
Real-time order lifecycle updates for the authenticated user. Streams all order state transitions (resting, partially filled, filled, cancelled). **Requires authentication.**
userFills
Real-time trade execution notifications for the authenticated user. **Requires authentication.**
userPositions
Real-time position updates for the authenticated user. Includes `prevQty` to track position size changes. **Requires authentication.**
userAccount
Real-time account margin and PnL updates for the authenticated user. **Requires authentication.**

Messages

SubscribeCommand
SubscribeCommand
Subscribe to channels
UnsubscribeCommand
UnsubscribeCommand
Unsubscribe from channels
ListSubscriptionsCommand
ListSubscriptionsCommand
List active subscriptions
AuthCommand
AuthCommand
Authenticate with HMAC signature
LogoutCommand
LogoutCommand
Log out and remove private subscriptions
SubscribeResponse
SubscribeResponse
Subscription confirmation
UnsubscribeResponse
UnsubscribeResponse
Unsubscription confirmation
ListSubscriptionsResponse
ListSubscriptionsResponse
Current subscription list
AuthOk
AuthOk
Authentication successful
AuthError
AuthError
Authentication failed
LoggedOut
LoggedOut
Successfully logged out
ErrorMessage
ErrorMessage
Error response
BookSnapshot
BookSnapshot
Full order book snapshot
BookUpdate
BookUpdate
Incremental order book update
TickerUpdate
TickerUpdate
Level 1 market data update
Trade
Trade
Public trade
IndexUpdate
IndexUpdate
Live attention index update
FundingEvent
FundingEvent
Funding event
CandleUpdate
CandleUpdate
Live candlestick update
Heartbeat
Heartbeat
Application-level heartbeat
OrderUpdate
OrderUpdate
Order state change
FillEvent
FillEvent
Trade execution
PositionUpdate
PositionUpdate
Position change
AccountUpdate
AccountUpdate
Account balance and margin update

Servers

wss
production
Production WebSocket server

AsyncAPI Specification

Raw ↑
asyncapi: 3.0.0
info:
  title: Forum WebSocket Feed
  version: '1.0'
  description: >
    Real-time market data and private account updates via WebSocket.


    ## Connection


    Connect to `wss://api.forum.market/ws/v1` to establish a WebSocket
    connection.


    You must send a `subscribe` command within **10 seconds** of connecting or
    the connection will be closed.


    ## Connection Limits


    - **32 connections per IP address**

    - **10 inbound messages per second** per connection (exceeding this
    disconnects the client)


    ## Ping/Pong


    The server sends a WebSocket ping every **30 seconds**. You must respond
    with a pong within 10 seconds or the connection is terminated.


    ## Subscription Management


    Subscriptions are **additive** — sending a new subscribe command does not
    replace existing subscriptions.

    Use the `unsubscribe` command to remove subscriptions.


    ### Subscribe


    ```json

    {
      "id": 1,
      "cmd": "subscribe",
      "params": {
        "channels": ["bookUpdates", "tickerUpdates"],
        "tickers": ["OPENAI"]
      }
    }

    ```


    ### Unsubscribe


    ```json

    {
      "id": 2,
      "cmd": "unsubscribe",
      "params": {
        "channels": ["tickerUpdates"],
        "tickers": ["OPENAI"]
      }
    }

    ```


    ### List Subscriptions


    ```json

    { "id": 3, "cmd": "listSubscriptions" }

    ```


    ## Authentication


    Private channels (`userOrders`, `userFills`, `userPositions`, `userAccount`)
    require authentication.


    ### In-Band HMAC Auth (recommended)


    ```json

    {
      "id": 1,
      "cmd": "auth",
      "params": {
        "key": "<api_key_id>",
        "timestamp": "<unix_seconds>",
        "signature": "<hmac_signature>"
      }
    }

    ```


    The signature signs the string: `timestamp + "GET" + "/ws/v1"`.


    ### URL-Based Auth


    ```

    wss://api.forum.market/ws/v1?key=<api_key_id>&timestamp=<ts>&signature=<sig>

    ```


    ### Auth Response


    Success: `{ "event": "authOk" }`

    Failure: `{ "type": "error", "error": { "code": "INVALID_SIGNATURE",
    "message": "..." } }`
servers:
  production:
    host: api.forum.market/ws/v1
    protocol: wss
    description: Production WebSocket server
channels:
  subscribe:
    address: /
    description: |
      Subscribe to one or more channels for the specified tickers.
      Subscriptions are additive — they do not replace existing subscriptions.
    messages:
      subscribeCommand:
        $ref: '#/components/messages/SubscribeCommand'
      subscribeResponse:
        $ref: '#/components/messages/SubscribeResponse'
  unsubscribe:
    address: /
    description: |
      Unsubscribe from one or more channels for the specified tickers.
    messages:
      unsubscribeCommand:
        $ref: '#/components/messages/UnsubscribeCommand'
      unsubscribeResponse:
        $ref: '#/components/messages/UnsubscribeResponse'
  listSubscriptions:
    address: /
    description: |
      List all current subscriptions on this connection.
    messages:
      listSubscriptionsCommand:
        $ref: '#/components/messages/ListSubscriptionsCommand'
      listSubscriptionsResponse:
        $ref: '#/components/messages/ListSubscriptionsResponse'
  auth:
    address: /
    description: |
      Authenticate the connection for private channel access using HMAC-SHA256.
      The signature signs: `timestamp + "GET" + "/ws/v1"`.
    messages:
      authCommand:
        $ref: '#/components/messages/AuthCommand'
      authOk:
        $ref: '#/components/messages/AuthOk'
      authError:
        $ref: '#/components/messages/AuthError'
  logout:
    address: /
    description: >
      Log out the authenticated user and remove all private channel
      subscriptions.
    messages:
      logoutCommand:
        $ref: '#/components/messages/LogoutCommand'
      loggedOut:
        $ref: '#/components/messages/LoggedOut'
  errors:
    address: /
    description: >
      General error responses sent when a command fails validation or cannot be
      processed.
    messages:
      errorMessage:
        $ref: '#/components/messages/ErrorMessage'
  bookUpdates:
    address: bookUpdates
    description: >
      Real-time order book updates. On subscribe, the server sends a full book
      snapshot, then incremental updates.


      **Sequence numbers:** Each message includes `data.seq` for gap detection.
      Verify that `seq` increments by 1. If a gap is detected, re-subscribe to
      get a fresh snapshot.


      **Quantity model:** The `qty` field is the **absolute size** at a price
      level. A `qty` of `0` means the level has been removed.
    messages:
      bookSnapshot:
        $ref: '#/components/messages/BookSnapshot'
      bookUpdate:
        $ref: '#/components/messages/BookUpdate'
  tickerUpdates:
    address: tickerUpdates
    description: >
      Level 1 market data updates including last price, best bid/ask, volume,
      funding rates, and index data.
    messages:
      tickerUpdate:
        $ref: '#/components/messages/TickerUpdate'
  trades:
    address: trades
    description: >
      Real-time public trade feed. Each message represents a single executed
      trade.
    messages:
      trade:
        $ref: '#/components/messages/Trade'
  indexUpdates:
    address: indexUpdates
    description: >
      Live attention index value updates, including changes to underlying
      metrics.
    messages:
      indexUpdate:
        $ref: '#/components/messages/IndexUpdate'
  fundingEvents:
    address: fundingEvents
    description: |
      Funding events. Emitted daily when funding occurs.
    messages:
      fundingEvent:
        $ref: '#/components/messages/FundingEvent'
  candleUpdates1m:
    address: candleUpdates1m
    title: Candle updates 1m
    description: >
      Live 1-minute candlestick updates. The `active` field indicates whether
      the candle is still open.
    messages:
      candleUpdate:
        $ref: '#/components/messages/CandleUpdate'
  candleUpdates5m:
    address: candleUpdates5m
    title: Candle updates 5m
    description: >
      Live 5-minute candlestick updates. The `active` field indicates whether
      the candle is still open.
    messages:
      candleUpdate:
        $ref: '#/components/messages/CandleUpdate'
  candleUpdates1d:
    address: candleUpdates1d
    title: Candle updates 1d
    description: >
      Live 1-day candlestick updates. The `active` field indicates whether the
      candle is still open.
    messages:
      candleUpdate:
        $ref: '#/components/messages/CandleUpdate'
  heartbeat:
    address: heartbeat
    description: >
      Application-level heartbeat. Emitted every 1 second per subscribed ticker.

      Useful for low-volume markets to confirm the connection and server are
      alive.
    messages:
      heartbeat:
        $ref: '#/components/messages/Heartbeat'
  userOrders:
    address: userOrders
    description: >
      Real-time order lifecycle updates for the authenticated user.

      Streams all order state transitions (resting, partially filled, filled,
      cancelled).


      **Requires authentication.**
    messages:
      orderUpdate:
        $ref: '#/components/messages/OrderUpdate'
  userFills:
    address: userFills
    description: |
      Real-time trade execution notifications for the authenticated user.

      **Requires authentication.**
    messages:
      fill:
        $ref: '#/components/messages/FillEvent'
  userPositions:
    address: userPositions
    description: |
      Real-time position updates for the authenticated user.
      Includes `prevQty` to track position size changes.

      **Requires authentication.**
    messages:
      positionUpdate:
        $ref: '#/components/messages/PositionUpdate'
  userAccount:
    address: userAccount
    description: |
      Real-time account margin and PnL updates for the authenticated user.

      **Requires authentication.**
    messages:
      accountUpdate:
        $ref: '#/components/messages/AccountUpdate'
operations:
  sendSubscribe:
    action: receive
    channel:
      $ref: '#/channels/subscribe'
    summary: Subscribe to channels
    messages:
      - $ref: '#/channels/subscribe/messages/subscribeCommand'
  sendUnsubscribe:
    action: receive
    channel:
      $ref: '#/channels/unsubscribe'
    summary: Unsubscribe from channels
    messages:
      - $ref: '#/channels/unsubscribe/messages/unsubscribeCommand'
  sendListSubscriptions:
    action: receive
    channel:
      $ref: '#/channels/listSubscriptions'
    summary: List active subscriptions
    messages:
      - $ref: '#/channels/listSubscriptions/messages/listSubscriptionsCommand'
  sendAuth:
    action: receive
    channel:
      $ref: '#/channels/auth'
    summary: Authenticate connection
    messages:
      - $ref: '#/channels/auth/messages/authCommand'
  sendLogout:
    action: receive
    channel:
      $ref: '#/channels/logout'
    summary: Log out
    messages:
      - $ref: '#/channels/logout/messages/logoutCommand'
  receiveSubscribeResponse:
    action: send
    channel:
      $ref: '#/channels/subscribe'
    summary: Subscription confirmation
    messages:
      - $ref: '#/channels/subscribe/messages/subscribeResponse'
  receiveUnsubscribeResponse:
    action: send
    channel:
      $ref: '#/channels/unsubscribe'
    summary: Unsubscription confirmation
    messages:
      - $ref: '#/channels/unsubscribe/messages/unsubscribeResponse'
  receiveListSubscriptionsResponse:
    action: send
    channel:
      $ref: '#/channels/listSubscriptions'
    summary: Current subscription list
    messages:
      - $ref: '#/channels/listSubscriptions/messages/listSubscriptionsResponse'
  receiveAuthOk:
    action: send
    channel:
      $ref: '#/channels/auth'
    summary: Authentication successful
    messages:
      - $ref: '#/channels/auth/messages/authOk'
  receiveAuthError:
    action: send
    channel:
      $ref: '#/channels/auth'
    summary: Authentication failed
    messages:
      - $ref: '#/channels/auth/messages/authError'
  receiveLoggedOut:
    action: send
    channel:
      $ref: '#/channels/logout'
    summary: Logout confirmation
    messages:
      - $ref: '#/channels/logout/messages/loggedOut'
  receiveError:
    action: send
    channel:
      $ref: '#/channels/errors'
    summary: Error response
    messages:
      - $ref: '#/channels/errors/messages/errorMessage'
  receiveBookUpdates:
    action: send
    channel:
      $ref: '#/channels/bookUpdates'
    summary: Receive order book updates
    messages:
      - $ref: '#/channels/bookUpdates/messages/bookSnapshot'
      - $ref: '#/channels/bookUpdates/messages/bookUpdate'
  receiveTickerUpdates:
    action: send
    channel:
      $ref: '#/channels/tickerUpdates'
    summary: Receive ticker updates
    messages:
      - $ref: '#/channels/tickerUpdates/messages/tickerUpdate'
  receiveTrades:
    action: send
    channel:
      $ref: '#/channels/trades'
    summary: Receive public trades
    messages:
      - $ref: '#/channels/trades/messages/trade'
  receiveIndexUpdates:
    action: send
    channel:
      $ref: '#/channels/indexUpdates'
    summary: Receive index updates
    messages:
      - $ref: '#/channels/indexUpdates/messages/indexUpdate'
  receiveFundingEvents:
    action: send
    channel:
      $ref: '#/channels/fundingEvents'
    summary: Receive funding events
    messages:
      - $ref: '#/channels/fundingEvents/messages/fundingEvent'
  receiveCandleUpdates1m:
    action: send
    channel:
      $ref: '#/channels/candleUpdates1m'
    summary: Receive 1-minute candle updates
    messages:
      - $ref: '#/channels/candleUpdates1m/messages/candleUpdate'
  receiveCandleUpdates5m:
    action: send
    channel:
      $ref: '#/channels/candleUpdates5m'
    summary: Receive 5-minute candle updates
    messages:
      - $ref: '#/channels/candleUpdates5m/messages/candleUpdate'
  receiveCandleUpdates1d:
    action: send
    channel:
      $ref: '#/channels/candleUpdates1d'
    summary: Receive 1-day candle updates
    messages:
      - $ref: '#/channels/candleUpdates1d/messages/candleUpdate'
  receiveHeartbeat:
    action: send
    channel:
      $ref: '#/channels/heartbeat'
    summary: Receive heartbeats
    messages:
      - $ref: '#/channels/heartbeat/messages/heartbeat'
  receiveOrderUpdates:
    action: send
    channel:
      $ref: '#/channels/userOrders'
    summary: Receive order updates
    messages:
      - $ref: '#/channels/userOrders/messages/orderUpdate'
  receiveFills:
    action: send
    channel:
      $ref: '#/channels/userFills'
    summary: Receive fill events
    messages:
      - $ref: '#/channels/userFills/messages/fill'
  receivePositionUpdates:
    action: send
    channel:
      $ref: '#/channels/userPositions'
    summary: Receive position updates
    messages:
      - $ref: '#/channels/userPositions/messages/positionUpdate'
  receiveAccountUpdates:
    action: send
    channel:
      $ref: '#/channels/userAccount'
    summary: Receive account updates
    messages:
      - $ref: '#/channels/userAccount/messages/accountUpdate'
components:
  messages:
    SubscribeCommand:
      name: Subscribe
      summary: Subscribe to channels
      payload:
        type: object
        required:
          - cmd
          - params
        properties:
          id:
            type: integer
            description: Client-generated request ID for response correlation
            example: 1
          cmd:
            type: string
            const: subscribe
          params:
            type: object
            required:
              - channels
              - tickers
            properties:
              channels:
                type: array
                items:
                  type: string
                description: Channels to subscribe to
                example:
                  - bookUpdates
                  - tickerUpdates
              tickers:
                type: array
                items:
                  type: string
                description: Market tickers to subscribe to
                example:
                  - OPENAI
      examples:
        - payload:
            id: 1
            cmd: subscribe
            params:
              channels:
                - bookUpdates
                - tickerUpdates
              tickers:
                - OPENAI
    UnsubscribeCommand:
      name: Unsubscribe
      summary: Unsubscribe from channels
      payload:
        type: object
        required:
          - cmd
          - params
        properties:
          id:
            type: integer
            example: 2
          cmd:
            type: string
            const: unsubscribe
          params:
            type: object
            required:
              - channels
              - tickers
            properties:
              channels:
                type: array
                items:
                  type: string
                example:
                  - tickerUpdates
              tickers:
                type: array
                items:
                  type: string
                example:
                  - OPENAI
      examples:
        - payload:
            id: 2
            cmd: unsubscribe
            params:
              channels:
                - tickerUpdates
              tickers:
                - OPENAI
    ListSubscriptionsCommand:
      name: List subscriptions
      summary: List active subscriptions
      payload:
        type: object
        required:
          - cmd
        properties:
          id:
            type: integer
            example: 3
          cmd:
            type: string
            const: listSubscriptions
      examples:
        - payload:
            id: 3
            cmd: listSubscriptions
    AuthCommand:
      name: Auth
      summary: Authenticate with HMAC signature
      payload:
        type: object
        required:
          - cmd
          - params
        properties:
          id:
            type: integer
            example: 1
          cmd:
            type: string
            const: auth
          params:
            type: object
            required:
              - key
              - timestamp
              - signature
            properties:
              key:
                type: string
                description: API key ID
                example: fk_abc123def456
              timestamp:
                type: string
                description: Unix timestamp in seconds
                example: '1740441600'
              signature:
                type: string
                description: >-
                  Base64-encoded HMAC-SHA256 signature of `timestamp + "GET" +
                  "/ws/v1"`
                example: dGhpcyBpcyBhIHNhbXBsZSBzaWduYXR1cmU=
      examples:
        - payload:
            id: 1
            cmd: auth
            params:
              key: fk_abc123def456
              timestamp: '1740441600'
              signature: dGhpcyBpcyBhIHNhbXBsZSBzaWduYXR1cmU=
    LogoutCommand:
      name: Logout
      summary: Log out and remove private subscriptions
      payload:
        type: object
        required:
          - cmd
        properties:
          id:
            type: integer
            example: 4
          cmd:
            type: string
            const: logout
      examples:
        - payload:
            id: 4
            cmd: logout
    SubscribeResponse:
      name: Subscribed
      summary: Subscription confirmation
      payload:
        type: object
        required:
          - type
          - result
        properties:
          id:
            type: integer
            example: 1
          type:
            type: string
            const: subscribed
          result:
            type: object
            properties:
              channels:
                type: array
                items:
                  type: string
                example:
                  - bookUpdates
                  - tickerUpdates
              tickers:
                type: array
                items:
                  type: string
                example:
                  - OPENAI
      examples:
        - payload:
            id: 1
            type: subscribed
            result:
              channels:
                - bookUpdates
                - tickerUpdates
              tickers:
                - OPENAI
    UnsubscribeResponse:
      name: Unsubscribed
      summary: Unsubscription confirmation
      payload:
        type: object
        required:
          - type
          - result
        properties:
          id:
            type: integer
            example: 2
          type:
            type: string
            const: unsubscribed
          result:
            type: object
            properties:
              channels:
                type: array
                items:
                  type: string
                example:
                  - tickerUpdates
              tickers:
                type: array
                items:
                  type: string
                example:
                  - OPENAI
      examples:
        - payload:
            id: 2
            type: unsubscribed
            result:
              channels:
                - tickerUpdates
              tickers:
                - OPENAI
    ListSubscriptionsResponse:
      name: Subscriptions
      summary: Current subscription list
      payload:
        type: object
        required:
          - type
          - result
        properties:
          id:
            type: integer
            example: 3
          type:
            type: string
            const: subscriptions
          result:
            type: object
            properties:
              subscriptions:
                type: array
                items:
                  type: object
                  properties:
                    channel:
                      type: string
                      example: bookUpdates
                    tickers:
                      type: array
                      items:
                        type: string
                      example:
                        - OPENAI
      examples:
        - payload:
            id: 3
            type: subscriptions
            result:
              subscriptions:
                - channel: bookUpdates
                  tickers:
                    - OPENAI
                - channel: tickerUpdates
                  tickers:
                    - OPENAI
    AuthOk:
      name: Auth OK
      summary: Authentication successful
      payload:
        type: object
        required:
          - event
        properties:
          id:
            type: integer
            example: 1
          event:
            type: string
            const: authOk
      examples:
        - payload:
            id: 1
            event: authOk
    AuthError:
      name: Auth error
      summary: Authentication failed
      payload:
        type: object
        required:
          - type
          - error
        properties:
          id:
            type: integer
            example: 1
          type:
            type: string
            const: error
          error:
            type: object
            required:
              - code
              - message
            properties:
              code:
                type: string
                description: Error code
                enum:
                  - INVALID_SIGNATURE
                  - MISSING_CREDENTIALS
                example: INVALID_SIGNATURE
              message:
                type: string
                example: Signature verification failed
      examples:
        - payload:
            id: 1
            type: error
            error:
              code: INVALID_SIGNATURE
              message: Signature verification failed
    LoggedOut:
      name: Logged out
      summary: Successfully logged out
      payload:
        type: object
        required:
          - event
        properties:
          id:
            type: integer
            example: 4
          event:
            type: string
            const: loggedOut
      examples:
        - payload:
            id: 4
            event: loggedOut
    ErrorMessage:
      name: Error
      summary: Error response
      payload:
        type: object
        required:
          - type
          - error
        properties:
          id:
            type: integer
          type:
            type: string
            const: error
          error:
            type: object
            required:
              - code
              - message
            properties:
              code:
                type: string
                enum:
                  - UNKNOWN_COMMAND
                  - INVALID_CHANNEL
                  - AUTH_REQUIRED
                  - RATE_LIMIT
                  - CONNECTION_LIMIT
                example: AUTH_REQUIRED
              message:
                type: string
                example: Authentication required for private channels
      examples:
        - payload:
            id: 5
            type: error
            error:
              code: AUTH_REQUIRED
              message: Authentication required for private channels
    BookSnapshot:
      name: Book snapshot
      summary: Full order book snapshot
      description: >-
        Sent once when subscribing to `bookUpdates`. Contains the complete order
        book state.
      payload:
        type: object
        required:
          - type
          - channel
          - ticker
          - data
        properties:
          type:
            type: string
            const: bookSnapshot
          channel:
            type: string
            const: bookUpdates
          ticker:
            type: string
            example: OPENAI
          data:
            type: object
            required:
              - seq
              - bids
              - asks
              - updatedAt
            properties:
              seq:
                type: integer
                description: >-
                  Sequence number. Verify incremental updates continue from this
                  value.
                example: 100
              bids:
                type: array
                description: Bid levels sorted by descending price
                items:
                  $ref: '#/components/schemas/BookLevel'
              asks:
                type: array
                description: Ask levels sorted by ascending price
                items:
                  $ref: '#/components/schemas/BookLevel'
              updatedAt:
                type: string
                format: date-time
                description: Last update timestamp (ISO 8601)
                example: '2026-02-25T12:00:00.000Z'
      examples:
        - payload:
            type: bookSnapshot
            channel: bookUpdates
            ticker: OPENAI
            data:
              seq: 100
              bids:
                - price: 10500
                  qty: 10
                - price: 10450
                  qty: 25
              asks:
                - price: 10600
                  qty: 8
                - price: 10650
                  qty: 15
              updatedAt: '2026-02-25T12:00:00.000Z'
    BookUpdate:
      name: Book update
      summary: Incremental order book update
      description: >
        Incremental update to a single price level. The `qty` is the **new
        absolute size** at that level.

        A `qty` of `0` means the level has been removed.
      payload:
        type: object
        required:
          - type
          - channel
          - ticker
          - data
        properties:
          type:
            type: string
            const: bookUpdate
          channel:
            type: string
            const: bookUpdates
          ticker:
            type: string
            example: OPENAI
          data:
            type: object
            required:
              - seq
              - side
              - price
              - qty
              - timestamp
            properties:
              seq:
                type: integer
                description: >-
                  Sequence number. Must increment by 1 from the previous
                  message.
                example: 101
              side:
                type: string
                enum:
                  - buy
                  - sell
                example: buy
              price:
                type: number
                example: 10500
              qty:
                type: number
                description: >-
                  New absolute quantity at this price level. 0 means the level
                  is removed.
                example: 15
              timestamp:
                type: string
                format: date-time
                description: Update timestamp (ISO 8601)
                example: '2026-02-25T12:00:00.100Z'
      examples:
        - payload:
            type: bookUpdate
            channel: bookUpdates
            ticker: OPENAI
            data:
              seq: 101
              side: buy
              price: 10500
              qty: 15
              timestamp: '2026-02-25T12:00:00.100Z'
    TickerUpdate:
      name: Ticker update
      summary: Level 1 market data update
      payload:
        type: object
        required:
          - type
          - channel
          - ticker
          - data
        properties:
          type:
            type: string
            const: tickerUpdate
          channel:
            type: string
            const: tickerUpdates
          ticker:
            type: string
            example: OPENAI
          data:
            type: object
            description: Ticker data
            properties:
              index:
                type: string
                example: OPENAI-IDX
              movingFundingRate:
                type:
                  - number
                  - 'null'
                description: >-
                  Estimated next funding rate based on the average premium index
                  in the current funding window
                example: 0.0001
              lastSettledFundingRate:
                type:
                  - number
                  - 'null'
                example: 0.0001
              lastPrice:
                type:
                  - number
                  - 'null'
                example: 10550
              markPrice:
                type:
                  - number
                  - 'null'
                description: >-
                  Fair-value mark price in cents used for unrealized PnL and
                  liquidation checks
                example: 10525
              bestBid:
                type:
                  - number
                  - 'null'
                example: 10500
              bestAsk:
                type:
                  - number
                  - 'null'
                example: 10600
              openInterest:
                type: number
                example: 1234
              highPastDay:
                type:
                  - number
                  - 'null'
                example: 11000
              lowPastDay:
                type:
                  - number
                  - 'null'
                example: 10000
              volumePastDay:
                type: number
                example: 500000
              changePercentPastDay:
                type:
                  - number
                  - 'null'
                example: 2.5
              changePastDay:
                type:
                  - number
                  - 'null'
                example: 250
              cumFunding:
                type: number
                example: 0.0023
              fundingAvgPastWeek:
                type:
                  - number
                  - 'null'
                example: 0.0001
              fundingHighPastWeek:
                type:
                  - number
                  - 'null'
                example: 0.0003
              fundingLowPastWeek:
                type:
                  - number
                  - 'null'
                example: -0.0001
              lastIndexValue:
                type:
                  - number
                  - 'null'
                example: 100
              changeIndexPercentPastDay:
                type:
                  - number
                  - 'null'
                example: 1.5
              changeIndexPastDay:
                type:
                  - number
                  - 'null'
                example: 1.5
              changeIndexPercentPastWeek:
                type:
                  - number
                  - 'null'
                example: 3
              changeIndexPastWeek:
                type:
                  - number
                  - 'null'
                example: 3
              changeIndexPercentPastMonth:
                type:
                  - number
                  - 'null'
                example: 10
              changeIndexPastMonth:
                type:
                  - number
                  - 'null'
                example: 10
              changeIndexPercentPastYear:
                type:
                  - number
                  - 'null'
                example: null
              changeIndexPastYear:
                type:
                  - number
                  - 'null'
                example: null
              changeIndexPercentAllTime:
                type:
                  - number
                  - 'null'
                example: 50
              changeIndexAllTime:
                type:
                  - number
                  - 'null'
                example: 50
              updatedAt:
                type: string
                format: date-time
                example: '2025-02-25T00:00:00.000Z'
      examples:
        - payload:
            type: tickerUpdate
            channel: tickerUpdates
            ticker: OPENAI
            data:
              index: OPENAI-IDX
              movingFundingRate: 0.0001
              lastSettledFundingRate: 0.0001
              lastPrice: 10550
              markPrice: 10525
              bestBid: 10500
              bestAsk: 10600
              openInterest: 1234
              highPastDay: 11000
              lowPastDay: 10000
              volumePastDay: 500000
              changePercentPastDay: 2.5
              changePastDay: 250
              cumFunding: 0.0023
              fundingAvgPastWeek: 0.0001
              fundingHighPastWeek: 0.0003
              f

# --- truncated at 32 KB (52 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/forum/refs/heads/main/asyncapi/forum-websocket-asyncapi.yml