AsyncAPI 2.6 description of Stream (GetStream.io) Chat's **real-time WebSocket** surface. Unlike the request/response server-side REST API (`https://chat.stream-io-api.com`, modeled in `openapi/getstream-openapi.yml`), Stream's client SDKs establish a persistent, bidirectional **WebSocket** connection to receive real-time chat events. Per Stream's official docs (getstream.io/chat/docs), every client-side chat integration opens a WebSocket connection via `client.connectUser()`; the connection is how devices receive real-time events. Stream limits the number of open connections per user to 50 in production and 3 in development. ## How the connection is opened A client connects by opening a WebSocket to `wss://chat.stream-io-api.com/connect` with the connection payload and credentials passed as query parameters: - `json` - a URL-encoded JSON object containing `user_details` (at minimum the `id`) and `user_token`. - `api_key` - the application API key. - `authorization` - the user's JWT. - `stream-auth-type` - the literal string `jwt`. On a successful handshake the server immediately emits a `health.check` event carrying a `connection_id`; this same event is re-sent periodically as a heartbeat to keep the socket alive. Thereafter the server pushes chat events (message.new, typing.start, reaction.new, notification.*, user.presence.changed, and others) for the channels the user is watching. The client sends `health.check` events back as keep-alives. Event names and fields are taken from Stream's documented event object (getstream.io/chat/docs/node/event_object).
View SpecView on GitHubChatMessagingActivity FeedsVideoAudioModerationWebSocketReal-TimeAsyncAPIEventsWebSockets
Channels
/connect
publishsendKeepAlive
Send keep-alive events to Stream.
The single multiplexed WebSocket channel. After the handshake, the server pushes all real-time events for the connected user across every channel they watch, and the client publishes keep-alive `health.check` events.
Messages
✉
HealthCheck
Health check / connection heartbeat
Connection keep-alive; the first one carries the connection_id.
✉
MessageNew
New message
A new message was sent to a channel the user watches.
✉
MessageUpdated
Message updated
✉
MessageDeleted
Message deleted
✉
MessageRead
Channel marked read
A user marked a channel read; unread counts changed.
✉
ReactionNew
New reaction
✉
TypingStart
Typing started
✉
TypingStop
Typing stopped
✉
UserPresenceChanged
User presence changed
A watched user's online/offline presence changed.
✉
UserWatchingStart
User started watching a channel
✉
NotificationMessageNew
Notification - new message
A new message arrived in a channel the user is a member of but is not currently watching.
✉
NotificationAddedToChannel
Notification - added to a channel
Servers
wss
productionchat.stream-io-api.com
Stream Chat real-time WebSocket edge. The client opens `wss://chat.stream-io-api.com/connect?json={payload}&api_key={key}&authorization={jwt}&stream-auth-type=jwt`.
asyncapi: '2.6.0'
id: 'urn:io:getstream:chat:websocket'
info:
title: Stream Chat Realtime WebSocket API
version: '1.0.0'
description: |
AsyncAPI 2.6 description of Stream (GetStream.io) Chat's **real-time
WebSocket** surface. Unlike the request/response server-side REST API
(`https://chat.stream-io-api.com`, modeled in
`openapi/getstream-openapi.yml`), Stream's client SDKs establish a
persistent, bidirectional **WebSocket** connection to receive real-time chat
events.
Per Stream's official docs (getstream.io/chat/docs), every client-side chat
integration opens a WebSocket connection via `client.connectUser()`; the
connection is how devices receive real-time events. Stream limits the number
of open connections per user to 50 in production and 3 in development.
## How the connection is opened
A client connects by opening a WebSocket to `wss://chat.stream-io-api.com/connect`
with the connection payload and credentials passed as query parameters:
- `json` - a URL-encoded JSON object containing `user_details` (at minimum
the `id`) and `user_token`.
- `api_key` - the application API key.
- `authorization` - the user's JWT.
- `stream-auth-type` - the literal string `jwt`.
On a successful handshake the server immediately emits a `health.check` event
carrying a `connection_id`; this same event is re-sent periodically as a
heartbeat to keep the socket alive. Thereafter the server pushes chat events
(message.new, typing.start, reaction.new, notification.*, user.presence.changed,
and others) for the channels the user is watching. The client sends `health.check`
events back as keep-alives.
Event names and fields are taken from Stream's documented event object
(getstream.io/chat/docs/node/event_object).
contact:
name: API Evangelist
email: kin@apievangelist.com
url: https://apievangelist.com
license:
name: API documentation - Stream Terms
url: https://getstream.io/legal/terms/
x-transport-notes:
transport: WebSocket
protocol: wss
endpoint: 'wss://chat.stream-io-api.com/connect'
direction: bidirectional
openedBy: 'client.connectUser() in the Stream Chat SDKs'
heartbeat: 'health.check events, sent both by server and client'
connectionLimit: '50 concurrent connections per user in production, 3 in development'
source: https://getstream.io/chat/docs/node/event_object/
defaultContentType: application/json
servers:
production:
url: chat.stream-io-api.com
protocol: wss
description: |
Stream Chat real-time WebSocket edge. The client opens
`wss://chat.stream-io-api.com/connect?json={payload}&api_key={key}&authorization={jwt}&stream-auth-type=jwt`.
security:
- jwtUser: []
channels:
/connect:
description: |
The single multiplexed WebSocket channel. After the handshake, the server
pushes all real-time events for the connected user across every channel
they watch, and the client publishes keep-alive `health.check` events.
bindings:
ws:
bindingVersion: '0.1.0'
query:
type: object
properties:
json:
type: string
description: URL-encoded JSON with user_details and user_token.
api_key:
type: string
description: Application API key.
authorization:
type: string
description: The user JWT.
stream-auth-type:
type: string
enum:
- jwt
subscribe:
operationId: receiveEvents
summary: Receive real-time chat events pushed by Stream.
description: |
Events the server pushes to the connected client over the WebSocket.
Each event is a JSON object with at least a `type` field; many also carry
`cid`, `user`, `message`, `reaction`, `channel`, `watcher_count`, and
`total_unread_count`.
message:
oneOf:
- $ref: '#/components/messages/HealthCheck'
- $ref: '#/components/messages/MessageNew'
- $ref: '#/components/messages/MessageUpdated'
- $ref: '#/components/messages/MessageDeleted'
- $ref: '#/components/messages/MessageRead'
- $ref: '#/components/messages/ReactionNew'
- $ref: '#/components/messages/TypingStart'
- $ref: '#/components/messages/TypingStop'
- $ref: '#/components/messages/UserPresenceChanged'
- $ref: '#/components/messages/UserWatchingStart'
- $ref: '#/components/messages/NotificationMessageNew'
- $ref: '#/components/messages/NotificationAddedToChannel'
publish:
operationId: sendKeepAlive
summary: Send keep-alive events to Stream.
description: |
The client periodically publishes a `health.check` event to keep the
WebSocket connection alive.
message:
$ref: '#/components/messages/HealthCheck'
components:
securitySchemes:
jwtUser:
type: httpApiKey
in: query
name: authorization
description: |
The user JWT passed as the `authorization` query parameter, alongside
`stream-auth-type=jwt` and the application `api_key`.
messages:
HealthCheck:
name: health.check
title: Health check / connection heartbeat
summary: Connection keep-alive; the first one carries the connection_id.
contentType: application/json
payload:
$ref: '#/components/schemas/HealthCheckEvent'
examples:
- name: firstHealthCheck
summary: First event after handshake, carrying connection_id
payload:
type: health.check
connection_id: 8a3b2c1d-1234-5678-9abc-def012345678
created_at: '2026-07-03T12:00:00Z'
me:
id: john
role: user
online: true
MessageNew:
name: message.new
title: New message
summary: A new message was sent to a channel the user watches.
contentType: application/json
payload:
$ref: '#/components/schemas/Event'
examples:
- name: messageNew
payload:
type: message.new
cid: messaging:general
channel_id: general
channel_type: messaging
user:
id: john
message:
id: 8f2a1b3c
text: Hello everyone
type: regular
watcher_count: 5
created_at: '2026-07-03T12:00:01Z'
MessageUpdated:
name: message.updated
title: Message updated
contentType: application/json
payload:
$ref: '#/components/schemas/Event'
MessageDeleted:
name: message.deleted
title: Message deleted
contentType: application/json
payload:
$ref: '#/components/schemas/Event'
MessageRead:
name: message.read
title: Channel marked read
summary: A user marked a channel read; unread counts changed.
contentType: application/json
payload:
$ref: '#/components/schemas/Event'
ReactionNew:
name: reaction.new
title: New reaction
contentType: application/json
payload:
$ref: '#/components/schemas/Event'
examples:
- name: reactionNew
payload:
type: reaction.new
cid: messaging:general
user:
id: jane
message:
id: 8f2a1b3c
reaction:
type: like
score: 1
created_at: '2026-07-03T12:00:02Z'
TypingStart:
name: typing.start
title: Typing started
contentType: application/json
payload:
$ref: '#/components/schemas/Event'
TypingStop:
name: typing.stop
title: Typing stopped
contentType: application/json
payload:
$ref: '#/components/schemas/Event'
UserPresenceChanged:
name: user.presence.changed
title: User presence changed
summary: A watched user's online/offline presence changed.
contentType: application/json
payload:
$ref: '#/components/schemas/Event'
UserWatchingStart:
name: user.watching.start
title: User started watching a channel
contentType: application/json
payload:
$ref: '#/components/schemas/Event'
NotificationMessageNew:
name: notification.message_new
title: Notification - new message
summary: >-
A new message arrived in a channel the user is a member of but is not
currently watching.
contentType: application/json
payload:
$ref: '#/components/schemas/Event'
NotificationAddedToChannel:
name: notification.added_to_channel
title: Notification - added to a channel
contentType: application/json
payload:
$ref: '#/components/schemas/Event'
schemas:
HealthCheckEvent:
type: object
required:
- type
properties:
type:
type: string
enum:
- health.check
connection_id:
type: string
description: The id assigned to this WebSocket connection. Present on the first event.
created_at:
type: string
format: date-time
me:
$ref: '#/components/schemas/OwnUser'
Event:
type: object
description: |
The generic Stream Chat event envelope. `type` is always present; the
other fields appear depending on the event type, per
getstream.io/chat/docs/node/event_object.
required:
- type
properties:
type:
type: string
description: The event type, e.g. message.new, typing.start, reaction.new.
cid:
type: string
description: The channel id in "{type}:{id}" form.
channel_id:
type: string
channel_type:
type: string
message:
$ref: '#/components/schemas/Message'
reaction:
$ref: '#/components/schemas/Reaction'
user:
$ref: '#/components/schemas/User'
member:
type: object
channel:
type: object
watcher_count:
type: integer
total_unread_count:
type: integer
unread_channels:
type: integer
created_at:
type: string
format: date-time
Message:
type: object
properties:
id:
type: string
text:
type: string
type:
type: string
user:
$ref: '#/components/schemas/User'
parent_id:
type: string
created_at:
type: string
format: date-time
Reaction:
type: object
properties:
type:
type: string
score:
type: integer
user_id:
type: string
message_id:
type: string
User:
type: object
properties:
id:
type: string
role:
type: string
online:
type: boolean
name:
type: string
image:
type: string
last_active:
type: string
format: date-time
OwnUser:
allOf:
- $ref: '#/components/schemas/User'
- type: object
properties:
total_unread_count:
type: integer
unread_channels:
type: integer
devices:
type: array
items:
type: object
Discovery needs no key. Ratings and market analysis are Pro.
Get an API key
Free tier, no form to fill in. Signing in shares your email address with us — we
store it to create your key and to recognise you if you sign in with another
provider. See our Privacy Policy and
Terms.