ChainStream API
ChainStream APIs are a way to stream Solana transaction, slot, and block updates directly from the validator.
Introduction
The ChainStream APIs allow you to stream transaction, slot, and block updates in real-time using an RPC PubSub WebSocket. Why does this matter? Having the latest blocks, slot updates (whether they're processed, rooted or confirmed) and real-time processed commitment-level transactions streamed to your application is critical for some applications. This API intends to solve those needs by streaming this data in real-time.
Another important benefit of the ChainStream API is that it consolidates updates from mulitple validators ensuring that you will never miss a notification. This is especially important for applications that require high-availability and reliability.
The ChainStream API is available to all customers on the Scale Mode plan. Scale Mode comes with one ChainStream subscription and you can add up to nine (9) additional subscriptions for $0.14/hour each.
Anatomy of a ChainStream API Subscription Request
ChainStream API uses the JSON RPC 2.0 Spec which you can check out here. Beyond the standard specification, each notification subscription request requires the following params
:
1. network
The network you want to subscribe to. Currently, we support solana-mainnet
, solana-devnet
will be available soon.
2. verified
Whether or not you want to receive verified transactions. If you set this to true
, you will only receive transactions that have been verified by ChainStream to have come from multiple validators. Please note: setting this to true
will delay the notification by one slot due to the verification process.
Setting this param
to false
will report the notification as quickly as possible without waiting for multiple validators to report the same notification.
Anatomy of a ChainStream API Notification
Every ChainStream API notification will contain the following:
1. subscription
This is the subscription ID that you received when you subscribed to the notification. You will need this to unsubscribe from the notification.
2. result
This is the actual notification. The contents of this will vary depending on the notification type. See below for more details.
Supported Subscription Types
The ChainStream API allows you to subscribe to the following notifications:
Below we will cover how to subscribe to each notification type.
Transaction Notifications
Receive a notification anytime a transaction takes place on your specified network
.
Filters
With ChainStream transaction notifications, you can optionally filter transactions by the following criteria:
excludeVotes
- Exclude transactions that are votes from the stream. Default:false
accountKeys
- Filter transactions by account keys. Default:null
. Options include:all
- All the specified account keys must be present in the transactiononeOf
- At least one of the account keys must be present in the transactionexclude
- Exclude transactions that contain any of the specified account keys
For accountKeys
, if both all
and oneOf
are supplied, then ChainStream will report transactions that contain all keys in all
and at least one key in oneOf
. If exclude
is supplied, then ChainStream will exclude transactions that contain any of the keys in exclude
.
If no filters are supplied, you will receive all transactions at the processed commitment level.
Subscribe Request
{
"jsonrpc": "2.0",
"id": 123,
"method": "chainstream.transactionsSubscribe",
"params": {
"network": "solana-mainnet",
"verified": true,
"filter": {
"excludeVotes": false
}
}
}
{
"jsonrpc": "2.0",
"id": 123,
"method": "chainstream.transactionsSubscribe",
"params": {
"network": "solana-mainnet",
"verified": true,
"filter": {
"excludeVotes": false,
"accountKeys": {
"all": [
"vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg",
"4fYNw3dojWmQ4dXtSGE9epjRGy9pFSx62YypT7avPYvA"
],
"oneOf": [
"vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg",
"4fYNw3dojWmQ4dXtSGE9epjRGy9pFSx62YypT7avPYvA"
],
"exclude": ["BGsqMegLpV6n6Ve146sSX2dTjUMj3M92HnU8BbNRMhF2"]
}
}
}
}
Subscribe Response
If successful, you should receive a response like below:
Save the subscription ID from the response here, you will need this to unsubscribe in the future.
{
"jsonrpc": "2.0",
"result": 446257156701906,
"id": 123
}
Notification
Example of periodic (streaming) chainstream.transactionNotification
(s):
Note: The blockTime
will be null
for transactions whose slotStatus
is processed
. This is to be expected, as the block has not been confirmed by the cluster yet.
{
"jsonrpc": "2.0",
"method": "transactionNotification",
"params": {
"subscription": 3,
"result": {
"context": {
"index": 604,
"isVote": false,
"nodeTime": "2023-11-28T19:36:09.977998269Z",
"signature": "3EJbaJmbMgS1SiG6HcDJFXrMtmvxBgEJQah5MLZMxp23TafZkgybBEvULBS6LC1mJEYnv5J3UoQ3tFiPfPG5qF34",
"slotStatus": "processed"
},
"value": {
"blockTime": null,
"meta": {
"err": {
"InstructionError": [
1.0,
{
"Custom": 6036.0
}
]
},
"fee": 5000,
"innerInstructions": [],
"loadedAddresses": {
"readonly": [],
"writable": []
},
"logMessages": [
"Program ComputeBudget111111111111111111111111111111 invoke [1]",
"Program ComputeBudget111111111111111111111111111111 success",
"Program whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc invoke [1]",
"Program log: Instruction: Swap",
"Program log: fee_growth: 451160579113",
"Program log: AnchorError occurred. Error Code: AmountOutBelowMinimum. Error Number: 6036. Error Message: Amount out below minimum threshold.",
"Program whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc consumed 41335 of 65536 compute units",
"Program whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc failed: custom program error: 0x1794"
],
"postBalances": [
10250627025, 994435781, 6448790698383, 48051806330590, 2039280, 2039280, 70407360,
70407360, 70407360, 1, 1141440, 934087680, 0
],
"postTokenBalances": [
{
"accountIndex": 2,
"mint": "So11111111111111111111111111111111111111112",
"owner": "AK47XL44WVb1sFp6ehkUwMAmPDuSyTtnVv7RY6Ys2dSy",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"uiTokenAmount": {
"amount": "6448788659103",
"decimals": 9,
"uiAmount": 6448.788659103,
"uiAmountString": "6448.788659103"
}
},
{
"accountIndex": 3,
"mint": "So11111111111111111111111111111111111111112",
"owner": "7qbRF6YsyGuLUVs6Y1q64bdVrfe4ZcUUz1JRdoVNUJnm",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"uiTokenAmount": {
"amount": "48051804291310",
"decimals": 9,
"uiAmount": 48051.80429131,
"uiAmountString": "48051.80429131"
}
},
{
"accountIndex": 4,
"mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"owner": "AK47XL44WVb1sFp6ehkUwMAmPDuSyTtnVv7RY6Ys2dSy",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"uiTokenAmount": {
"amount": "12665588254",
"decimals": 6,
"uiAmount": 12665.588254,
"uiAmountString": "12665.588254"
}
},
{
"accountIndex": 5,
"mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"owner": "7qbRF6YsyGuLUVs6Y1q64bdVrfe4ZcUUz1JRdoVNUJnm",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"uiTokenAmount": {
"amount": "2653068643838",
"decimals": 6,
"uiAmount": 2653068.643838,
"uiAmountString": "2653068.643838"
}
}
],
"preBalances": [
10250632025, 994435781, 6448790698383, 48051806330590, 2039280, 2039280, 70407360,
70407360, 70407360, 1, 1141440, 934087680, 0
],
"preTokenBalances": [
{
"accountIndex": 2,
"mint": "So11111111111111111111111111111111111111112",
"owner": "AK47XL44WVb1sFp6ehkUwMAmPDuSyTtnVv7RY6Ys2dSy",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"uiTokenAmount": {
"amount": "6448788659103",
"decimals": 9,
"uiAmount": 6448.788659103,
"uiAmountString": "6448.788659103"
}
},
{
"accountIndex": 3,
"mint": "So11111111111111111111111111111111111111112",
"owner": "7qbRF6YsyGuLUVs6Y1q64bdVrfe4ZcUUz1JRdoVNUJnm",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"uiTokenAmount": {
"amount": "48051804291310",
"decimals": 9,
"uiAmount": 48051.80429131,
"uiAmountString": "48051.80429131"
}
},
{
"accountIndex": 4,
"mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"owner": "AK47XL44WVb1sFp6ehkUwMAmPDuSyTtnVv7RY6Ys2dSy",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"uiTokenAmount": {
"amount": "12665588254",
"decimals": 6,
"uiAmount": 12665.588254,
"uiAmountString": "12665.588254"
}
},
{
"accountIndex": 5,
"mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"owner": "7qbRF6YsyGuLUVs6Y1q64bdVrfe4ZcUUz1JRdoVNUJnm",
"programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"uiTokenAmount": {
"amount": "2653068643838",
"decimals": 6,
"uiAmount": 2653068.643838,
"uiAmountString": "2653068.643838"
}
}
],
"rewards": [],
"status": {
"Err": {
"InstructionError": [
1.0,
{
"Custom": 6036.0
}
]
}
}
},
"slot": 232812811,
"transaction": {
"message": {
"accountKeys": [
"AK47XL44WVb1sFp6ehkUwMAmPDuSyTtnVv7RY6Ys2dSy",
"7qbRF6YsyGuLUVs6Y1q64bdVrfe4ZcUUz1JRdoVNUJnm",
"F9EgG1oDJo8YyLc3ohEURvW6c5vPTsiHNDMBbYMKGdLB",
"9RfZwn2Prux6QesG1Noo4HzMEBv3rPndJ2bN2Wwd6a7p",
"8BuHWU9dXykNNS8cnVSbV1JY648UkGm6dfRbSfmE2grf",
"BVNo8ftg2LkkssnWT4ZWdtoFaevnfD6ExYeramwM27pe",
"Yb2axPXvJG3ouAQ4ZBUzSqmQjbgKDkhqQPsd9Mqq3jp",
"FLNNqPmeaSEdmq7xVVTTt5ErEVmpg4kcnRrffg9D6PQr",
"CrG3tbpzisatcBwVRfiuJJvWXUFewmxxYYKEh7L42nrd",
"ComputeBudget111111111111111111111111111111",
"whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc",
"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"6vK8gSiRHSnZzAa5JsvBF2ej1LrxpRX21Y185CzP4PeA"
],
"addressTableLookups": [],
"header": {
"numReadonlySignedAccounts": 0,
"numReadonlyUnsignedAccounts": 4,
"numRequiredSignatures": 1
},
"instructions": [
{
"accounts": [],
"data": "E64fMy",
"programIdIndex": 9
},
{
"accounts": [11, 0, 1, 2, 3, 4, 5, 6, 7, 8, 12],
"data": "59p8WydnSZtRpTLDVVek9vtNmpBYwynq1ukXnjA1cvWmHCquRh8cpXDZU4",
"programIdIndex": 10
}
],
"recentBlockhash": "D3eHsPe4Ecy9PwMdiNbXxTSRPMDXzibMLSXyDMRmEbdm"
},
"messageHash": "3gYBCTjxJ4oCLVJCfNRsJERDuqUtk8MVctQuJ8vCMN3F",
"signatures": [
"3EJbaJmbMgS1SiG6HcDJFXrMtmvxBgEJQah5MLZMxp23TafZkgybBEvULBS6LC1mJEYnv5J3UoQ3tFiPfPG5qF34"
]
}
}
}
}
}
Unsubscribe
Unsubscribe using subscription ID, which can be found in each notification from the stream:
{
"jsonrpc": "2.0",
"id": 123,
"method": "chainstream.transactionsUnsubscribe",
"params": {
"subscription": 446257156701906
}
}
Block Notifications
Receive a notification every time a new block is processed by a validator.
Subscription Request
{
"jsonrpc": "2.0",
"id": "123",
"method": "chainstream.blocksSubscribe",
"params": {}
}
Subscribe Response
If successful, you should receive a response like below:
Save the subscription ID from the response here, you will need this to unsubscribe in the future.
{
"jsonrpc": "2.0",
"result": 32026100100140,
"id": 123
}
notifications
Example of periodic (streaming) block notifications:
Result:
context
: this object contains contextual data related to the block notificationvalue
: a block notification. See example notification below for list of fields returned.
{
"jsonrpc": "2.0",
"method": "blockNotification",
"params": {
"subscription": 32026100100140,
"result": {
"context": {
"nodeTime": "2023-11-28T20:30:18.891246638Z"
},
"value": {
"slot": 232820203,
"blockhash": "4af1ziNjnJjAM4Wc5dbs5oLCfZSUX3et3SBpYamUVnqS",
"rewards": [
{
"pubkey": "",
"lamports": 25987280,
"postBalance": 1935203524,
"rewardType": 0,
"commission": null
}
],
"blockTime": "2023-11-28T20:30:18Z",
"blockHeight": 214481453,
"parentSlot": 232820202,
"parentBlockhash": "5Mg2RJQqdCibdWmwxYhrszJz4HrXu1Tq7B4xnJwEYnQN",
"executedTransactionCount": 1037
}
}
}
}
Unsubscribe
Unsubscribe using subscription ID, which can be found in each notification from the stream:
{
"jsonrpc": "2.0",
"id": 123,
"method": "chainstream.blocksUnsubscribe",
"params": {
"subscription": 446257156701906
}
}
Slot Notifications
Receive a notification anytime a slot is updated by a validator.
Subscription Request
{
"jsonrpc": "2.0",
"id": "123",
"method": "chainstream.slotUpdatesSubscribe",
"params": {
"network": "solana-mainnet",
"verified": true
}
}
Subscription Response
If successful, you should receive a response like below:
Save the subscription ID from the response here, you will need this to unsubscribe in the future.
{
"jsonrpc": "2.0",
"result": 6296444419224395,
"id": 123
}
Notification
Receive a notification anytime a slot is updated by the validator.
{
"jsonrpc": "2.0",
"method": "slotUpdateNotification",
"params": {
"subscription": 6296444419224395,
"result": {
"context": {
"nodeTime": "2023-11-28T20:47:23.363515459Z"
},
"value": {
"slot": 232822534,
"parent": 232822533,
"status": "processed"
}
}
}
}
Unsubscribe
Unsubscribe to slot updates using chainstream.slotUpdatesUnsubscribe
method:
{
"jsonrpc": "2.0",
"id": 123,
"method": "chainstream.slotUpdatesUnsubscribe",
"params": {
"subscription": 6296444419224395
}
}
Using the ChainStream APIs
Make sure you have access. To use the ChainStream API you'll need to be subscribed to our Scale Mode plan and enable ChainSteam in the platform.
Establish a WebSocket connection to the ChainStream API endpoint:
This endpoint is different than the Syndica Elastic Nodes endpoint available on the platform
wss://api.syndica.io/
Example of sending JSON RPC messages via WebSocket client in Node.JS
- JavaScript
const url = 'wss://api.syndica.io/'
const connection = new WebSocket(url)
const slotUpdatesSubscribeReq = {
jsonrpc: '2.0',
id: '123',
method: 'chainstream.slotUpdatesSubscribe',
params: {},
}
connection.onopen = () => {
connection.send(JSON.stringify(slotUpdatesSubscribeReq))
}
connection.onerror = (error) => {
console.log(`WebSocket error: ${error}`)
}
connection.onmessage = (e) => {
console.log(e.data)
// {
// "jsonrpc": "2.0",
// "method": "chainstream.slotUpdateNotification",
// "params": {
// "subscription": "09c63354-70b2-4e4b-8dcb-45c9a981d54f",
// "result": {
// "slot": 150867846,
// "parent": 150867845,
// "status": "processed" // or: "rooted", "confirmed"
// }
// }
// }
}