Betfair · AsyncAPI Specification

Betfair Exchange Stream API (SSL/TCP)

Version 1.0.0

AsyncAPI 2.6 description of the Betfair **Exchange Stream API** - Betfair's low-latency, subscription-based push channel for market and order changes. IMPORTANT TRANSPORT NOTE: this is **NOT a WebSocket API**. The Exchange Stream API is a persistent **raw SSL/TCP socket** to `stream-api.betfair.com` on **port 443**, over which messages are exchanged as **CRLF-delimited JSON** - one complete JSON object per line, terminated by `\r\n`, with JSON pretty-printing turned off. Betfair's own documentation states that any attempted WebSocket connection will be refused. `secure-tcp` is used as the AsyncAPI server protocol; the exact socket semantics are documented here and in `info.x-transport-notes`. Flow: open the SSL socket, read the initial `connection` message, send an `authentication` request (appKey + session token), then send `marketSubscription` and/or `orderSubscription` requests. The server then pushes `mcm` (market change) and `ocm` (order change) messages plus periodic `status` and `heartbeat` frames. A `heartbeat` request may be sent to keep the socket alive; a message must be sent within 15 seconds of connecting or the server returns a TIMEOUT status. Every RequestMessage carries a client-supplied integer `id`, echoed back on the corresponding `status` ResponseMessage. The `op` field on every message identifies its type for correct (de)serialization.

View Spec View on GitHub Betting ExchangeSports BettingWageringTradingMarket DataJSON-RPCStreamingAsyncAPIWebhooksEvents

Channels

authentication
publish sendAuthentication
Authenticate the stream connection.
Client -> server request that authenticates the socket using the Application Key and the session token (ssoid) from identity SSO login. Must be sent before any subscription. The server replies with a `status` message on the response stream.
marketSubscription
publish sendMarketSubscription
Subscribe to market changes.
Client -> server request subscribing to market changes for a set of markets (via a marketFilter) at a chosen priceData/ladder level (via a marketDataFilter). The server then pushes `mcm` messages on the change stream.
orderSubscription
publish sendOrderSubscription
Subscribe to order changes.
Client -> server request subscribing to the customer's order changes. The server then pushes `ocm` messages on the change stream.
heartbeatRequest
publish sendHeartbeat
Send a keep-alive heartbeat request.
Client -> server keep-alive request (op=heartbeat). Used to keep the socket active and detect a broken connection; the server replies with a `status` message.
connectionStream
subscribe receiveConnection
Receive the initial connection frame.
Server -> client initial `connection` message sent on socket open, carrying the connectionId.
statusStream
subscribe receiveStatus
Receive status / acknowledgement frames.
Server -> client `status` messages - the acknowledgement/response to a request `id`, plus connection health (connectionsAvailable) and error details (statusCode, errorCode, errorMessage).
marketChangeStream
subscribe receiveMarketChange
Receive market change messages.
Server -> client `mcm` (Market Change Message) frames pushing price/status deltas for subscribed markets.
orderChangeStream
subscribe receiveOrderChange
Receive order change messages.
Server -> client `ocm` (Order Change Message) frames pushing order/matched deltas for the customer.

Messages

AuthenticationMessage
Authentication request
Authenticates the socket with appKey + session token.
MarketSubscriptionMessage
Market subscription request
OrderSubscriptionMessage
Order subscription request
HeartbeatRequestMessage
Heartbeat request
ConnectionMessage
Connection frame
StatusMessage
Status / acknowledgement frame
MarketChangeMessage
Market Change Message
Push of market price/status deltas.
OrderChangeMessage
Order Change Message
Push of the customer's order/matched deltas.

Servers

secure-tcp
production stream-api.betfair.com:443
Production Exchange Stream endpoint. Establish an SSL/TLS socket to this host:port and exchange CRLF-delimited JSON messages. This is a raw TCP socket over SSL - not WebSocket and not HTTP.
secure-tcp
integration stream-api-integration.betfair.com:443
Integration/test Exchange Stream endpoint with the same protocol.

AsyncAPI Specification

Raw ↑
asyncapi: '2.6.0'
id: 'urn:com:betfair:exchange:stream-api'
info:
  title: Betfair Exchange Stream API (SSL/TCP)
  version: '1.0.0'
  description: |
    AsyncAPI 2.6 description of the Betfair **Exchange Stream API** - Betfair's
    low-latency, subscription-based push channel for market and order changes.

    IMPORTANT TRANSPORT NOTE: this is **NOT a WebSocket API**. The Exchange
    Stream API is a persistent **raw SSL/TCP socket** to
    `stream-api.betfair.com` on **port 443**, over which messages are exchanged
    as **CRLF-delimited JSON** - one complete JSON object per line, terminated
    by `\r\n`, with JSON pretty-printing turned off. Betfair's own
    documentation states that any attempted WebSocket connection will be
    refused. `secure-tcp` is used as the AsyncAPI server protocol; the exact
    socket semantics are documented here and in `info.x-transport-notes`.

    Flow: open the SSL socket, read the initial `connection` message, send an
    `authentication` request (appKey + session token), then send
    `marketSubscription` and/or `orderSubscription` requests. The server then
    pushes `mcm` (market change) and `ocm` (order change) messages plus periodic
    `status` and `heartbeat` frames. A `heartbeat` request may be sent to keep
    the socket alive; a message must be sent within 15 seconds of connecting or
    the server returns a TIMEOUT status.

    Every RequestMessage carries a client-supplied integer `id`, echoed back on
    the corresponding `status` ResponseMessage. The `op` field on every message
    identifies its type for correct (de)serialization.
  contact:
    name: API Evangelist
    email: kin@apievangelist.com
    url: https://apievangelist.com
  license:
    name: API documentation - Betfair Developer Program Terms
    url: https://developer.betfair.com/
  x-transport-notes:
    transport: Raw SSL/TCP socket (persistent)
    host: stream-api.betfair.com
    integrationHost: stream-api-integration.betfair.com
    port: 443
    framing: CRLF-delimited JSON (one JSON object per line, terminated by \r\n)
    prettyPrint: must be disabled
    isWebSocket: false
    webSocketRefused: true
    connectTimeoutSeconds: 15
    source: https://github.com/betfair/stream-api-sample-code
defaultContentType: application/json
servers:
  production:
    url: stream-api.betfair.com:443
    protocol: secure-tcp
    description: |
      Production Exchange Stream endpoint. Establish an SSL/TLS socket to this
      host:port and exchange CRLF-delimited JSON messages. This is a raw TCP
      socket over SSL - not WebSocket and not HTTP.
  integration:
    url: stream-api-integration.betfair.com:443
    protocol: secure-tcp
    description: Integration/test Exchange Stream endpoint with the same protocol.
channels:
  authentication:
    description: |
      Client -> server request that authenticates the socket using the
      Application Key and the session token (ssoid) from identity SSO login.
      Must be sent before any subscription. The server replies with a `status`
      message on the response stream.
    publish:
      operationId: sendAuthentication
      summary: Authenticate the stream connection.
      message:
        $ref: '#/components/messages/AuthenticationMessage'
  marketSubscription:
    description: |
      Client -> server request subscribing to market changes for a set of
      markets (via a marketFilter) at a chosen priceData/ladder level (via a
      marketDataFilter). The server then pushes `mcm` messages on the change
      stream.
    publish:
      operationId: sendMarketSubscription
      summary: Subscribe to market changes.
      message:
        $ref: '#/components/messages/MarketSubscriptionMessage'
  orderSubscription:
    description: |
      Client -> server request subscribing to the customer's order changes. The
      server then pushes `ocm` messages on the change stream.
    publish:
      operationId: sendOrderSubscription
      summary: Subscribe to order changes.
      message:
        $ref: '#/components/messages/OrderSubscriptionMessage'
  heartbeatRequest:
    description: |
      Client -> server keep-alive request (op=heartbeat). Used to keep the
      socket active and detect a broken connection; the server replies with a
      `status` message.
    publish:
      operationId: sendHeartbeat
      summary: Send a keep-alive heartbeat request.
      message:
        $ref: '#/components/messages/HeartbeatRequestMessage'
  connectionStream:
    description: Server -> client initial `connection` message sent on socket open, carrying the connectionId.
    subscribe:
      operationId: receiveConnection
      summary: Receive the initial connection frame.
      message:
        $ref: '#/components/messages/ConnectionMessage'
  statusStream:
    description: |
      Server -> client `status` messages - the acknowledgement/response to a
      request `id`, plus connection health (connectionsAvailable) and error
      details (statusCode, errorCode, errorMessage).
    subscribe:
      operationId: receiveStatus
      summary: Receive status / acknowledgement frames.
      message:
        $ref: '#/components/messages/StatusMessage'
  marketChangeStream:
    description: Server -> client `mcm` (Market Change Message) frames pushing price/status deltas for subscribed markets.
    subscribe:
      operationId: receiveMarketChange
      summary: Receive market change messages.
      message:
        $ref: '#/components/messages/MarketChangeMessage'
  orderChangeStream:
    description: Server -> client `ocm` (Order Change Message) frames pushing order/matched deltas for the customer.
    subscribe:
      operationId: receiveOrderChange
      summary: Receive order change messages.
      message:
        $ref: '#/components/messages/OrderChangeMessage'
components:
  messages:
    AuthenticationMessage:
      name: authentication
      title: Authentication request
      summary: Authenticates the socket with appKey + session token.
      contentType: application/json
      payload:
        type: object
        required: [op, id, appKey, session]
        properties:
          op:
            type: string
            enum: [authentication]
          id:
            type: integer
            description: Client-supplied request id, echoed on the status response.
          appKey:
            type: string
          session:
            type: string
            description: Session token (ssoid) from identity SSO login.
      examples:
        - name: auth
          payload:
            op: authentication
            id: 1
            appKey: 'YOUR_APP_KEY'
            session: 'YOUR_SESSION_TOKEN'
    MarketSubscriptionMessage:
      name: marketSubscription
      title: Market subscription request
      contentType: application/json
      payload:
        type: object
        required: [op, id]
        properties:
          op:
            type: string
            enum: [marketSubscription]
          id:
            type: integer
          marketFilter:
            type: object
            properties:
              marketIds:
                type: array
                items:
                  type: string
              eventTypeIds:
                type: array
                items:
                  type: string
              countryCodes:
                type: array
                items:
                  type: string
              marketTypes:
                type: array
                items:
                  type: string
          marketDataFilter:
            type: object
            properties:
              ladderLevels:
                type: integer
                maximum: 10
              fields:
                type: array
                items:
                  type: string
                  enum: [EX_BEST_OFFERS, EX_ALL_OFFERS, EX_TRADED, EX_TRADED_VOL, EX_LTP, EX_MARKET_DEF, SP_TRADED, SP_PROJECTED, EX_BEST_OFFERS_DISP]
          conflateMs:
            type: integer
          heartbeatMs:
            type: integer
      examples:
        - name: marketSub
          payload:
            op: marketSubscription
            id: 2
            marketFilter:
              marketIds: ['1.234567890']
            marketDataFilter:
              ladderLevels: 3
              fields: [EX_BEST_OFFERS, EX_LTP]
    OrderSubscriptionMessage:
      name: orderSubscription
      title: Order subscription request
      contentType: application/json
      payload:
        type: object
        required: [op, id]
        properties:
          op:
            type: string
            enum: [orderSubscription]
          id:
            type: integer
          orderFilter:
            type: object
            properties:
              includeOverallPosition:
                type: boolean
              partitionMatchedByStrategyRef:
                type: boolean
          conflateMs:
            type: integer
          heartbeatMs:
            type: integer
    HeartbeatRequestMessage:
      name: heartbeatRequest
      title: Heartbeat request
      contentType: application/json
      payload:
        type: object
        required: [op, id]
        properties:
          op:
            type: string
            enum: [heartbeat]
          id:
            type: integer
    ConnectionMessage:
      name: connection
      title: Connection frame
      contentType: application/json
      payload:
        type: object
        properties:
          op:
            type: string
            enum: [connection]
          connectionId:
            type: string
      examples:
        - name: connection
          payload:
            op: connection
            connectionId: '206-221216154618-94060'
    StatusMessage:
      name: status
      title: Status / acknowledgement frame
      contentType: application/json
      payload:
        type: object
        properties:
          op:
            type: string
            enum: [status]
          id:
            type: integer
            description: Echoes the request id being acknowledged.
          statusCode:
            type: string
            enum: [SUCCESS, FAILURE]
          errorCode:
            type: string
            enum:
              - NO_APP_KEY
              - INVALID_APP_KEY
              - NO_SESSION
              - INVALID_SESSION_INFORMATION
              - NOT_AUTHORIZED
              - INVALID_INPUT
              - INVALID_CLOCK
              - UNEXPECTED_ERROR
              - TIMEOUT
              - SUBSCRIPTION_LIMIT_EXCEEDED
              - INVALID_REQUEST
              - CONNECTION_FAILED
              - MAX_CONNECTION_LIMIT_EXCEEDED
              - TOO_MANY_REQUESTS
          errorMessage:
            type: string
          connectionClosed:
            type: boolean
          connectionsAvailable:
            type: integer
      examples:
        - name: ok
          payload:
            op: status
            id: 1
            statusCode: SUCCESS
            connectionClosed: false
    MarketChangeMessage:
      name: mcm
      title: Market Change Message
      summary: Push of market price/status deltas.
      contentType: application/json
      payload:
        type: object
        properties:
          op:
            type: string
            enum: [mcm]
          id:
            type: integer
          ct:
            type: string
            enum: [SUB_IMAGE, RESUB_DELTA, HEARTBEAT]
            description: Change type; absent for a normal delta.
          clk:
            type: string
            description: Sequence token for this stream position.
          initialClk:
            type: string
          conflateMs:
            type: integer
          heartbeatMs:
            type: integer
          pt:
            type: integer
            format: int64
            description: Publish time (epoch millis).
          mc:
            type: array
            description: Array of market changes.
            items:
              type: object
              properties:
                id:
                  type: string
                  description: Market id.
                con:
                  type: boolean
                  description: Whether the data is conflated.
                img:
                  type: boolean
                  description: Whether this is a full image (replace) vs delta.
                tv:
                  type: number
                  description: Total value/volume matched.
                marketDefinition:
                  type: object
                rc:
                  type: array
                  description: Runner changes.
                  items:
                    type: object
                    properties:
                      id:
                        type: integer
                        format: int64
                        description: selectionId.
                      ltp:
                        type: number
                        description: Last traded price.
                      tv:
                        type: number
                      batb:
                        type: array
                        description: Best available to back [level, price, size].
                        items:
                          type: array
                          items:
                            type: number
                      batl:
                        type: array
                        description: Best available to lay [level, price, size].
                        items:
                          type: array
                          items:
                            type: number
      examples:
        - name: heartbeatFrame
          payload:
            op: mcm
            id: 2
            ct: HEARTBEAT
            clk: 'AAAAAAAA'
            pt: 1671205578000
        - name: delta
          payload:
            op: mcm
            id: 2
            clk: 'ABAQAB'
            pt: 1671205579000
            mc:
              - id: '1.234567890'
                tv: 12345.67
                rc:
                  - id: 47972
                    ltp: 3.4
                    batb: [[0, 3.35, 120.0]]
                    batl: [[0, 3.45, 90.0]]
    OrderChangeMessage:
      name: ocm
      title: Order Change Message
      summary: Push of the customer's order/matched deltas.
      contentType: application/json
      payload:
        type: object
        properties:
          op:
            type: string
            enum: [ocm]
          id:
            type: integer
          ct:
            type: string
            enum: [SUB_IMAGE, RESUB_DELTA, HEARTBEAT]
          clk:
            type: string
          pt:
            type: integer
            format: int64
          oc:
            type: array
            description: Order changes by market.
            items:
              type: object
              properties:
                id:
                  type: string
                  description: Market id.
                orc:
                  type: array
                  description: Order runner changes.
                  items:
                    type: object
                    properties:
                      id:
                        type: integer
                        format: int64
                        description: selectionId.
                      uo:
                        type: array
                        description: Unmatched orders.
                        items:
                          type: object
                      mb:
                        type: array
                        description: Matched backs [price, size].
                        items:
                          type: array
                          items:
                            type: number
                      ml:
                        type: array
                        description: Matched lays [price, size].
                        items:
                          type: array
                          items:
                            type: number