diff --git a/docs/networks/node-ops/access-onchain-data/access-nodes/accessing-data/websockets-stream-api/_category_.yml b/docs/networks/node-ops/access-onchain-data/access-nodes/accessing-data/websockets-stream-api/_category_.yml new file mode 100644 index 0000000000..cb16fc145f --- /dev/null +++ b/docs/networks/node-ops/access-onchain-data/access-nodes/accessing-data/websockets-stream-api/_category_.yml @@ -0,0 +1 @@ +label: Websockets Stream API \ No newline at end of file diff --git a/docs/networks/node-ops/access-onchain-data/access-nodes/accessing-data/websockets-stream-api/list-subscriptions-message.md b/docs/networks/node-ops/access-onchain-data/access-nodes/accessing-data/websockets-stream-api/list-subscriptions-message.md new file mode 100644 index 0000000000..16596bbfe1 --- /dev/null +++ b/docs/networks/node-ops/access-onchain-data/access-nodes/accessing-data/websockets-stream-api/list-subscriptions-message.md @@ -0,0 +1,48 @@ +--- +title: List subscriptions request message format +sidebar_label: Listing subscriptions +sidebar_position: 4 +--- + +# List subscriptions message format + +List subscriptions requests must be sent as JSON in text frames, one request per frame. +This message is different from other as it doesn't require you to provide subscription ID. +Thus, the response for this message is different too. + +### Example of request + +```json +{ + "action": "list_subscriptions" +} +``` + +### Example of response + +```json +{ + "subscriptions": [ + { + "subscription_id": "uuid-1", + "topic": "blocks", + "parameters": { + "start_block_height": "123456789" + } + }, + { + "subscription_id": "uuid-2", + "topic": "events", + "parameters": {} + } + ] +} +``` + +If there are no active subscriptions, `subscriptions` array will be empty. + +### Request fields + +| Name | Type | Required | Description | +|----------|--------|----------|-----------------------------------------------------------------------------------------| +| `action` | STRING | YES | Action to perform. Must be `list_subscriptions` to initiate a list subscription request | diff --git a/docs/networks/node-ops/access-onchain-data/access-nodes/accessing-data/websockets-stream-api/overview.md b/docs/networks/node-ops/access-onchain-data/access-nodes/accessing-data/websockets-stream-api/overview.md new file mode 100644 index 0000000000..6e964c2373 --- /dev/null +++ b/docs/networks/node-ops/access-onchain-data/access-nodes/accessing-data/websockets-stream-api/overview.md @@ -0,0 +1,191 @@ +--- +title: Overview +sidebar_label: Overview +sidebar_position: 1 +--- + +# Websockets Stream API + +## Overview + +The Stream API allows clients to receive real-time updates from the Flow blockchain via WebSocket connections. It +supports subscribing to various topics, such as blocks, events, and transactions, enabling low-latency access to live +data. + +### Important Information + +- **Endpoint**: The WebSocket server is available at: + ``` + wss://rest-mainnet.onflow.org/ws + ``` +- **Limits**: + - Each connection supports up to 20 concurrent subscriptions. Exceeding this limit will result in an error. + - Each subscription may provide up to 20 responses per second. + - After 1 minute of inactivity (no data is sent to/read from connection) connection is closed. +- **Supported Topics**: + - `blocks` + - `block_headers` + - `block_digests` + - `events` + - `transaction_statuses` + - `account_statuses` +- **Notes**: Always handle errors gracefully and close unused subscriptions to maintain efficient connections. + +--- + +## Setting Up a WebSocket Connection + +Use any WebSocket client library to connect to the endpoint. Below is an example using JavaScript: + +```javascript +const ws = new WebSocket('wss://rest-mainnet.onflow.org/ws'); + +ws.onopen = () => { + console.log('Connected to WebSocket server'); +}; + +ws.onclose = () => { + console.log('Disconnected from WebSocket server'); +}; + +ws.onerror = (error) => { + console.error('WebSocket error:', error); +}; +``` + +--- + +## Subscribing to Topics + +To receive data from a specific topic, send a subscription request in JSON format over the WebSocket connection. + +### Request Format + +```json +{ + "subscription_id": "some-id-42", + "action": "subscribe", + "topic": "blocks", + "arguments": { + "start_block_height": "123456789" + } +} +``` + +- **`subscription_id`**: A unique identifier for the subscription (string with max len constraint). If omitted, the server generates one. +- **`action`**: The action to perform. Supported actions include: `subscribe`, `unsubscribe`, `list_subscriptions`. +- **`topic`**: The topic to subscribe to. See the supported topics in the Overview. +- **`arguments`**: Additional arguments for subscriptions, such as `start_block_height`, `start_block_id`, and others. + +### Response Format + +```json +{ + "subscription_id": "some-id-42", + "action": "subscribe" +} +``` + +--- + +## Unsubscribing from Topics + +To stop receiving data from a specific topic, send an unsubscribe request. + +### Request Format + +```json +{ + "subscription_id": "some-id-42", + "action": "unsubscribe" +} +``` + +### Response Format + +```json +{ + "subscription_id": "some-id-42", + "action": "unsubscribe" +} +``` + +--- + +## Listing Active Subscriptions + +You can retrieve a list of all active subscriptions for the current WebSocket connection. + +### Request Format + +```json +{ + "action": "list_subscriptions" +} +``` + +### Response Format + +```json +{ + "subscriptions": [ + { + "subscription_id": "some-id-1", + "topic": "blocks", + "arguments": { + "start_block_height": "123456789" + } + }, + { + "subscription_id": "some-id-2", + "topic": "events", + "arguments": {} + } + ] +} +``` + +--- + +## Errors Example + +If a request is invalid or cannot be processed, the server responds with an error message. + +### OK Response + +```json +{ + "subscription_id": "some-id-42", + "payload": { + "id": "0x1234...", + "height:": "123456789", + "timestamp": "2025-01-02T10:00:00Z" + } +} +``` + +### Error Response + +```json +{ + "subscription_id": "some-id-42", + "error": { + "code": 500, + "message": "Access Node failed" + } +} +``` + +### Common Error Codes + +- **400**: Invalid message format or arguments +- **404**: Subscription not found +- **500**: Internal server error + +### Asynchronous environments + +If you're working in an asynchronous environment, the Streaming API ensures **first-in first-out** message processing, +so responses will be returned in the same order the requests were received over the connection. +You can leverage this feature to simplify your code and maintain consistency. + +Additionally, you can specify your own `subscription_id` in the subscribe request to easily identify the correct response. diff --git a/docs/networks/node-ops/access-onchain-data/access-nodes/accessing-data/websockets-stream-api/subscribe-message.md b/docs/networks/node-ops/access-onchain-data/access-nodes/accessing-data/websockets-stream-api/subscribe-message.md new file mode 100644 index 0000000000..5b7756e16f --- /dev/null +++ b/docs/networks/node-ops/access-onchain-data/access-nodes/accessing-data/websockets-stream-api/subscribe-message.md @@ -0,0 +1,80 @@ +--- +title: Subscribe request message format +sidebar_label: Subscribing to topic +sidebar_position: 2 +--- + +# Subscribe request format + +Subscribe requests must be sent as JSON in text frames, one request per frame. + +### Example of subscribe request + +```json +{ + "subscription_id": "some-id-1", + "action": "subscribe", + "topic": "block_digests", + "parameters": { + "start_block_height": "99,416,580" + } +} +``` + +### Example of successful response + +```json +{ + "subscription_id": "some-id-1", + "action": "subscribe" +} +``` + +### Example of failed response + +```json +{ + "subscription_id": "some-id-1", + "error": { + "code": 400, + "message": "invalid message" + } +} +``` + +### Example of messages provided by subscription (if successful) + +```json +{ + "subscription_id": "some-id-1", + "payload": { + "id": "0x1234...", + "height:": "123456789", + "timestamp": "2025-01-02T10:00:00Z" + } +} +``` + +### Example of messages provided by subscription (if error) + +```json +{ + "subscription_id": "some-id-1", + "error": { + "code": 500, + "message": "internal error" + } +} +``` + +### Request fields: + +| Name | Type | Required | Description | +|-------------------|--------|----------|-----------------------------------------------------------------------------------------------------------------------------------| +| `subscription_id` | STRING | NO | Optional unique identifier for the subscription. Max length of ID generated by client is 20. Server will generate UUID if omitted | +| `action` | STRING | YES | Action to perform. Must be `subscribe` to initiate a subscription | +| `topic` | STRING | YES | The topic to subscribe to, such as `blocks`, `block_digests`, etc. | +| `arguments` | STRING | NO | Additional topic specific parameters for the subscription, such as `start_block_id`, `start_block_height` or other. | + +You can use `subscription_id` as a client-generated identifier to track responses asynchronously. +If you don't provide `subscription_id`, the server will generate one and include it in the response. diff --git a/docs/networks/node-ops/access-onchain-data/access-nodes/accessing-data/websockets-stream-api/unsubscribe-message.md b/docs/networks/node-ops/access-onchain-data/access-nodes/accessing-data/websockets-stream-api/unsubscribe-message.md new file mode 100644 index 0000000000..069e0b0e4a --- /dev/null +++ b/docs/networks/node-ops/access-onchain-data/access-nodes/accessing-data/websockets-stream-api/unsubscribe-message.md @@ -0,0 +1,45 @@ +--- +title: Unsubscribe request message format +sidebar_label: Unsubscribing from topic +sidebar_position: 3 +--- + +# Unsubscribe message format + +Unsubscribe requests must be sent as JSON in text frames, one request per frame. + +### Example of unsubscribe request + +```json +{ + "subscription_id": "some-id-1", + "action": "unsubscribe" +} +``` + +### Example of successful response + +```json +{ + "subscription_id": "some-id-1", + "action": "unsubscribe" +} +``` + +### Example of error response + +```json +{ + "error": { + "code": 404, + "message": "subscription not found" + } +} +``` + +### Request fields + +| Name | Type | Required | Description | +|-------------------|--------|----------|-----------------------------------------------------------------------| +| `subscription_id` | STRING | YES | Unique identifier of the subscription | +| `action` | STRING | YES | Action to perform. Must be `unsubscribe` to initiate a unsubscription |