Betfair Exchange Stream API

Low-latency, subscription-based push of market and order changes over a persistent raw SSL/TCP socket to stream-api.betfair.com:443. The protocol is CRLF-delimited JSON (one JSON message per line) - NOT WebSocket; attempted WebSocket connections are refused. Clients authenticate then send marketSubscription / orderSubscription requests and receive market change (mcm) and order change (ocm) messages plus connection, status, and heartbeat frames.

AsyncAPI Specification

betfair-asyncapi.yml 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
Where this information came from

This is an independent, third-party profile of Betfair Exchange Stream API, published by API Evangelist. We do not operate, host, resell, or support these APIs, and we are not affiliated with or endorsed by the company unless stated above. Everything here is built from publicly available information — the company's own site, developer portal, documentation, public repositories, and the specifications it publishes for public use. Nothing is obtained by breaching a system, defeating an access control, or using credentials.

The Kin Score and Agent Readiness rating are independently calculated assessments of a company's public API artifacts, scored against a published rubric. They are not certifications, endorsements, security assessments, or audits.

Corrections, re-scores, and removal are free — no partnership or purchase required, and you do not need to justify the request. A removed company is recorded as unrated, never scored zero for having asked. Acknowledgement within one business day; removal within two.

info@apievangelist.com · Read the full data-sourcing policy →
On a security or compliance team? Put security in the subject line and you will get a person, not a form — we will tell you exactly which public URLs this profile was built from.