# CLI Source: https://docs.chainstream.io/en/docs/access-methods/cli The `chainstream` command-line interface — shell-native access to every data product, GraphQL and DeFi primitive. The ChainStream CLI is the command-line front door to the same [data products](/en/docs/data-products/overview) you'd hit via SDK, REST, GraphQL or WebSocket. It's designed to compose with `jq`, shell pipelines and AI agents that drive shells. ## Install ```bash theme={null} # Option A — global install (recommended for interactive use) npm install -g @chainstream-io/cli # Option B — zero-install, always-latest (recommended for agents and CI) npx @chainstream-io/cli ``` In the examples below, `chainstream ` is equivalent to `npx @chainstream-io/cli `. Pick whichever invocation style matches your environment. ## Authenticate The CLI has two authentication paths. Both grant access to the REST API, GraphQL and DeFi commands from the same config file. ```bash theme={null} # Create an on-host wallet and auto-grant the nano trial (50K CU, 30 days) chainstream login # …or set an existing API Key explicitly chainstream config set --key apiKey --value # Scripts can pass it via env var instead export CHAINSTREAM_API_KEY=... ``` Config lives in `~/.config/chainstream/config.json`; wallet keys live under `~/.config/chainstream/keys/`. `chainstream logout` clears the wallet config but keeps the key files on disk. ## Command groups | Group | Purpose | | --------- | ---------------------------------------------------------------------------------------------------- | | `token` | `search`, `info`, `security`, `holders`, `candles`, `pools` | | `market` | `trending`, `new`, `trades` | | `wallet` | `profile`, `pnl`, `holdings`, `activity`, `address`, `balance`, `pricing`, `sign`, `set-raw`, `link` | | `dex` | `route`, `swap`, `create` — build **unsigned** transactions for a host-managed wallet to sign | | `tx` | `send`, `gas-price`, `estimate-gas` | | `graphql` | `schema`, `query` — see below | | `plan` | `status`, `purchase` — uses x402 auto-pay, returns API Key | | `config` | `set`, `get`, `auth` | | `job` | `status` | | top-level | `login`, `logout`, `verify`, `bind-email`, `bind-email-verify` | Global flag: `--json` prints single-line machine-readable JSON (default output is pretty-printed JSON). ## First commands ```bash theme={null} chainstream token search --chain sol --keyword PUMP --limit 5 chainstream token security --chain sol --address chainstream market trending --chain sol --duration 1h --limit 20 chainstream wallet pnl --chain sol --address chainstream dex route --chain sol --from SOL --to USDC --amount 1 ``` ## GraphQL subcommand The `graphql` group exposes ChainStream's on-chain data warehouse (27 cubes across `Solana`, `EVM`, `Trading`) — useful when REST/MCP endpoints aren't flexible enough (cross-cube JOINs, custom aggregations, time-series, multi-condition filters). Default endpoint: `https://graphql.chainstream.io/graphql`. ### Discover the schema ```bash theme={null} chainstream graphql schema --summary # compact catalog of all 27 cubes chainstream graphql schema --type DEXTrades # drill into one cube's fields chainstream graphql schema --full # complete reference (best for agents) chainstream graphql schema --summary --refresh # bypass cache, re-fetch ``` ### Execute a query ```bash theme={null} # Inline query chainstream graphql query \ --query 'query { Solana { DEXTrades(limit:{count:5}) { Block { Time } } } }' \ --json # Query from file with variables chainstream graphql query --file ./query.graphql --var '{"chain":"sol"}' ``` Auth is automatic: if an API Key is set (`config set --key apiKey` or `CHAINSTREAM_API_KEY`), the CLI sends it via `X-API-KEY`; otherwise it signs a SIWX token from the on-host wallet. GraphQL shares the same API Key and subscription pool as the REST API — no separate purchase. On 402, `graphql query` returns a descriptive error. Run `chainstream plan status`, then `chainstream plan purchase` (which handles x402 auto-pay and saves the resulting API Key) and retry. ## When to use * Quick exploration ("what's happening right now?") * Scripts, cron jobs, GitHub Actions * Giving an AI agent shell-executable ChainStream primitives * Custom GraphQL analytics without writing any client code * Preparing unsigned DeFi transactions for a user-controlled wallet to sign ## Next Every command, flag and exit code. Endpoint, schema, query patterns. How AI agents should use `graphql schema` / `query`. How AI agents should use the CLI. # GraphQL Source: https://docs.chainstream.io/en/docs/access-methods/graphql Flexible, analytical queries that JOIN across data products in a single request. The GraphQL endpoint is the right choice when you want to **shape your response** — picking exactly the fields you need across multiple data products in one request. If REST is "look up this one thing", GraphQL is "answer this one analytical question." ## Endpoint ``` POST https://graphql.chainstream.io/graphql ``` Or use the [GraphQL IDE](https://graphql.chainstream.io) to explore interactively. ## Authentication Two equivalent paths — pick whichever fits your client: ```bash theme={null} # API Key (browser, server, most clients) -H "X-API-KEY: $CHAINSTREAM_API_KEY" -H "Content-Type: application/json" # SIWX wallet token (agents / on-host wallets) -H "Authorization: SIWX " -H "Content-Type: application/json" ``` GraphQL and REST share the same API Key and subscription quota — no separate purchase. ## First query ```graphql theme={null} query TopSolanaTokens { tokens(chain: SOLANA, orderBy: VOLUME_24H_DESC, limit: 5) { address symbol priceUsd marketCap recentTrades(limit: 3) { timestamp sizeUsd side } } } ``` One request returns tokens, metadata and their recent trades — no N+1 roundtrips. ## When to use * Analytical queries crossing multiple data products * Dashboards that need many fields without overfetching * Reporting / BI workloads * Server-side rendering where you pre-shape the response When **not** to: real-time streams (use WebSocket/Kafka) and hot-path reads where REST caching is cheaper. ## Invoke from CLI The [`chainstream` CLI](/en/docs/access-methods/cli) ships with `graphql schema` (for discovery) and `graphql query` (for execution) — no need to wire up a client library for quick checks or shell automation: ```bash theme={null} # Discover the 27 cubes chainstream graphql schema --summary chainstream graphql schema --type DEXTrades # Run a query from a file chainstream graphql query --file ./query.graphql --json ``` ## Schema Types, relationships and conventions. Complete first-query walkthrough. ## Next Explore the schema and run queries interactively. Structured Agent Skill for GraphQL workflows. `chainstream graphql schema` and `query` reference. Typed GraphQL wrappers via codegen. # EVM Streams Source: https://docs.chainstream.io/en/docs/access-methods/kafka-streams/evm-streams Protobuf data streams for Ethereum, BSC, Base, Polygon, Optimism and other EVM chains EVM chains have different block intervals depending on the network (Ethereum mainnet \~12 seconds/block), supporting Ethereum, BSC, Base, Polygon (Matic), Optimism and other networks, sharing a unified Protobuf Schema. **Schema Repository**: [github.com/chainstream-io/streaming\_protobuf/evm](https://github.com/chainstream-io/streaming_protobuf/tree/main/evm) *** ## Message Types Overview EVM Streams provides the following message types: | Message Type | Description | Topic | | :---------------- | :-------------------- | :--------------------------- | | TradeEvents | DEX trade events | `{chain}.dex.trades` | | TokenEvents | Token events | `{chain}.tokens` | | BalanceEvents | Balance change events | `{chain}.balances` | | DexPoolEvents | Liquidity pool events | `{chain}.dex.pools` | | TransfersMessage | Transfer messages | `{chain}.v1.transfers.proto` | | CandlestickEvents | Candlestick data | `{chain}.candlesticks` | *** ## Block-Level Data Each block contains `BlockHeader` with core fields: | Field | Type | Description | | :-------------- | :-------- | :-------------------- | | `Number` | uint64 | Block number | | `Hash` | bytes | Block hash | | `ParentHash` | bytes | Parent block hash | | `Timestamp` | Timestamp | Block time | | `BaseFeePerGas` | uint64 | EIP-1559 base fee | | `GasUsed` | uint64 | Block gas consumption | | `GasLimit` | uint64 | Block gas limit | `BlockMessage` also contains: | Field | Description | | :------------- | :-------------------------------------------- | | `Transactions` | All transactions in the block | | `Withdrawals` | Validator withdrawals (post-Shanghai upgrade) | | `BlobGasUsed` | Blob gas consumption (EIP-4844) | *** ## Transaction-Level Data ### TransactionHeader — Core Transaction Metadata | Field | Type | Description | | :------ | :----- | :----------------------- | | `Hash` | bytes | Transaction hash | | `Index` | uint32 | Index within block | | `From` | bytes | Sender address | | `To` | bytes | Recipient address | | `Value` | BigInt | Transfer amount (wei) | | `Nonce` | uint64 | Sender nonce | | `Type` | uint32 | Transaction type (0/1/2) | ### ReceiptHeader — Execution Result | Field | Description | | :------------------ | :-------------------------------------- | | `Status` | Execution status (1=success, 0=failure) | | `GasUsed` | Actual gas consumption | | `CumulativeGasUsed` | Cumulative gas consumption | | `ContractAddress` | Created contract address (if any) | ### TransactionFee — Fee Details | Field | Description | | :------------ | :----------------------- | | `SenderFee` | Total fee paid by sender | | `MinerReward` | Miner/validator reward | | `Burnt` | EIP-1559 burnt portion | | `Savings` | Saved gas fees | ### Calls — Internal Call Traces Contains all nested contract calls, each call includes: * `From`, `To`: Caller and callee * `Input`, `Output`: Input and output data * `GasUsed`: Gas consumption * `Opcode`: Operation code (CALL/DELEGATECALL/STATICCALL) * `Signature`: Function signature * `Logs`: Event logs * `StateChanges`: State changes * `ReturnValues`: Return values ### Balance Updates ERC-20/721/1155 Token balance changes: | Field | Description | | :------------ | :-------------------------------------------------------- | | `Token` | Token info (address, fungibility, decimals, total supply) | | `Wallet` | Wallet address | | `PostBalance` | Balance after transaction | Native currency (e.g., ETH) balance changes: | Field | Description | | :------------ | :------------------------- | | `Address` | Address | | `PreBalance` | Balance before transaction | | `PostBalance` | Balance after transaction | | `ReasonCode` | Change reason code | *** ## Transfer Data `TransfersMessage` provides EVM chain transfer information (Topic: `{chain}.v1.transfers.proto`). ### TransfersMessage Structure ```protobuf theme={null} message TransfersMessage { Chain Chain = 1; BlockHeader Header = 2; repeated Transfer Transfers = 5; optional BlockHeader L1Header = 6; // Included for L2 chains } ``` ### Transfer Structure | Field | Type | Description | | :------------------ | :---------------- | :----------------- | | `CallIndex` | uint64 | Call index | | `LogIndex` | uint64 | Log index | | `Sender` | string | Sender address | | `Receiver` | string | Receiver address | | `Amount` | string | Transfer amount | | `Id` | string | Token ID (NFT) | | `URI` | string | Token URI | | `Currency` | TokenInfo | Token information | | `Success` | bool | Success status | | `Index` | uint32 | Transfer index | | `TransactionHeader` | TransactionHeader | Transaction header | ### TokenInfo Structure | Field | Type | Description | | :-------------- | :----- | :----------------- | | `SmartContract` | string | Contract address | | `Delegated` | bool | Is delegated | | `DelegatedTo` | string | Delegation address | | `ProtocolName` | string | Protocol name | | `Name` | string | Token name | | `Symbol` | string | Token symbol | | `Decimals` | int32 | Decimals | | `HasURI` | bool | Has URI | | `Fungible` | bool | Is fungible | | `AssetId` | string | Asset ID | ### Supported Token Standards | Standard | Description | | :------- | :------------------------ | | ERC-20 | Fungible tokens | | ERC-721 | Non-fungible tokens (NFT) | | ERC-1155 | Multi-asset tokens | *** ## DEX Data `TradeEvents` provides DEX trade data (Topic: `{chain}.dex.trades`). ### TradeEvent Structure ```protobuf theme={null} message TradeEvent { Instruction instruction = 1; Block block = 2; Transaction transaction = 3; DApp d_app = 4; Trade trade = 100; BondingCurve bonding_curve = 110; TradeProcessed trade_processed = 200; // included in processed topic } ``` ### Trade Core Fields | Field | Description | | :------------------------------------------- | :--------------------------- | | `token_a_address` / `token_b_address` | Trading pair token addresses | | `token_a_decimals` / `token_b_decimals` | Token decimals | | `user_a_amount` / `user_b_amount` | User trade amounts | | `user_a_pre_amount` / `user_a_post_amount` | User balance before/after | | `pool_address` | Pool address | | `vault_a` / `vault_b` | Pool vault addresses | | `vault_a_amount` / `vault_b_amount` | Vault amounts | | `vault_a_pre_amount` / `vault_a_post_amount` | Vault balance before/after | | `was_original_direction` | Is original direction | | `pool_config_address` | Pool config address | ### TradeProcessed Enhanced Fields `.processed` topic includes additional fields: | Field | Description | | :---------------------------------------------------- | :------------------------------------------------------- | | `token_a_price_in_usd` / `token_b_price_in_usd` | USD price | | `token_a_price_in_native` / `token_b_price_in_native` | Native currency price | | `is_token_a_price_in_usd_suspect` | Is price suspicious | | `is_token_a_price_in_usd_suspect_reason` | Suspicious reason (e.g., price volatility, small amount) | ### DexPoolEvent - Liquidity Pools `DexPoolEvents` provides liquidity pool events (Topic: `{chain}.dex.pools`). | Field | Description | | :------------------------------------------------ | :------------------------------------------------------------------- | | `type` | Event type (INITIALIZE/INCREASE\_LIQUIDITY/DECREASE\_LIQUIDITY/SWAP) | | `address` | Pool address | | `token_a_address` / `token_b_address` | Token addresses | | `token_a_vault_address` / `token_b_vault_address` | Vault addresses | | `token_a_amount` / `token_b_amount` | Token amounts | | `lp_wallet` | LP wallet address | *** ## EVM Chain Characteristics ### Gas & EIP-1559 Fee Model EVM uses Gas mechanism to measure computational resources. EIP-1559 introduced dynamic BaseFee adjustment and fee burning, transaction fees split into: * **Validator reward**: `MinerReward` * **Burnt portion**: `Burnt` ### Layer 2 Support EVM Streams provides dedicated fields for L2 chains: | Field | Description | Applicable Chains | | :--------------- | :--------------------------------- | :---------------- | | `L1Header` | Corresponding L1 block information | All L2 | | `SequenceNumber` | Sequence number | Optimism | | `BatcherAddr` | Batcher address | Optimism | | `L1FeeOverhead` | L1 fee overhead | Optimism | | `GasL1` | L1 data cost | Arbitrum | *** ## Topic → Message Type Mapping | Topic | Proto File | Message Type | Description | | :----------------------------- | :----------------------- | :---------------- | :------------------------------------ | | `{chain}.dex.trades` | trade\_event.proto | TradeEvents | DEX trade events | | `{chain}.dex.trades.processed` | trade\_event.proto | TradeEvents | With USD price, suspicious flag | | `{chain}.tokens` | token\_event.proto | TokenEvents | Token events | | `{chain}.tokens.processed` | token\_event.proto | TokenEvents | With description, image, social links | | `{chain}.balances` | balance\_event.proto | BalanceEvents | Balance change events | | `{chain}.balances.processed` | balance\_event.proto | BalanceEvents | With USD value | | `{chain}.dex.pools` | dex\_pool\_event.proto | DexPoolEvents | Liquidity pool events | | `{chain}.v1.transfers.proto` | transfers\_message.proto | TransfersMessage | EVM transfer messages | | `{chain}.candlesticks` | candlestick.proto | CandlestickEvents | Candlestick data | Replace `{chain}` with `eth` or `bsc`. E.g., `eth.dex.trades`, `bsc.tokens.processed`. *** ## Code Examples ### Python Example: Consume DEX Trade Data ```python theme={null} from kafka import KafkaConsumer from common import trade_event_pb2 # Get from streaming_protobuf repository # Create consumer consumer = KafkaConsumer( 'eth.dex.trades', bootstrap_servers=[''], security_protocol='SASL_SSL', sasl_mechanism='SCRAM-SHA-512', sasl_plain_username='your_username', sasl_plain_password='your_password', auto_offset_reset='latest', enable_auto_commit=False, group_id='my-dex-consumer' ) # Consume and parse messages for message in consumer: # Parse protobuf message trade_events = trade_event_pb2.TradeEvents() trade_events.ParseFromString(message.value) # Iterate DEX trades for event in trade_events.events: print(f"Pool: {event.trade.pool_address}") print(f"Token A: {event.trade.token_a_address}") print(f"Token B: {event.trade.token_b_address}") print(f"Amount A: {event.trade.user_a_amount}") print(f"Amount B: {event.trade.user_b_amount}") print(f"Block: {event.block.height}, Tx: {event.transaction.signature}") print("---") ``` ### JavaScript Example ```javascript theme={null} const { Kafka } = require('kafkajs'); const protobuf = require('protobufjs'); const kafka = new Kafka({ clientId: 'my-app', brokers: [''], ssl: true, sasl: { mechanism: 'scram-sha-512', username: 'your_username', password: 'your_password' } }); const consumer = kafka.consumer({ groupId: 'my-dex-consumer' }); async function run() { // Load protobuf definitions const root = await protobuf.load('common/trade_event.proto'); const TradeEvents = root.lookupType('io.chainstream.v1.dex.trade.TradeEvents'); await consumer.connect(); await consumer.subscribe({ topic: 'eth.dex.trades', fromBeginning: false }); await consumer.run({ eachMessage: async ({ message }) => { const tradeEvents = TradeEvents.decode(message.value); tradeEvents.events.forEach(event => { console.log(`Pool: ${event.trade.poolAddress}`); console.log(`Token A: ${event.trade.tokenAAddress}`); console.log(`Token B: ${event.trade.tokenBAddress}`); console.log(`Amount A: ${event.trade.userAAmount}`); console.log(`Amount B: ${event.trade.userBAmount}`); console.log(`Block: ${event.block.height}`); }); } }); } run().catch(console.error); ``` *** ## Related Documentation Kafka Streams integration basics Solana high-throughput data streams TRON network data streams WebSocket integration # Concepts & Integration Guide Source: https://docs.chainstream.io/en/docs/access-methods/kafka-streams/overview ChainStream Kafka Streams multi-chain real-time data stream integration guide ChainStream provides multi-chain real-time on-chain data streams through Kafka Streams. Compared to GraphQL Subscriptions and WebSocket, Kafka Streams is designed for latency-sensitive, high-reliability server-side application scenarios, offering lower latency and stronger fault tolerance for data consumption. Official ChainStream Protobuf Schema definitions, supporting Go and Python, including all message types for EVM, Solana, and TRON. *** ## Support Matrix | Chain | dex.trades | tokens | balances | dex.pools | transfers | candlesticks | | :------------- | :--------: | :----: | :------: | :-------: | :-------: | :----------: | | Ethereum (eth) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | BSC (bsc) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | Solana (sol) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | TRON (tron) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | All chains also support `token-supplies`, `token-prices`, `token-holdings`, `token-market-caps`, `trade-stats` Topics. See full Topic list for details. *** ## Kafka Streams vs WebSocket Selection Guide ### When to Choose Kafka Streams Latency is the primary concern, application deployed on cloud or dedicated servers Cannot accept losing any messages, requires durable and reliable data consumption Need to perform complex computation, filtering, or formatting beyond pre-processing capabilities Need multi-instance horizontal scaling for consumption capacity ### When to Choose WebSocket Building prototypes, development speed is the primary factor Application needs both historical and real-time data with unified query and subscription interface Application consumes data directly in browser (Kafka Streams only supports server-side) Need to dynamically filter data based on page content ### Comparison Summary | Feature | Kafka Streams | WebSocket | | :--------------------- | :-------------------------: | :------------------------: | | Latency | Lowest | Low | | Reliability | Persistent, no message loss | May lose on disconnect | | Scalability | Native horizontal scaling | Requires additional design | | Data Filtering | Client-side processing | Server-side pre-filtering | | Client Support | Server-side only | Server + Browser | | Integration Complexity | Higher | Lower | *** ## Credential Acquisition Kafka Streams uses independent authentication credentials and requires contacting the ChainStream team to apply for access. Send an email to [support@chainstream.io](mailto:support@chainstream.io) to apply for Kafka Streams access After approval, you will receive the following credential information: * Username * Password * Broker address list Configure your Kafka client connection using the received credentials *** ## Connection Configuration ### Broker Address The Broker address will be provided along with your credentials after your application is approved. Do not use any unauthorized addresses for connection. ### SASL\_SSL Connection Configuration ```python theme={null} from kafka import KafkaConsumer consumer = KafkaConsumer( 'eth.dex.trades', bootstrap_servers=[''], security_protocol='SASL_SSL', sasl_mechanism='SCRAM-SHA-512', sasl_plain_username='your_username', sasl_plain_password='your_password', auto_offset_reset='latest', enable_auto_commit=False, group_id='your_group_id' ) ``` ```javascript theme={null} const { Kafka } = require('kafkajs'); const kafka = new Kafka({ clientId: 'my-app', brokers: [''], ssl: true, sasl: { mechanism: 'scram-sha-512', username: 'your_username', password: 'your_password' } }); const consumer = kafka.consumer({ groupId: 'your_group_id' }); ``` ```go theme={null} package main import ( "github.com/segmentio/kafka-go" "github.com/segmentio/kafka-go/sasl/scram" ) func main() { mechanism, _ := scram.Mechanism(scram.SHA512, "your_username", "your_password") reader := kafka.NewReader(kafka.ReaderConfig{ Brokers: []string{""}, Topic: "eth.dex.trades", GroupID: "your_group_id", Dialer: &kafka.Dialer{ SASLMechanism: mechanism, TLS: &tls.Config{}, }, }) } ``` *** ## Topic Naming Convention & Complete List ### Naming Convention Topics follow this naming pattern: ``` {chain}.{message_type} # Raw event data {chain}.{message_type}.processed # Processed data (with price, flags, enrichments) {chain}.{message_type}.created # Creation events (e.g., token creation) ``` Where `{chain}` includes: `sol`, `bsc`, `eth`, `tron` ### Message Types | Type | Description | | :------------------ | :---------------------- | | `dex.trades` | DEX trade events | | `dex.pools` | Liquidity pool events | | `tokens` | Token events | | `balances` | Balance change events | | `transfers` | Transfer events | | `token-supplies` | Token supply events | | `token-prices` | Token price events | | `token-holdings` | Token holding data | | `token-market-caps` | Token market cap events | | `candlesticks` | OHLCV candlestick data | | `trade-stats` | Trade statistics | ### Complete Topic List The following Topics apply to all supported chains (replace `{chain}` with `sol`, `bsc`, `eth`): ``` # DEX Trades {chain}.dex.trades {chain}.dex.trades.processed # Includes USD/native price, suspicious flag # Token Events {chain}.tokens {chain}.tokens.created # Token creation events {chain}.tokens.processed # Includes description, image URL, social links # Balance Changes {chain}.balances {chain}.balances.processed # Includes USD/native value # Liquidity Pools {chain}.dex.pools {chain}.dex.pools.processed # Includes liquidity USD/native value # Token Data {chain}.token-supplies {chain}.token-supplies.processed {chain}.token-prices {chain}.token-holdings {chain}.token-market-caps.processed # Aggregated Data {chain}.candlesticks # OHLCV candlestick data {chain}.trade-stats # Trade statistics ``` ``` # Transfer Events sol.transfers sol.transfers.processed # Includes USD/native value ``` ``` # Transfer Messages (BSC / ETH) {chain}.v1.transfers.proto {chain}.v1.transfers.processed.proto ``` ``` # Transfer Messages tron.v1.transfers.proto tron.v1.transfers.processed.proto ``` For complete Protobuf Schema and Topic mappings, refer to the [streaming\_protobuf repository](https://github.com/chainstream-io/streaming_protobuf). *** ## Consumption Modes & Offset Management Two core configurations to consider when subscribing to topics: ### Offset Strategy Selection Consumers need to decide where to start reading messages after connecting to Kafka. Two common strategies: Start from the current latest position on each connection, suitable for scenarios only caring about real-time data. No historical message replay on reconnection. ```javascript theme={null} { autoCommit: false, fromBeginning: false, 'auto.offset.reset': 'latest' } ``` Auto-commit offset, continue from last consumed position on reconnection, ensuring no message loss. ```javascript theme={null} { autoCommit: true, fromBeginning: false, 'auto.offset.reset': 'latest' } ``` If service restarts, it will continue reading from the last recorded offset. Messages during restart may cause backlog after recovery. ### Group ID Rules Deploying multiple instances with the same Group ID enables failover and load balancing—messages from the same topic will only be consumed by one instance in the Group, with Kafka automatically distributing partitions among instances. It's recommended to have an independent consumer for each topic, as different topics have different message parsing logic. *** ## Quick Start: First Consumer in 5 Minutes The following example shows how to consume the `eth.dex.trades` topic and parse DEX trade data. Clone the Schema definitions from the official repository: ```bash theme={null} git clone https://github.com/chainstream-io/streaming_protobuf.git ``` Or add as a Git submodule to your project: ```bash theme={null} git submodule add https://github.com/chainstream-io/streaming_protobuf.git ``` ```bash theme={null} pip install kafka-python protobuf ``` ```python theme={null} from kafka import KafkaConsumer from common import trade_event_pb2 # Get from streaming_protobuf repository # Create consumer consumer = KafkaConsumer( 'eth.dex.trades', bootstrap_servers=[''], security_protocol='SASL_SSL', sasl_mechanism='SCRAM-SHA-512', sasl_plain_username='your_username', sasl_plain_password='your_password', auto_offset_reset='latest', enable_auto_commit=False, group_id='my-dex-consumer' ) # Consume messages for message in consumer: # Parse protobuf message trade_events = trade_event_pb2.TradeEvents() trade_events.ParseFromString(message.value) # Print DEX trade info for event in trade_events.events: print(f"Pool: {event.trade.pool_address}") print(f"Token A: {event.trade.token_a_address}") print(f"Token B: {event.trade.token_b_address}") print(f"Amount A: {event.trade.user_a_amount}") print(f"Amount B: {event.trade.user_b_amount}") print(f"Block: {event.block.height}") print("---") ``` *** ## Core Data Structures All message types share these base structures (defined in `common/common.proto`): ### Base Structures Block information: | Field | Type | Description | | :---------- | :----- | :------------------- | | `timestamp` | int64 | Block timestamp | | `hash` | string | Block hash | | `height` | uint64 | Block height | | `slot` | uint64 | Slot number (Solana) | Transaction information: | Field | Type | Description | | :---------- | :------------------- | :-------------------------------- | | `fee` | uint64 | Transaction fee | | `fee_payer` | string | Fee payer | | `index` | uint32 | Index within block | | `signature` | string | Transaction signature | | `signer` | string | Signer address | | `status` | Status | Execution status (SUCCESS/FAILED) | | `bundles` | \[]BundleTransaction | Bundle info (MEV detection) | Instruction information: | Field | Type | Description | | :------------------------ | :----- | :---------------------- | | `index` | uint32 | Instruction index | | `is_inner_instruction` | bool | Is inner instruction | | `inner_instruction_index` | uint32 | Inner instruction index | | `type` | string | Instruction type | DApp information: | Field | Type | Description | | :---------------------- | :----- | :-------------------- | | `program_address` | string | Program address | | `inner_program_address` | string | Inner program address | | `chain` | Chain | Chain identifier | ### Main Message Types **Topic**: `{chain}.dex.trades` ```protobuf theme={null} message TradeEvent { Instruction instruction = 1; Block block = 2; Transaction transaction = 3; DApp d_app = 4; Trade trade = 100; BondingCurve bonding_curve = 110; TradeProcessed trade_processed = 200; // included in processed topic } ``` **Trade Core Fields**: | Field | Description | | :------------------------------------ | :--------------------------- | | `token_a_address` / `token_b_address` | Trading pair token addresses | | `user_a_amount` / `user_b_amount` | User trade amounts | | `pool_address` | Pool address | | `vault_a` / `vault_b` | Pool vault addresses | | `vault_a_amount` / `vault_b_amount` | Vault amounts | **TradeProcessed Enhanced Fields** (processed topic): | Field | Description | | :---------------------------------------------------- | :-------------------- | | `token_a_price_in_usd` / `token_b_price_in_usd` | USD price | | `token_a_price_in_native` / `token_b_price_in_native` | Native currency price | | `is_token_a_price_in_usd_suspect` | Is price suspicious | | `is_token_a_price_in_usd_suspect_reason` | Suspicious reason | **Topic**: `{chain}.tokens`, `{chain}.tokens.created` ```protobuf theme={null} message TokenEvent { Instruction instruction = 1; Block block = 2; Transaction transaction = 3; DApp d_app = 4; EventType type = 100; // CREATED, UPDATED Token token = 101; TokenProcessed token_processed = 200; } ``` **Token Core Fields**: | Field | Description | | :----------------- | :------------------------------------ | | `address` | Token address | | `name` / `symbol` | Name and symbol | | `decimals` | Decimals | | `uri` | Metadata URI | | `metadata_address` | Metadata address | | `creators` | Creator list | | `solana_extra` | Solana-specific fields | | `evm_extra` | EVM-specific fields (token\_standard) | **Topic**: `{chain}.balances` ```protobuf theme={null} message BalanceEvent { Instruction instruction = 1; Block block = 2; Transaction transaction = 3; DApp d_app = 4; Balance balance = 100; BalanceProcessed balance_processed = 200; } ``` **Balance Core Fields**: | Field | Description | | :--------------------------- | :-------------------------------------- | | `token_account_address` | Token account address | | `account_owner_address` | Account owner address | | `token_address` | Token address | | `pre_amount` / `post_amount` | Balance before/after | | `decimals` | Decimals | | `lifecycle` | Account lifecycle (NEW/EXISTING/CLOSED) | **Topic**: `{chain}.dex.pools` ```protobuf theme={null} message DexPoolEvent { Instruction instruction = 1; Block block = 2; Transaction transaction = 3; DApp d_app = 4; DexPoolEventType type = 100; // INITIALIZE, INCREASE_LIQUIDITY, DECREASE_LIQUIDITY, SWAP DexPool pool = 101; DexPoolProcessed pool_processed = 200; } ``` **DexPool Core Fields**: | Field | Description | | :------------------------------------------------ | :---------------- | | `address` | Pool address | | `token_a_address` / `token_b_address` | Token addresses | | `token_a_vault_address` / `token_b_vault_address` | Vault addresses | | `token_a_amount` / `token_b_amount` | Token amounts | | `lp_wallet` | LP wallet address | **Topic**: `{chain}.candlesticks` | Field | Description | | :------------------------------------------------------------------------ | :------------------------------------------------- | | `token_address` | Token address | | `resolution` | Time resolution (1m, 5m, 15m, 1h, etc.) | | `timestamp` | Timestamp | | `open` / `high` / `low` / `close` | OHLC prices (USD) | | `open_in_native` / `high_in_native` / `low_in_native` / `close_in_native` | OHLC prices (native) | | `volume` / `volume_in_usd` / `volume_in_native` | Volume | | `trades` | Trade count | | `dimension` | Dimension type (TOKEN\_ADDRESS/POOL\_ADDRESS/PAIR) | **Topic**: `{chain}.trade-stats` | Field | Description | | :----------------------------------------- | :----------------- | | `token_address` | Token address | | `resolution` | Time resolution | | `buys` / `sells` | Buy/sell count | | `buyers` / `sellers` | Buyer/seller count | | `buy_volume` / `sell_volume` | Buy/sell volume | | `buy_volume_in_usd` / `sell_volume_in_usd` | USD volume | | `high_in_usd` / `low_in_usd` | High/low price | **Topic**: `{chain}.token-holdings` | Field Group | Description | | :------------------------------------------------------ | :-------------------------- | | `top10_holders` / `top10_amount` / `top10_ratio` | Top 10 holders stats | | `top50_holders` / `top50_amount` / `top50_ratio` | Top 50 holders stats | | `top100_holders` / `top100_amount` / `top100_ratio` | Top 100 holders stats | | `holders` | Total holders count | | `creators_count` / `creators_amount` / `creators_ratio` | Creators holding stats | | `fresh_count` / `fresh_amount` / `fresh_ratio` | Fresh wallets holding stats | | `smart_count` / `smart_amount` / `smart_ratio` | Smart Money holding stats | | `sniper_count` / `sniper_amount` / `sniper_ratio` | Sniper holding stats | | `insider_count` / `insider_amount` / `insider_ratio` | Insider holding stats | **Topic**: `{chain}.token-prices` | Field | Description | | :---------------- | :-------------------- | | `token_address` | Token address | | `price_in_usd` | USD price | | `price_in_native` | Native currency price | **Topic**: `{chain}.token-supplies` | Field | Description | | :--------------------- | :-------------------------------------- | | `type` | Event type (INITIALIZE\_MINT/MINT/BURN) | | `token_address` | Token address | | `amount` | Amount | | `decimals` | Decimals | | `amount_with_decimals` | Amount with decimals | For complete Protobuf definitions, refer to the [streaming\_protobuf repository](https://github.com/chainstream-io/streaming_protobuf). *** ## Message Characteristics & Considerations Developers need to be aware of the following message characteristics when consuming Kafka Streams: Stream does not pre-filter, containing all messages and complete data within the topic. This means consumers need sufficient network throughput, server performance, and efficient parsing code. **Messages for the same token or same account arrive strictly in block order**. This means the event stream for a specific token or wallet address is ordered, making it easy to track state changes. However, message arrival order between different tokens/accounts is not guaranteed. The same message may be delivered multiple times. If duplicate processing causes issues, consumers need to maintain cache or storage for idempotent processing. ChainStream guarantees the integrity of each message. Messages will not be split. Regardless of how many transactions a block contains, the message you receive is a complete data unit. Messages use Protobuf encoding, more compact than JSON. Consumers need to use the corresponding language's Protobuf library for parsing. *** ## Latency Model Kafka Streams latency depends on the processing stages data passes through in the pipeline. Different topics from the same chain have different latencies: ```mermaid theme={null} flowchart TD A[Blockchain Node] --> B[Raw Data Collection] B --> C[Data Parsing] C --> D[Structured Processing] D --> E[Enrichment] E --> F[Kafka Topic] F --> G[Consumer] style A fill:#e1f5fe style F fill:#c8e6c9 style G fill:#fff3e0 ``` ### Broadcasted vs Committed | Type | Description | Latency | Data Certainty | | :---------- | :----------------------------------------------------------------------- | :-----: | :------------: | | Broadcasted | Transactions consumable at broadcast stage, no block confirmation needed | Lowest | Lower | | Committed | Transactions enter stream only after block confirmation | Higher | Highest | ### Pipeline Latency Each transformation layer from blockchain node to Kafka topic (parsing, structuring, enrichment) introduces approximately 100-1000ms latency: * **raw topic**: Lowest latency, closest to raw node data * **transactions topic**: Parsed and structured * **dextrades topic**: Relatively higher latency, but richer data If latency is your primary concern, prefer topics closest to raw data that you can effectively parse. *** ## Best Practices ### Parallel Partition Consumption Kafka topics are divided into multiple partitions, each partition needs parallel reading to maximize throughput. Message partition keys are set to **token address** or **wallet address** (unified across all chains), ensuring: * All events for the same token route to the same partition, guaranteeing order * All balance changes for the same wallet route to the same partition, facilitating state tracking Recommend allocating an independent thread for each partition for load balancing. ### Continuous Consumption, Don't Block Main Loop Consumer's read loop should run continuously, avoiding backlog from message processing blocking. If messages need processing, adopt async processing mode: main loop handles reading, processing logic delegated to worker threads. ### Message Processing Efficiency Batch processing can reduce overhead, but requires balancing batch size and latency. In Go, use channel + worker group for concurrent processing. *** ## Chain-Specific Documentation Ethereum, BSC, Base, Polygon, Optimism Solana high-throughput data streams TRON network data streams *** ## Related Documentation WebSocket real-time data integration guide Get Access Token # Solana Streams Source: https://docs.chainstream.io/en/docs/access-methods/kafka-streams/solana-streams Protobuf data streams for Solana high-throughput blockchain Solana targets 400ms block time, with actual throughput of \~4,000 TPS and theoretical peak of 65,000 TPS. The extremely high message volume places high demands on consumer processing capacity. **Schema Repository**: [github.com/chainstream-io/streaming\_protobuf/solana](https://github.com/chainstream-io/streaming_protobuf/tree/main/solana) *** ## Message Types Overview Solana Streams provides the following message types: | Message Type | Description | Topic | | :---------------- | :-------------------- | :----------------- | | TradeEvents | DEX trade events | `sol.dex.trades` | | TokenEvents | Token events | `sol.tokens` | | BalanceEvents | Balance change events | `sol.balances` | | DexPoolEvents | Liquidity pool events | `sol.dex.pools` | | TransferEvents | Transfer events | `sol.transfers` | | CandlestickEvents | Candlestick data | `sol.candlesticks` | *** ## Block-Level Data Solana uses Slot rather than traditional block number as the timeline identifier. | Field | Type | Description | | :------------ | :-------- | :------------------------------- | | `Slot` | uint64 | Slot number (primary identifier) | | `BlockHeight` | uint64 | Block height | | `BlockHash` | bytes | Block hash | | `ParentSlot` | uint64 | Parent slot | | `Timestamp` | Timestamp | Block time | In Solana's shred stream, Block Header may be incomplete, only the **Slot** field is guaranteed correct. *** ## Transaction-Level Data ### Core Transaction Fields | Field | Type | Description | | :---------- | :---------------- | :---------------------------------------- | | `Signature` | bytes | Transaction signature (unique identifier) | | `Status` | Status | Execution status | | `Header` | TransactionHeader | Metadata (including fees and signers) | | `Index` | uint32 | Position within block | ### Instructions Transactions contain multiple Instructions, which is the core of Solana's execution model: | Field | Description | | :-------------------- | :--------------------------------------------- | | `ProgramAccountIndex` | Called program | | `Data` | Encoded instruction data | | `AccountIndexes` | Referenced accounts | | `BalanceUpdates` | SOL balance changes caused by this instruction | A Solana transaction can contain multiple Instructions, each calling different programs. *** ## Transfer Data `TransferEvents` provides Solana transfer information (Topic: `sol.transfers`). ### TransferEvent Structure ```protobuf theme={null} message TransferEvent { Instruction instruction = 1; Block block = 2; Transaction transaction = 3; DApp d_app = 4; Transfer transfer = 100; TransferProcessed transfer_processed = 200; // included in processed topic } ``` ### Transfer Core Fields | Field | Type | Description | | :------------------------------- | :----- | :----------------------------- | | `sender_token_account_address` | string | Sender token account address | | `sender_account_owner_address` | string | Sender account owner address | | `receiver_token_account_address` | string | Receiver token account address | | `receiver_account_owner_address` | string | Receiver account owner address | | `token_address` | string | Token address (Mint) | | `token_amount` | string | Transfer amount | ### Token Metadata (TokenEvent) Token events use common `TokenEvents` (Topic: `sol.tokens`), containing: | Field | Description | | :----------------- | :--------------------------------------------- | | `address` | Token address | | `name` / `symbol` | Name and symbol | | `decimals` | Decimals | | `uri` | Metadata URI | | `metadata_address` | Metadata address | | `creators` | Creator list (address, verified status, share) | ### SolanaExtra Specific Fields Solana tokens include additional metadata fields: | Field | Description | | :--------------------------------------------------------- | :--------------------------------- | | `collection_address` | Collection address (NFT) | | `fungible` | Is fungible | | `is_mutable` | Is mutable | | `is_native` | Is native SOL | | `program_address` | Program address | | `seller_fee_basis_points` | Creator royalty basis points (NFT) | | `token_standard` | Token standard | | `mint_authority` / `freeze_authority` / `update_authority` | Authority accounts | | `is_verified_collection` | Is verified collection | ### Balance Updates Layered Mechanism (Solana-specific) This is an important characteristic of Solana stream data, balance updates are provided at two levels: Immediate balance changes after each instruction execution, reflecting the direct impact of single-step operations. ``` Transaction └── Instruction 1 └── BalanceUpdate: +100 SOL └── Instruction 2 └── BalanceUpdate: -50 SOL └── Instruction 3 └── BalanceUpdate: +25 SOL ``` Final balance state after all instructions in a transaction complete. ``` Transaction └── FinalBalanceUpdate: +75 SOL (net change) ``` This enables developers to track both fine-grained fund flows and final states. *** ## DEX Data `TradeEvents` provides DEX trade data (Topic: `sol.dex.trades`), using common TradeEvent structure. ### Trade Core Fields | Field | Description | | :------------------------------------ | :--------------------------------- | | `token_a_address` / `token_b_address` | Trading pair token addresses | | `user_a_amount` / `user_b_amount` | User trade amounts | | `pool_address` | Pool address | | `vault_a` / `vault_b` | Pool vault addresses | | `vault_a_amount` / `vault_b_amount` | Vault amounts | | `bonding_curve` | Bonding curve info (if applicable) | ### DApp Info | Field | Description | | :---------------------- | :---------------------------------------- | | `program_address` | DEX program address (e.g., Raydium, Orca) | | `inner_program_address` | Inner program address | | `chain` | Chain identifier (CHAIN\_SOLANA) | ### DexPoolEvent - Liquidity Pools | Field | Description | | :------------------------------------ | :------------------------------------------------------------------- | | `type` | Event type (INITIALIZE/INCREASE\_LIQUIDITY/DECREASE\_LIQUIDITY/SWAP) | | `address` | Pool address | | `token_a_address` / `token_b_address` | Token addresses | | `token_a_amount` / `token_b_amount` | Token amounts | | `lp_wallet` | LP wallet address | *** ## Solana Chain Characteristics ### Slot Mechanism Solana uses Slot rather than traditional block number as timeline identifier: | Characteristic | Description | | :----------------- | :-------------------------- | | Block interval | \~400ms | | Message volume | Much higher than EVM chains | | Primary identifier | Slot number | ### Message Packaging Transactions are packaged in small batches, each Kafka message contains no more than 250 transactions. ### Block Header Completeness In Solana's shred stream, Block Header may be incomplete, only the **Slot** field is guaranteed correct. Other fields may be empty or inaccurate. ### High-Throughput Processing Recommendations Due to Solana's extremely high throughput, we recommend: 1. **Sufficient processing capacity**: Ensure consumers have adequate CPU and memory 2. **Parallel processing**: Use multi-threading/coroutines for parallel message processing 3. **Efficient parsing**: Optimize Protobuf parsing code 4. **Batch writes**: Use batch database writes if persistence is needed *** ## Topic → Message Type Mapping | Topic | Proto File | Message Type | Description | | :------------------------- | :-------------------------------------- | :---------------------- | :------------------------------------ | | `sol.dex.trades` | trade\_event.proto | TradeEvents | DEX trade events | | `sol.dex.trades.processed` | trade\_event.proto | TradeEvents | With USD price, suspicious flag | | `sol.tokens` | token\_event.proto | TokenEvents | Token events | | `sol.tokens.processed` | token\_event.proto | TokenEvents | With description, image, social links | | `sol.balances` | balance\_event.proto | BalanceEvents | Balance change events | | `sol.transfers` | solana/transfer\_event.proto | TransferEvents | Solana transfer events | | `sol.transfers.processed` | solana/transfer\_processed\_event.proto | TransferProcessedEvents | With USD value | | `sol.dex.pools` | dex\_pool\_event.proto | DexPoolEvents | Liquidity pool events | | `sol.candlesticks` | candlestick.proto | CandlestickEvents | Candlestick data | *** ## Code Examples ### Python Example: Consume Solana DEX Trades ```python theme={null} from kafka import KafkaConsumer from common import trade_event_pb2 # Get from streaming_protobuf repository # Create consumer consumer = KafkaConsumer( 'sol.dex.trades', bootstrap_servers=[''], security_protocol='SASL_SSL', sasl_mechanism='SCRAM-SHA-512', sasl_plain_username='your_username', sasl_plain_password='your_password', auto_offset_reset='latest', enable_auto_commit=False, group_id='my-solana-consumer' ) # Consume and parse messages for message in consumer: trade_events = trade_event_pb2.TradeEvents() trade_events.ParseFromString(message.value) for event in trade_events.events: print(f"Pool: {event.trade.pool_address}") print(f"Token A: {event.trade.token_a_address}") print(f"Token B: {event.trade.token_b_address}") print(f"Amount A: {event.trade.user_a_amount}") print(f"Amount B: {event.trade.user_b_amount}") print(f"Slot: {event.block.slot}") print(f"DEX Program: {event.d_app.program_address}") print("---") ``` ### Go Example: High-Performance Consumption ```go theme={null} package main import ( "context" "log" "github.com/segmentio/kafka-go" "github.com/segmentio/kafka-go/sasl/scram" "google.golang.org/protobuf/proto" common "github.com/chainstream-io/streaming_protobuf/common/messages" ) func main() { mechanism, _ := scram.Mechanism(scram.SHA512, "your_username", "your_password") reader := kafka.NewReader(kafka.ReaderConfig{ Brokers: []string{""}, Topic: "sol.dex.trades", GroupID: "my-solana-consumer", Dialer: &kafka.Dialer{ SASLMechanism: mechanism, TLS: &tls.Config{}, }, }) defer reader.Close() // Use worker pool for parallel processing messages := make(chan kafka.Message, 100) // Start workers for i := 0; i < 10; i++ { go func() { for msg := range messages { var tradeEvents common.TradeEvents if err := proto.Unmarshal(msg.Value, &tradeEvents); err != nil { log.Printf("Failed to parse: %v", err) continue } // Process trades for _, event := range tradeEvents.Events { log.Printf("Pool: %s, Token A: %s, Token B: %s", event.Trade.PoolAddress, event.Trade.TokenAAddress, event.Trade.TokenBAddress) log.Printf("Amount A: %s, Amount B: %s, Slot: %d", event.Trade.UserAAmount, event.Trade.UserBAmount, event.Block.Slot) } } }() } // Read messages for { msg, err := reader.ReadMessage(context.Background()) if err != nil { log.Printf("Error reading: %v", err) continue } messages <- msg } } ``` *** ## Related Documentation Kafka Streams integration basics EVM chain data streams TRON network data streams WebSocket integration # TRON Streams Source: https://docs.chainstream.io/en/docs/access-methods/kafka-streams/tron-streams Protobuf data streams for TRON network TRON produces a block approximately every 3 seconds, supporting high-throughput transactions and smart contract execution. TRON uses a unique resource model (Energy and Bandwidth) and Witness (Super Representative) consensus mechanism. **Schema Repository**: [github.com/chainstream-io/streaming\_protobuf/tron](https://github.com/chainstream-io/streaming_protobuf/tree/main/tron) *** ## Message Types Overview TRON Streams provides the following message types: | Message Type | Description | Topic | | :---------------- | :-------------------- | :------------------------ | | TradeEvents | DEX trade events | `tron.dex.trades` | | TokenEvents | Token events | `tron.tokens` | | BalanceEvents | Balance change events | `tron.balances` | | DexPoolEvents | Liquidity pool events | `tron.dex.pools` | | TransfersMessage | Transfer messages | `tron.v1.transfers.proto` | | CandlestickEvents | Candlestick data | `tron.candlesticks` | *** ## Block-Level Data ### BlockHeader Core Fields | Field | Type | Description | | :----------- | :-------- | :-------------------- | | `Number` | uint64 | Block number | | `Hash` | bytes | Block hash | | `ParentHash` | bytes | Parent block hash | | `Timestamp` | Timestamp | Block time | | `TxTrieRoot` | bytes | Transaction trie root | | `Version` | uint32 | Block version | ### Witness (Super Representative) Information | Field | Description | | :---------- | :-------------- | | `Address` | Witness address | | `Id` | Witness ID | | `Signature` | Block signature | TRON uses DPoS consensus mechanism with 27 Super Representatives (Witnesses) taking turns to produce blocks. *** ## Transaction-Level Data ### TransactionHeader | Field | Type | Description | | :----------- | :-------- | :----------------- | | `Hash` | bytes | Transaction hash | | `Fee` | uint64 | Transaction fee | | `Index` | uint32 | Index within block | | `Expiration` | Timestamp | Expiration time | | `FeeLimit` | uint64 | Fee limit | | `Signatures` | \[]bytes | Signature list | | `FeePayer` | bytes | Fee payer | ### Result — Execution Result | Field | Description | | :-------- | :----------------------- | | `Status` | Execution status | | `Success` | Whether successful | | `Message` | Error message on failure | ### Receipt — Resource Consumption | Field | Description | | :----------------- | :----------------------- | | `EnergyUsageTotal` | Total Energy consumption | | `EnergyFee` | Energy fee | | `NetUsage` | Bandwidth consumption | | `NetFee` | Bandwidth fee | ### Contract Contains contract execution details: | Field | Description | | :--------------------- | :----------------------------------------------------------- | | `Address` | Contract address | | `Type` | Contract type (TransferContract, TriggerSmartContract, etc.) | | `Parameters` | Call parameters | | `InternalTransactions` | Internal transactions | | `Logs` | Event logs | | `ExecutionTrace` | Execution trace | | `WithdrawInfo` | Reward withdrawal information | *** ## Transfer Data `TransfersMessage` provides TRON chain transfer information (Topic: `tron.v1.transfers.proto`). ### TransfersMessage Structure ```protobuf theme={null} message TransfersMessage { Chain Chain = 1; BlockHeader Header = 2; repeated Transfer Transfers = 3; } ``` ### Transfer Structure | Field | Type | Description | | :------------------ | :---------------- | :----------------- | | `CallIndex` | uint64 | Call index | | `LogIndex` | uint64 | Log index | | `Sender` | string | Sender address | | `Receiver` | string | Receiver address | | `Amount` | string | Transfer amount | | `Id` | string | Token ID (NFT) | | `URI` | string | Token URI | | `Currency` | TokenInfo | Token information | | `Success` | bool | Success status | | `Index` | uint32 | Transfer index | | `TransactionHeader` | TransactionHeader | Transaction header | ### TokenInfo Structure | Field | Type | Description | | :-------------- | :----- | :----------------- | | `SmartContract` | string | Contract address | | `Delegated` | bool | Is delegated | | `DelegatedTo` | string | Delegation address | | `ProtocolName` | string | Protocol name | | `Name` | string | Token name | | `Symbol` | string | Token symbol | | `Decimals` | int32 | Decimals | | `HasURI` | bool | Has URI | | `Fungible` | bool | Is fungible | | `AssetId` | string | Asset ID (TRC-10) | ### TRON Token Standards | Standard | Description | | :------- | :------------------------------------------- | | TRC-10 | TRON native tokens, no smart contract needed | | TRC-20 | Smart contract tokens (similar to ERC-20) | | TRC-721 | NFT tokens (similar to ERC-721) | TRC-10 is TRON's unique native token standard, cheaper to create and transfer, but less flexible than TRC-20. *** ## DEX Data `TradeEvents` provides DEX trade data (Topic: `tron.dex.trades`), using common TradeEvent structure. ### Trade Core Fields | Field | Description | | :------------------------------------ | :--------------------------- | | `token_a_address` / `token_b_address` | Trading pair token addresses | | `user_a_amount` / `user_b_amount` | User trade amounts | | `pool_address` | Pool address | | `vault_a` / `vault_b` | Pool vault addresses | | `vault_a_amount` / `vault_b_amount` | Vault amounts | ### DApp Info | Field | Description | | :---------------------- | :----------------------------------- | | `program_address` | DEX contract address (e.g., SunSwap) | | `inner_program_address` | Inner program address | | `chain` | Chain identifier (CHAIN\_TRON) | ### DexPoolEvent - Liquidity Pools | Field | Description | | :------------------------------------ | :------------------------------------------------------------------- | | `type` | Event type (INITIALIZE/INCREASE\_LIQUIDITY/DECREASE\_LIQUIDITY/SWAP) | | `address` | Pool address | | `token_a_address` / `token_b_address` | Token addresses | | `token_a_amount` / `token_b_amount` | Token amounts | | `lp_wallet` | LP wallet address | *** ## TRON Chain Characteristics ### Energy and Bandwidth Resource Model Unlike EVM's Gas model, TRON uses two resources: | Resource | Description | How to Obtain | | :------------------ | :-------------------------------------------- | :--------------- | | **Energy** | Measures smart contract execution consumption | Stake TRX or pay | | **Bandwidth (Net)** | Measures transaction data size consumption | Stake TRX or pay | Receipt shows usage and fees for both resources: ``` Receipt { EnergyUsageTotal: 50000 // Smart contract consumption EnergyFee: 0 // 0 if staked NetUsage: 265 // Transaction data size NetFee: 0 // 0 if staked } ``` ### Witness System | Characteristic | Description | | :--------------- | :------------------------------ | | Name | Witness (Super Representative) | | Count | 27 active Super Representatives | | Election | Elected by token holders | | Block production | Takes turns, \~3 seconds/block | `BlockMessage` contains Witness address, ID, and signature. ### Predefined Contract Types TRON predefines contract types for common operations: | Type | Description | | :-------------------------- | :-------------------- | | `TransferContract` | TRX transfer | | `TransferAssetContract` | TRC-10 transfer | | `TriggerSmartContract` | Call smart contract | | `CreateSmartContract` | Create smart contract | | `FreezeBalanceV2Contract` | Stake TRX | | `UnfreezeBalanceV2Contract` | Unstake | | `DelegateResourceContract` | Resource delegation | | `WithdrawBalanceContract` | Withdraw rewards | Identified through Contract's `Type` field. ### Resource Delegation Users can delegate Energy and Bandwidth to other accounts, commonly used in the TRON ecosystem for: * Reducing user transaction costs * DApps paying resources for users *** ## Topic → Message Type Mapping | Topic | Proto File | Message Type | Description | | :---------------------------------- | :---------------------------- | :---------------- | :------------------------------------ | | `tron.dex.trades` | trade\_event.proto | TradeEvents | DEX trade events | | `tron.dex.trades.processed` | trade\_event.proto | TradeEvents | With USD price, suspicious flag | | `tron.tokens` | token\_event.proto | TokenEvents | Token events | | `tron.tokens.processed` | token\_event.proto | TokenEvents | With description, image, social links | | `tron.balances` | balance\_event.proto | BalanceEvents | Balance change events | | `tron.v1.transfers.proto` | tron/transfers\_message.proto | TransfersMessage | TRON transfer messages | | `tron.v1.transfers.processed.proto` | tron/transfers\_message.proto | TransfersMessage | Processed transfer messages | | `tron.dex.pools` | dex\_pool\_event.proto | DexPoolEvents | Liquidity pool events | | `tron.candlesticks` | candlestick.proto | CandlestickEvents | Candlestick data | *** ## Code Examples ### Python Example: Consume TRON DEX Trades ```python theme={null} from kafka import KafkaConsumer from common import trade_event_pb2 # Get from streaming_protobuf repository # Create consumer consumer = KafkaConsumer( 'tron.dex.trades', bootstrap_servers=[''], security_protocol='SASL_SSL', sasl_mechanism='SCRAM-SHA-512', sasl_plain_username='your_username', sasl_plain_password='your_password', auto_offset_reset='latest', enable_auto_commit=False, group_id='my-tron-consumer' ) # Consume and parse messages for message in consumer: trade_events = trade_event_pb2.TradeEvents() trade_events.ParseFromString(message.value) for event in trade_events.events: print(f"Pool: {event.trade.pool_address}") print(f"Token A: {event.trade.token_a_address}") print(f"Token B: {event.trade.token_b_address}") print(f"Amount A: {event.trade.user_a_amount}") print(f"Amount B: {event.trade.user_b_amount}") print(f"Block: {event.block.height}") print(f"DEX: {event.d_app.program_address}") print("---") ``` ### Monitor TRC-20 Token Events ```python theme={null} from kafka import KafkaConsumer from common import token_event_pb2 consumer = KafkaConsumer( 'tron.tokens', bootstrap_servers=[''], security_protocol='SASL_SSL', sasl_mechanism='SCRAM-SHA-512', sasl_plain_username='your_username', sasl_plain_password='your_password', auto_offset_reset='latest', group_id='my-tron-token-consumer' ) # USDT on TRON USDT_ADDRESS = 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t' for message in consumer: token_events = token_event_pb2.TokenEvents() token_events.ParseFromString(message.value) for event in token_events.events: # Filter USDT events if event.token.address == USDT_ADDRESS: print(f"Event Type: {event.type}") # CREATED or UPDATED print(f"Token: {event.token.symbol}") print(f"Name: {event.token.name}") print(f"Decimals: {event.token.decimals}") print("---") ``` *** ## Related Documentation Kafka Streams integration basics EVM chain data streams Solana high-throughput data streams WebSocket integration # Access Methods Source: https://docs.chainstream.io/en/docs/access-methods/overview Pick the right interface for your workload — REST, GraphQL, WebSocket, Kafka, SDK, CLI or MCP. ChainStream exposes the same catalog of [data products](/en/docs/data-products/overview) through several different interfaces. Each one has a sweet spot — you will usually combine two or three in a single integration. ## Quick comparison | | Best for | Pattern | Latency | Auth | Where to start | | :---------------- | :----------------------------------------------- | :--------------- | :---------------- | :--------------------- | :------------------------------------------------------ | | **REST API** | On-demand lookups, dashboards, user queries | Request/response | 50–200 ms | API key / OAuth | [REST API](/en/docs/access-methods/rest-api) | | **GraphQL** | Analytical queries, aggregations, flexible joins | Request/response | 100–500 ms | API key / OAuth | [GraphQL](/en/docs/access-methods/graphql) | | **WebSocket** | Live UIs, browser + mobile apps | Push (subscribe) | \<2 ms tick | API key | [WebSocket](/en/docs/access-methods/websocket) | | **Kafka Streams** | Trading engines, indexers, alert pipelines | Stream (consume) | \<100 ms p99 | SASL / OAuth | [Kafka](/en/docs/access-methods/kafka-streams/overview) | | **SDKs** | Typed access from TS / Python / Go / Rust | Client library | Matches transport | Inherits underlying | [SDKs](/en/sdks/overview) | | **CLI** | Scripting, CI/CD, AI agents, pay-per-call | Command line | Matches transport | API key / OAuth / x402 | [CLI](/en/docs/access-methods/cli) | | **MCP Server** | AI agents (Claude, Cursor, ChatGPT, custom) | Tool protocol | Matches transport | API key / x402 | [MCP](/en/docs/ai-agents/mcp-server/introduction) | ## Decision guide Start with **REST** for lookups and charts, layer **WebSocket** for live updates. Use **GraphQL** if your screens need aggregated or pivoted data. Use **Kafka Streams** for primary ingestion (exactly-once, horizontally scaled). Fall back to **REST** for cold lookups and **GraphQL** for analytical backfills. **GraphQL** gives you dimensional queries over the entire data cube without per-chain boilerplate. Export to notebooks via the **Python SDK**. **WebSocket** for live streams (prices, trades, balances). **REST** for anything that is fine with polling or happens on user action. **MCP Server** exposes the catalog as typed tools for LLM agents. If your agent runs its own code, use **SDKs** directly; for pay-per-call semantics, use the **CLI** with x402/MPP. **REST** calls to the KYT endpoints fit most integration patterns. For high volume screening pipelines, use the **Kafka transfer topic** plus REST scoring side-by-side. ## Authentication at a glance Every access method accepts the same credentials. Pick the one that matches your environment — you do not need separate credentials per transport. Quickest path. One header, works on REST / GraphQL / WebSocket / CLI / SDK. For server-to-server production use — client-credentials JWT flow. Sign-In With X — let end-users authenticate with their wallet. For AI agents and per-call micropayments see [x402 Payments](/en/docs/platform/billing-payments/x402-payments) and [MPP Payments](/en/docs/platform/billing-payments/mpp-payments). ## Next HTTP endpoints for tokens, wallets, trades, pools, compliance. Flexible analytics across the normalized chain cube. Live push for prices, trades, balances and pool events. Production streaming with exactly-once semantics. # REST API Source: https://docs.chainstream.io/en/docs/access-methods/rest-api Lookup, snapshot and analytical endpoints over plain HTTP — the default surface for most apps. The REST API is the simplest way to pull data from ChainStream. Every [data product](/en/docs/data-products/overview) is exposed as a JSON endpoint, with the same authentication and error envelope. ## Base URL ``` https://api.chainstream.io ``` ## Authentication Include one of: ```bash theme={null} -H "Authorization: Bearer $CHAINSTREAM_API_KEY" # or OAuth token -H "Authorization: Bearer $OAUTH_TOKEN" # or x402 micropayment (see Platform / Billing) -H "X-PAYMENT: " ``` See [Authentication](/en/api-reference/authentication/authenticate) for the full matrix. ## First request ```bash theme={null} curl -H "Authorization: Bearer $CHAINSTREAM_API_KEY" \ "https://api.chainstream.io/v2/token/search?chain=sol&keyword=USDC&limit=5" ``` ## When to use * Single lookups, snapshots, server-rendered pages * Any workload where sub-second latency isn't critical * Pairing with [WebSocket](/en/docs/access-methods/websocket) (REST for history, WS for live) * Agent tool-calls where each invocation maps to one endpoint When **not** to: high-frequency streaming workloads (use WebSocket or Kafka) and multi-product JOINs (use GraphQL). ## Conventions * Pagination: `limit` + `cursor` (cursor-based) on list endpoints * Rate limits: per-plan; see response headers `X-RateLimit-Remaining`, `X-RateLimit-Reset` * Errors: RFC 7807-style JSON with `code`, `message`, `requestId` ## Next Every REST endpoint with request/response examples. Typed REST wrappers for TS / Py / Go / Rust. Per-plan throughput and how to plan for it. API keys, OAuth, wallet-auth, x402. # SDKs Source: https://docs.chainstream.io/en/docs/access-methods/sdks Typed client libraries for TypeScript, Python, Go and Rust — idiomatic wrappers over REST, GraphQL and WebSocket. The ChainStream SDKs give you a single, ergonomic way to call every data product from your language of choice. The same [data products](/en/docs/data-products/overview) and [access methods](/en/docs/access-methods/overview) — just typed, batteries-included. ## Languages `@chainstream-io/sdk` — first-class support for browser and Node. `chainstream` — async-first client, friendly for notebooks and bots. `github.com/chainstream-io/chainstream-go` — idiomatic Go. `chainstream` crate — for latency-critical consumers. ## Install ```bash theme={null} npm install @chainstream-io/sdk # TypeScript pip install chainstream # Python go get github.com/chainstream-io/chainstream-go cargo add chainstream # Rust ``` ## First call — TypeScript ```ts theme={null} import { ChainStream } from "@chainstream-io/sdk"; const cs = new ChainStream({ apiKey: process.env.CHAINSTREAM_API_KEY! }); const results = await cs.token.search({ chain: "solana", keyword: "USDC", limit: 5, }); for (const t of results) { console.log(t.symbol, t.priceUsd); } ``` ## Common patterns * **REST** — `cs.token.*`, `cs.wallet.*`, `cs.trade.*`, `cs.ranking.*`, `cs.dex.*` ... * **WebSocket** — `cs.stream.subscribeTokenTrade({ chain, tokenAddress, callback })` (and parallel methods for candles, stats, holders, wallets, rankings, pools) * **GraphQL** — `cs.gql(query, variables)` returns a fully typed result via codegen * **CLI bridge** — `cs.cli("market", "trending", { chain: "sol", duration: "24h" })` runs the same logic as `chainstream market trending --chain sol --duration 24h` ## When to use * Integrating into an application — almost always the right default * When you want types, retries, error mapping and pagination handled for you * When you want to swap REST ↔ WebSocket for the same resource without rewriting When **not** to: quick one-offs where `curl` + REST is faster (or CLI). ## Next Per-language guides and release notes. Underlying REST / GraphQL / WebSocket surfaces. # Realtime Streaming Source: https://docs.chainstream.io/en/docs/access-methods/websocket WebSocket real-time data streaming guide ChainStream provides powerful real-time data streaming capabilities, allowing developers to instantly receive on-chain events, transactions, and state changes. This document covers WebSocket connection, subscription mechanisms, and best practices. *** ## Connection ### WebSocket Endpoint ``` wss://realtime-dex.chainstream.io/connection/websocket ``` ### Authentication Provide the Access Token in the URL when establishing a connection: ``` wss://realtime-dex.chainstream.io/connection/websocket?token=YOUR_ACCESS_TOKEN ``` The SDK handles connection and authentication automatically. Just call the subscribe method: ```javascript theme={null} import { ChainStreamClient } from '@chainstream-io/sdk'; import { Resolution } from '@chainstream-io/sdk/openapi'; const client = new ChainStreamClient(process.env.CHAINSTREAM_ACCESS_TOKEN); // Subscribe directly, SDK handles connection and authentication automatically client.stream.subscribeTokenCandles({ chain: 'sol', tokenAddress: '6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN', resolution: Resolution._1m, callback: (data) => { console.log('Received data:', data); } }); ``` The SDK automatically detects connection status and establishes connection when needed. No need to manually call `connect()`. When using native WebSocket, send a `connect` message after connection to complete authentication: ```javascript theme={null} const token = process.env.CHAINSTREAM_ACCESS_TOKEN; const ws = new WebSocket( `wss://realtime-dex.chainstream.io/connection/websocket?token=${token}` ); ws.onopen = () => { console.log('WebSocket connection established'); // Send connect message to complete authentication ws.send(JSON.stringify({ connect: { token: token, name: 'js' }, id: 1 })); }; ws.onmessage = (event) => { const data = JSON.parse(event.data); // Handle connect response if (data.connect) { console.log('✅ Authentication successful, client ID:', data.connect.client); // Start subscribing after authentication ws.send(JSON.stringify({ subscribe: { channel: 'dex-candle:sol_6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN_1m' }, id: 2 })); } // Handle subscription data if (data.push) { console.log('Received data:', data.push.pub.data); } }; ``` Test using `wscat`: ```bash theme={null} wscat -c "wss://realtime-dex.chainstream.io/connection/websocket?token=YOUR_ACCESS_TOKEN" ``` Send connect message after connection: ```json theme={null} {"connect":{"token":"YOUR_ACCESS_TOKEN","name":"test"},"id":1} ``` ### Connection Response Upon successful authentication, you'll receive a response like: ```json theme={null} { "id": 1, "connect": { "client": "0f819f5f-7d8b-4949-9433-0e91bbfe1cdb", "version": "0.0.0 OSS", "expires": true, "ttl": 86002, "ping": 25, "pong": true } } ``` | Field | Description | | :------- | :--------------------------------- | | `client` | Unique client identifier | | `ttl` | Token remaining validity (seconds) | | `ping` | Heartbeat interval (seconds) | | `pong` | Whether pong response is supported | *** ## Subscription Types ChainStream WebSocket supports multiple data subscription types: | Category | Channel Prefix | Description | | :--------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------ | | Candles (USD) | `dex-candle:` | Token candles (token / pool / pair variants) | | Candles (native) | `dex-candle-in-native:` | Same as above, priced in the chain's native asset | | Pool Candles | `dex-pool-candle:` / `dex-pair-candle:` | Pool-scoped or pair-scoped candles | | Token Stats | `dex-token-stats:` | Multi-window trade stats (1m, 5m, ... 1W, 1M) | | Holder Stats | `dex-token-holding:` | Holder distribution and balance tags | | Token Supply | `dex-token-supply:` | Supply and market cap updates | | Liquidity | `dex-token-liquidity:` / `dex-token-total-liquidity:` | Largest-pool / total liquidity | | New Tokens | `dex-new-token:` / `dex-new-tokens:` / `dex-new-tokens-metadata:` | New listings (single event / batch / metadata) | | Token Trades | `dex-trade:` | Trades filtered by token address | | Wallet Balance | `dex-wallet-balance:` | Wallet token-balance changes | | Wallet Trades | `dex-wallet-trade:` | Trades filtered by wallet address | | Wallet PnL | `dex-wallet-token-pnl:` / `dex-wallet-pnl-list:` | Per-token / aggregate wallet PnL | | Rankings | `dex-ranking-list:` / `dex-ranking-token-stats-list:` / `dex-ranking-token-holding-list:` / `dex-ranking-token-supply-list:` / `dex-ranking-token-bounding-curve-list:` | Ranking membership + per-token stats | | DEX Pools | `dex-pool-balance:` | Pool liquidity snapshots | For complete subscription types, parameters, and response formats, see the [WebSocket API reference](/en/api-reference/endpoint/websocket/api). The SDKs (`client.stream.subscribeTokenCandles`, `subscribeTokenStats`, `subscribeTokenTrade`, ...) wrap these channel strings so you don't have to build them by hand. ### Subscription Format Examples ```javascript theme={null} // Subscribe to candle data ws.send(JSON.stringify({ subscribe: { channel: 'dex-candle:sol_6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN_1m' }, id: 2 })); // Subscribe to token stats ws.send(JSON.stringify({ subscribe: { channel: 'dex-token-stats:sol_6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN' }, id: 3 })); // Subscribe to new tokens ws.send(JSON.stringify({ subscribe: { channel: 'dex-new-token:sol' }, id: 4 })); ``` ### Unsubscribe ```javascript theme={null} ws.send(JSON.stringify({ unsubscribe: { channel: 'dex-candle:sol_6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN_1m' }, id: 5 })); ``` *** ## Message Format ### Request Messages **Connect Message (Authentication):** ```json theme={null} { "connect": { "token": "YOUR_ACCESS_TOKEN", "name": "client_name" }, "id": 1 } ``` **Subscribe Message:** ```json theme={null} { "subscribe": { "channel": "dex-candle:sol_xxx_1m" }, "id": 2 } ``` **Unsubscribe Message:** ```json theme={null} { "unsubscribe": { "channel": "dex-candle:sol_xxx_1m" }, "id": 3 } ``` ### Response Messages **Subscription Confirmation:** ```json theme={null} { "id": 2, "subscribe": {} } ``` **Data Push:** ```json theme={null} { "push": { "channel": "dex-candle:sol_xxx_1m", "pub": { "data": { "o": 0.001234, "c": 0.001256, "h": 0.001280, "l": 0.001200, "v": 1234567, "t": 1706745600 } } } } ``` **Error Message:** ```json theme={null} { "id": 2, "error": { "code": 100, "message": "invalid channel" } } ``` *** ## Heartbeat WebSocket connections require periodic heartbeat messages to stay active. Based on the `ping` field in the connect response (usually 25 seconds), send heartbeats within this interval: ```javascript theme={null} // Heartbeat message ws.send(JSON.stringify({})); // Or send ping ws.send(JSON.stringify({ ping: {} })); ``` If no messages are sent within the specified time (typically 3x the ping interval), the server will disconnect. *** ## Complete Example ```javascript JavaScript theme={null} const WebSocket = require('ws'); class ChainStreamWebSocket { constructor(accessToken) { this.accessToken = accessToken; this.ws = null; this.messageId = 0; this.reconnectAttempts = 0; this.maxReconnectAttempts = 10; this.subscriptions = new Set(); this.pingInterval = null; } connect() { const url = `wss://realtime-dex.chainstream.io/connection/websocket?token=${this.accessToken}`; this.ws = new WebSocket(url); this.ws.onopen = () => { console.log('WebSocket connection established'); this.reconnectAttempts = 0; // Send connect message this.send({ connect: { token: this.accessToken, name: 'nodejs' } }); }; this.ws.onmessage = (event) => { const data = JSON.parse(event.data); this.handleMessage(data); }; this.ws.onclose = (event) => { console.log(`Connection closed: ${event.code}`); this.stopPing(); if (event.code !== 1000) { this.scheduleReconnect(); } }; this.ws.onerror = (error) => { console.error('WebSocket error:', error.message); }; } handleMessage(data) { // Handle connect response if (data.connect) { console.log('✅ Authentication successful'); this.startPing(data.connect.ping || 25); this.resubscribe(); return; } // Handle data push if (data.push) { console.log(`[${data.push.channel}]`, data.push.pub.data); return; } // Handle error if (data.error) { console.error('Error:', data.error.message); return; } } send(message) { message.id = ++this.messageId; this.ws.send(JSON.stringify(message)); } subscribe(channel) { this.subscriptions.add(channel); this.send({ subscribe: { channel } }); } unsubscribe(channel) { this.subscriptions.delete(channel); this.send({ unsubscribe: { channel } }); } resubscribe() { this.subscriptions.forEach(channel => { this.send({ subscribe: { channel } }); }); } startPing(interval) { this.pingInterval = setInterval(() => { if (this.ws.readyState === WebSocket.OPEN) { this.ws.send('{}'); } }, interval * 1000); } stopPing() { if (this.pingInterval) { clearInterval(this.pingInterval); this.pingInterval = null; } } scheduleReconnect() { if (this.reconnectAttempts >= this.maxReconnectAttempts) { console.error('❌ Max reconnect attempts reached'); return; } const delay = Math.min(1000 * Math.pow(2, this.reconnectAttempts), 30000); console.log(`⏳ Reconnecting in ${delay}ms... (attempt ${this.reconnectAttempts + 1})`); this.reconnectAttempts++; setTimeout(() => this.connect(), delay); } close() { this.stopPing(); if (this.ws) { this.ws.close(1000, 'Normal closure'); } } } // Usage example const client = new ChainStreamWebSocket(process.env.CHAINSTREAM_ACCESS_TOKEN); client.connect(); // Subscribe after connection is established setTimeout(() => { client.subscribe('dex-candle:sol_6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN_1m'); client.subscribe('dex-new-token:sol'); }, 1000); ``` ```python Python theme={null} import asyncio import websockets import json import os class ChainStreamWebSocket: def __init__(self, access_token): self.access_token = access_token self.ws = None self.message_id = 0 self.subscriptions = set() self.ping_interval = 25 async def connect(self): url = f"wss://realtime-dex.chainstream.io/connection/websocket?token={self.access_token}" async with websockets.connect(url) as ws: self.ws = ws print("WebSocket connection established") # Send connect message await self.send({ "connect": { "token": self.access_token, "name": "python" } }) # Start heartbeat and message receiving await asyncio.gather( self.heartbeat(), self.receive() ) async def send(self, message): self.message_id += 1 message["id"] = self.message_id await self.ws.send(json.dumps(message)) async def receive(self): async for message in self.ws: data = json.loads(message) await self.handle_message(data) async def handle_message(self, data): if "connect" in data: print("✅ Authentication successful") self.ping_interval = data["connect"].get("ping", 25) await self.resubscribe() elif "push" in data: channel = data["push"]["channel"] pub_data = data["push"]["pub"]["data"] print(f"[{channel}]", pub_data) elif "error" in data: print(f"Error: {data['error']['message']}") async def subscribe(self, channel): self.subscriptions.add(channel) await self.send({"subscribe": {"channel": channel}}) async def resubscribe(self): for channel in self.subscriptions: await self.send({"subscribe": {"channel": channel}}) async def heartbeat(self): while True: await asyncio.sleep(self.ping_interval) if self.ws and self.ws.open: await self.ws.send("{}") # Usage example async def main(): client = ChainStreamWebSocket(os.environ["CHAINSTREAM_ACCESS_TOKEN"]) # Pre-add subscriptions client.subscriptions.add("dex-candle:sol_6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN_1m") client.subscriptions.add("dex-new-token:sol") await client.connect() asyncio.run(main()) ``` *** ## Best Practices ### Performance Optimization Subscribe only to needed data to reduce bandwidth. Use CEL expressions to filter data. Batch process high-frequency data instead of processing one by one. Use message queues for buffering. Cache static data like token information to reduce repeated processing. A single connection can subscribe to multiple channels. Avoid creating multiple connections. ### Error Handling 1. **Listen for error events** — Handle connection and data errors promptly 2. **Implement retry mechanism** — Use exponential backoff for reconnection 3. **Log recording** — Record key events for troubleshooting 4. **Graceful degradation** — Switch to polling when WebSocket is unavailable ### Resource Management ```javascript theme={null} // ✅ Unsubscribe from unneeded channels promptly client.unsubscribe('dex-candle:sol_xxx_1m'); // ✅ Close connection gracefully function gracefulClose() { // 1. Stop heartbeat client.stopPing(); // 2. Close connection client.close(); } ``` *** ## Related Documentation Complete subscription types and parameters Hands-on: Build a price monitoring bot # chainstream-data Skill Source: https://docs.chainstream.io/en/docs/ai-agents/agent-skills/chainstream-data On-chain data intelligence — token analytics, market trends, wallet profiling ## Overview The `chainstream-data` skill provides read-only on-chain data capabilities across Solana, BSC, and Ethereum. It covers token analytics, market ranking, wallet profiling, and WebSocket streaming. * **Pattern**: Tool (read-only, no signing) * **MCP Server**: `https://mcp.chainstream.io/mcp` (17 tools) * **CLI**: `npx @chainstream-io/cli` * **API Base**: `https://api.chainstream.io` ## Integration Path The skill uses a decision tree to route to the right execution channel: ```mermaid theme={null} flowchart TD Start["Data query"] --> HasMCP{"MCP registered?"} HasMCP -->|Yes| MCP["Use MCP tools"] HasMCP -->|No| CLI["Use CLI commands"] MCP -->|Failed| CLI CLI --> NeedDeFi{"Need DeFi?"} NeedDeFi -->|Yes| DefiSkill["Switch to chainstream-defi"] NeedDeFi -->|No| Done["Return results"] ``` ## Channel Matrix | Operation | MCP Tool | CLI Command | SDK Method | | ---------------------- | ---------------------- | ----------------- | -------------------------- | | Search tokens | `tokens_search` | `token search` | `client.token.search` | | Analyze token | `tokens_analyze` | `token info` | `client.token.getToken` | | Security check | `tokens_analyze` | `token security` | `client.token.getSecurity` | | Top holders | `tokens_analyze` | `token holders` | `client.token.getHolders` | | Price history (K-line) | `tokens_price_history` | `token candles` | `client.token.getCandles` | | Liquidity pools | `tokens_discover` | `token pools` | `client.token.getPools` | | Trending tokens | `market_trending` | `market trending` | `client.ranking.*` | | New listings | `market_trending` | `market new` | `client.ranking.*` | | Recent trades | `trades_recent` | `market trades` | `client.trade.*` | | Wallet profile | `wallets_profile` | `wallet profile` | `client.wallet.*` | | Wallet PnL | `wallets_profile` | `wallet pnl` | `client.wallet.*` | | Token balances | `wallets_profile` | `wallet holdings` | `client.wallet.*` | | Transfer history | `wallets_activity` | `wallet activity` | `client.wallet.*` | | DEX quote | `dex_quote` | `dex route` | `client.dex.quote` | ## AI Workflows ### Token Research A complete token analysis flow — always run security checks before recommending any token. ```mermaid theme={null} graph LR Search["token search"] --> Info["token info"] Info --> Security["token security"] Security --> Holders["token holders"] Holders --> Candles["token candles"] ``` ```bash theme={null} npx @chainstream-io/cli token search --keyword PUMP --chain sol npx @chainstream-io/cli token info --chain sol --address npx @chainstream-io/cli token security --chain sol --address npx @chainstream-io/cli token holders --chain sol --address npx @chainstream-io/cli token candles --chain sol --address --resolution 1h ``` ``` tokens_search { "query": "PUMP", "chain": "solana" } tokens_analyze { "chain": "solana", "address": "" } tokens_price_history { "chain": "solana", "address": "", "resolution": "1h" } ``` ### Market Discovery Find trending tokens, apply multi-factor analysis, then security-check the top candidates. ```mermaid theme={null} graph LR Trending["market trending"] --> Analysis["AI multi-factor analysis"] Analysis --> Security["token security (top 5)"] Security --> Present["Present to user"] Present --> Trade{"User wants to trade?"} Trade -->|Yes| DefiSkill["Load chainstream-defi"] ``` ```bash theme={null} npx @chainstream-io/cli market trending --chain sol --duration 1h --limit 50 # AI analyzes: smart money signals, volume, momentum, safety npx @chainstream-io/cli token security --chain sol --address npx @chainstream-io/cli token security --chain sol --address ``` ``` market_trending { "chain": "solana", "duration": "1h", "limit": 50 } tokens_analyze { "chain": "solana", "address": "" } ``` ### Wallet Profiling Analyze a wallet's performance, holdings, and trading behavior. ```mermaid theme={null} graph LR Profile["wallet profile"] --> Activity["wallet activity"] Activity --> TokenInfo["token info (top holdings)"] TokenInfo --> Assess["Assess: win rate, concentration, behavior"] ``` ```bash theme={null} npx @chainstream-io/cli wallet profile --chain sol --address npx @chainstream-io/cli wallet activity --chain sol --address npx @chainstream-io/cli token info --chain sol --address ``` ``` wallets_profile { "chain": "solana", "address": "" } wallets_activity { "chain": "solana", "address": "" } ``` ## Safety Rules These rules are enforced by the skill to ensure data accuracy and responsible AI behavior. | Rule | Reason | | -------------------------------------------------------- | ----------------------------------------------------------------------------- | | Never answer price questions from training data | Crypto prices are stale within seconds — always make a live API call | | Always run `token security` before recommending | ChainStream's risk model covers honeypot, rug pull, and concentration signals | | Never pass `format: "detailed"` to MCP unless requested | Returns 4-10x more data than `concise`, wastes context window | | Never batch more than 50 addresses in `/multi` endpoints | API hard limit | | Never use public RPC as substitute | Results differ and miss ChainStream-specific enrichments | ## Error Recovery | Error | Recovery | | ------------------------- | ---------------------------------------------------------------------------- | | 401 / "Not authenticated" | Configure API Key or run `chainstream login` | | 402 / "Payment required" | Follow [x402 payment flow](/en/docs/platform/billing-payments/x402-payments) | | 429 / Rate limit | Wait 1s, exponential backoff | | 5xx / Server error | Retry once after 2s | ## Related For executing trades after research Full CLI command reference # chainstream-defi Skill Source: https://docs.chainstream.io/en/docs/ai-agents/agent-skills/chainstream-defi Irreversible DeFi execution — swap, launchpad, transaction broadcast All DeFi operations are **real and irreversible**. This skill requires explicit user confirmation before every destructive operation. Never auto-execute transactions. ## Overview The `chainstream-defi` skill handles on-chain DeFi execution across Solana, BSC, and Ethereum. It covers DEX token swaps, launchpad token creation, and signed transaction broadcasting. * **Pattern**: Process (destructive, requires signing) * **CLI**: `npx @chainstream-io/cli` (primary execution path) * **SDK**: `@chainstream-io/sdk` with `WalletSigner` * **MCP**: Quote, swap, and create tools available — but on-chain execution requires wallet-backed authentication on the host side ## Wallet Requirements DeFi operations require a wallet capable of signing transactions: | Path | Signing | Setup | | ------------------ | ----------------- | --------------------------------------------- | | CLI + TEE wallet | TEE-based signing | `chainstream login` | | CLI + Raw key | Local signing | `chainstream wallet set-raw --chain base` | | SDK + WalletSigner | Custom signing | Implement `signMessage` + `signTypedData` | | MCP only | **Not supported** | MCP has no wallet — use CLI or SDK | | API Key only | **Not supported** | API Key cannot sign — run `chainstream login` | ## Four-Phase Protocol Every destructive DeFi operation follows a strict four-phase protocol: ```mermaid theme={null} sequenceDiagram participant User participant Agent as AI Agent participant CLI participant API as ChainStream API participant Chain as Blockchain Agent->>CLI: dex route CLI->>API: POST /v2/dex/{chain}/route API-->>CLI: Quote (price, fees, route) CLI-->>Agent: Quote details Agent->>User: "Swap 1 SOL for ~X tokens. Fee: Y. Confirm?" User-->>Agent: "Yes" Agent->>CLI: dex swap --from wallet ... CLI->>API: POST /v2/dex/{chain}/swap API-->>CLI: Unsigned transaction CLI->>Chain: Sign + send transaction Chain-->>CLI: Transaction hash CLI->>API: POST /v2/transaction/{chain}/send API-->>CLI: Job ID CLI->>API: Poll job status API-->>CLI: { status: "completed", hash: "..." } CLI-->>Agent: Success + explorer link ``` ### Phase 1: Quote Get a price quote before any execution. This is read-only and safe. ```bash theme={null} chainstream dex route --chain sol --from --input-token SOL --output-token --amount 1000000 ``` ### Phase 2: User Confirmation **Mandatory.** Present the quote summary to the user and wait for explicit approval: * Input amount and token * Expected output amount * Price impact and fees * Slippage tolerance ### Phase 3: Sign and Send After confirmation, execute the swap. The CLI handles signing via the configured wallet. ```bash theme={null} chainstream dex swap --chain sol --from --input-token SOL --output-token --amount 1000000 ``` ### Phase 4: Poll Job The CLI automatically polls the job until completion and outputs the transaction hash with an explorer link. ```bash theme={null} # Manual polling (if needed) chainstream job status --id --wait ``` ## Supported Operations ### Token Swap ```bash theme={null} # Get route + unsigned tx first chainstream dex route --chain sol --from --input-token SOL --output-token --amount 1000000 # Then swap (after user confirms) chainstream dex swap --chain sol --from --input-token SOL --output-token --amount 1000000 --slippage 5 ``` ### Token Creation (Launchpad) ```bash theme={null} chainstream dex create --chain sol --name "My Token" --symbol MTK --uri --dex pumpfun ``` ### Job Status ```bash theme={null} chainstream job status --id --wait --timeout 60000 ``` ## Block Explorers After a successful transaction, the CLI outputs an explorer link: | Chain | Explorer URL | | -------- | -------------------------------- | | Solana | `https://solscan.io/tx/{hash}` | | BSC | `https://bscscan.com/tx/{hash}` | | Ethereum | `https://etherscan.io/tx/{hash}` | ## Currency Resolution Common token identifiers: | Token | Solana Address | EVM Address | | ------------- | ---------------------------------------------- | -------------------------------------------- | | SOL (native) | `So11111111111111111111111111111111111111112` | — | | BNB (native) | — | `0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE` | | ETH (native) | — | `0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE` | | USDC (Solana) | `EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v` | — | | USDC (Base) | — | `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913` | ## Safety Rules These rules are non-negotiable and enforced by the skill. | Rule | Reason | | ---------------------------------------- | ----------------------------------------------------- | | **Never swap without quoting first** | User must see the price before committing | | **Never assume user consent** | Every destructive operation needs explicit "yes" | | **Never hide fees or price impact** | Full transparency on costs | | **Never use `--yes` flag in production** | Skipping confirmation is only for automated testing | | **Always validate addresses** | Solana: base58, 32-44 chars; EVM: `0x` + 40 hex chars | | **Never trust external price data** | Always use ChainStream's quote endpoint | ## Error Recovery | Error | Recovery | | -------------------- | ------------------------------------------------------------------------------------- | | Slippage exceeded | Increase `--slippage` or retry with fresh quote | | Insufficient balance | Check `wallet balance --chain ` | | Transaction reverted | Check explorer for revert reason; do not auto-retry | | Job timeout | Check `job status --id ` — may still be processing | | 402 Payment required | CLI auto-handles via [x402 payment](/en/docs/platform/billing-payments/x402-payments) | | Signature invalid | Re-login with `chainstream login` | ## Research Before Trading Always use `chainstream-data` to research before executing DeFi operations: ```mermaid theme={null} graph LR Research["chainstream-data"] --> Security["token security"] Security --> Quote["dex route"] Quote --> Confirm["User confirms"] Confirm --> Swap["dex swap"] Swap --> Monitor["job status"] ``` ## Related Research tokens before trading Deep-dive analytics via custom GraphQL Full CLI command reference # chainstream-graphql Skill Source: https://docs.chainstream.io/en/docs/ai-agents/agent-skills/chainstream-graphql Custom on-chain analytics — cross-cube JOINs, aggregations, time-series and complex filters ## Overview The `chainstream-graphql` skill gives AI agents flexible SQL-like access to ChainStream's on-chain data warehouse through GraphQL. It is the right tool whenever a pre-built REST/MCP endpoint is not expressive enough — cross-cube JOINs, custom aggregations, multi-condition filters, custom time-series resolution, or data only exposed via GraphQL (e.g. PolyMarket prediction cubes). * **Pattern**: Tool (read-only, no signing) * **Endpoint**: `https://graphql.chainstream.io/graphql` (routed through APISIX) * **CLI**: `npx @chainstream-io/cli graphql` * **Auth**: API Key via `X-API-KEY`, or SIWX wallet token * **Payment**: Same API Key / subscription pool as REST (x402 / MPP auto-handled by CLI) * **Scope**: 27 cubes across 3 chain groups — `Solana`, `EVM(network: eth | bsc | polygon)`, `Trading` ## When to Use Decision matrix vs `chainstream-data`: | Scenario | Use | Why | | ------------------------------------------------------ | ----------------------- | ---------------------------------------------------- | | Standard token search, market trending, wallet profile | `chainstream-data` | Pre-built REST / MCP endpoints, simpler | | Cross-cube JOIN (trades + transfers, pools + events) | **chainstream-graphql** | `joinXxx` support | | Custom aggregation (count / sum / avg with `groupBy`) | **chainstream-graphql** | Metrics + dimension grouping | | Multi-condition filters (nested, OR via `any`) | **chainstream-graphql** | Full filter operator set | | Time-series with custom resolution / buckets | **chainstream-graphql** | Time interval bucketing | | Prediction market data (PolyMarket on Polygon) | **chainstream-graphql** | `PredictionTrades / Managements / Settlements` cubes | ## Integration Path ```mermaid theme={null} flowchart TD Start["Analytics request"] --> Standard{"Fits pre-built REST/MCP?"} Standard -->|Yes| DataSkill["Use chainstream-data"] Standard -->|No| Schema["graphql schema --summary
(discover 27 cubes)"] Schema --> Drill{"Know the cube?"} Drill -->|No| Type["graphql schema --type CubeName"] Drill -->|Yes| Build["Construct query"] Type --> Build Build --> Run["graphql query --query '...' --json"] Run --> Parse["Parse JSON, summarize insights"] ``` ## Channel Matrix GraphQL is a single surface accessed from different callers: | Operation | CLI Command | SDK Method | | --------------------------- | ----------------------------------------------- | -------------------------------------------- | | List all cubes (summary) | `graphql schema --summary` | N/A — use CLI for discovery | | Drill into one cube | `graphql schema --type ` | N/A | | Full schema reference | `graphql schema --full` | N/A | | Force-refresh cached schema | `graphql schema --summary --refresh` | N/A | | Inline query | `graphql query --query ''` | `client.graphql.query(gql)` | | Query from file | `graphql query --file ./q.graphql` | `client.graphql.query(fs.readFileSync(...))` | | Query with variables | `graphql query --query '...' --var '{"k":"v"}'` | `client.graphql.query(gql, vars)` | | Machine-readable output | Append `--json` | Native JSON return | ## AI Workflows ### Discover Schema Always start here if the agent doesn't already know which cube it needs. ```bash theme={null} npx @chainstream-io/cli graphql schema --summary npx @chainstream-io/cli graphql schema --type DEXTrades ``` `--summary` returns a compact catalog of all 27 cubes grouped by chain (EVM / Solana / Trading), with top-level fields and descriptions. `--type` expands one cube's field tree for query construction. ### Construct and Run a Query The schema uses **chain group wrappers** as the top-level entry point. ```graphql theme={null} query { Solana { DEXTrades( limit: { count: 25 } orderBy: { descending: Block_Time } ) { Block { Time } Trade { Buy { Currency { MintAddress } Amount PriceInUSD } Sell { Currency { MintAddress } Amount } Dex { ProtocolName } } } } } ``` ```graphql theme={null} query { EVM(network: eth) { DEXTrades( limit: { count: 25 } orderBy: { descending: Block_Time } where: { Trade: { Buy: { Amount: { gt: "0" } } } } ) { Block { Time } Trade { Buy { Currency { Symbol } Amount } Sell { Currency { Symbol } Amount } } } } } ``` ```graphql theme={null} query { Trading { Pairs( tokenAddress: { is: "So11111111111111111111111111111111111111112" } limit: { count: 24 } ) { TimeMinute Price { Open High Low Close } } } } ``` Execute from the CLI: ```bash theme={null} npx @chainstream-io/cli graphql query --file ./query.graphql --json ``` Or inline: ```bash theme={null} npx @chainstream-io/cli graphql query \ --query 'query { Solana { DEXTrades(limit:{count:5}) { Block { Time } } } }' \ --json ``` ## Query Construction Quick Reference * **Chain group wrapper**: Top-level required. `Solana`, `EVM(network: ...)`, or `Trading`. * **`network`**: Only on `EVM`. Values: `eth`, `bsc`, `polygon`. * **`limit`**: `{ count: N, offset: M }`. Default 25. * **`orderBy`**: `{ descending: Field }` / `{ ascending: Field }`. For computed fields use `{ descendingByField: "field_name" }`. * **`where`**: `{ Group: { Field: { operator: value } } }`. OR conditions via `any: [{...}, {...}]`. * **DateTime format**: `"YYYY-MM-DD HH:MM:SS"` — **no `T`, no `Z`** (ClickHouse requirement). * **DateTime filters**: `since`, `till`, `after`, `before` — **never `gt` / `lt`** on DateTime fields. * **`joinXxx`**: LEFT JOIN to related cubes. Prefer over multiple queries. * **`dataset`** wrapper arg: `realtime`, `archive`, `combined` (default). * **`aggregates`** wrapper arg: `yes`, `no`, `only`. ## Chain Groups and Cubes | Chain Group | Wrapper | Cubes | | ----------- | ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Solana** | `Solana { ... }` | DEXTrades, DEXTradeByTokens, Transfers, BalanceUpdates, Blocks, Transactions, DEXPools, Instructions, InstructionBalanceUpdates, Rewards, DEXOrders, TokenSupplyUpdates | | **EVM** | `EVM(network: eth\|bsc\|polygon) { ... }` | DEXTrades, DEXTradeByTokens, Transfers, BalanceUpdates, Blocks, Transactions, DEXPoolEvents, Events, Calls, MinerRewards, DEXPoolSlippages, TokenHolders, TransactionBalances, Uncles, PredictionTrades\*, PredictionManagements\*, PredictionSettlements\* | | **Trading** | `Trading { ... }` | Pairs, Tokens, Currencies, Trades | \* Prediction cubes only available on `polygon` network. ## Safety Rules These rules are enforced by the skill to keep queries correct and avoid wasted quota. | Rule | Reason | | ----------------------------------------------------------------------------- | --------------------------------------------------- | | Never use a flat `CubeName(network: sol)` — always wrap in a chain group | Server rejects un-wrapped queries | | Never guess field names — run `graphql schema --type ` first | Saves a round-trip of "field does not exist" errors | | Never use ISO-8601 `"2026-03-31T00:00:00Z"` — use `"2026-03-31 00:00:00"` | ClickHouse DateTime format | | Never use `gt` / `lt` on DateTime — use `since` / `after` / `before` / `till` | DateTime filters are named | | Never split related data across multiple queries when `joinXxx` can combine | One paid request instead of many | | Never auto-select a payment plan — always let the user choose | Billing consent | ## Error Recovery | Error | Recovery | | --------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 401 / "Not authenticated" | `config auth` — if not logged in, run `login` (auto-grants the nano trial, 50K CU). Then retry. | | 402 / "Payment required" | `plan status`; if no active subscription, `wallet pricing` → `plan purchase --plan `. See [x402 payments](/en/docs/platform/billing-payments/x402-payments). | | `GraphQL error: field X does not exist` | Re-check the field against `graphql schema --type `. | | 429 | Wait 1s, exponential backoff. | | 5xx | Retry once after 2s. | ## Related Standard REST/MCP queries for token, market and wallet analytics Execute trades after analysis — swap, create token Endpoint reference, auth, schema overview `chainstream graphql schema` and `query` reference # Skills Installation Source: https://docs.chainstream.io/en/docs/ai-agents/agent-skills/installation Install ChainStream Agent Skills on Cursor, Claude Code, ClawHub, and more ## Installation Methods ChainStream skills can be installed through multiple channels depending on your agent platform. The `npx skills add` route is the fastest — one command, works across Cursor, Claude Code, Codex, OpenCode and OpenClaw. | Method | What it does | Setup Time | | ------------------------------------------------------------- | ------------------------------------------------------------------------------- | ------------ | | [`npx skills add` (recommended)](#npx-skills-add-recommended) | Cross-platform installer: adds all three ChainStream skills to the target agent | \~20 seconds | | [ClawHub](#clawhub) | Marketplace install via `openclaw skills install` | \~30 seconds | | [Cursor](#cursor) | Clone repo + `.cursor-plugin/` auto-discovery | \~1 minute | | [Claude Code](#claude-code) | `/plugin install chainstream` | \~30 seconds | | [Codex](#codex) | Git clone + symlink into `~/.agents/skills/` | \~1 minute | | [OpenCode](#opencode) | Git clone + symlink into `~/.agents/skills/` | \~1 minute | | [Gemini CLI](#gemini-cli) | `gemini extensions install` | \~30 seconds | *** ## `npx skills add` (recommended) A single command installs all three ChainStream skills (`chainstream-data`, `chainstream-graphql`, `chainstream-defi`) into the target agent. Use `-a ` to pick which agent to install into. ```bash theme={null} npx skills add chainstream-io/skills -a cursor ``` ```bash theme={null} npx skills add chainstream-io/skills -a claude-code ``` ```bash theme={null} npx skills add chainstream-io/skills -a openclaw ``` ```bash theme={null} npx skills add chainstream-io/skills -a codex ``` ```bash theme={null} npx skills add chainstream-io/skills -a opencode ``` After install, configure the API Key so the CLI and MCP tools work: ```bash theme={null} npx @chainstream-io/cli login # create wallet + get nano trial (50K CU) # or, if you already have a key: npx @chainstream-io/cli config set --key apiKey --value ``` `npx skills add` pulls the latest version of the skills on every run, so re-running it also updates. See the full OpenClaw install flow (skill verification, multi-agent targeting) in [Ecosystem → OpenClaw → Skills Install](/en/docs/ecosystem/openclaw/skills-install). *** ## ClawHub ChainStream skills are published on [ClawHub](https://clawhub.ai), the OpenClaw skill marketplace. | Skill | ClawHub URL | Version | | ------------------- | ------------------------------------------------------------------------ | ------- | | chainstream-data | [clawhub.ai/chainstream-data](https://clawhub.ai/chainstream-data) | Latest | | chainstream-graphql | [clawhub.ai/chainstream-graphql](https://clawhub.ai/chainstream-graphql) | Latest | | chainstream-defi | [clawhub.ai/chainstream-defi](https://clawhub.ai/chainstream-defi) | Latest | ```bash theme={null} # Install via ClawHub CLI openclaw skills install chainstream-data openclaw skills install chainstream-graphql openclaw skills install chainstream-defi ``` Or install from the ClawHub web UI — click **Install** on the skill page and follow the instructions. *** ## Cursor Skills are automatically discovered via the `.cursor-plugin/plugin.json` configuration included in the skills repository. ```bash theme={null} git clone https://github.com/chainstream-io/skills.git ``` Open the cloned `skills/` directory in Cursor. The `.cursor-plugin/plugin.json` tells Cursor to load the skills automatically. Set your API Key for CLI and MCP access: ```bash theme={null} npx @chainstream-io/cli config set --key apiKey --value ``` Ask your AI assistant: ``` search for meme tokens on Solana is safe to buy? swap 0.1 SOL for ``` Cursor will also publish ChainStream as a marketplace plugin. Once available, you can install directly from Cursor Settings > Extensions. *** ## Claude Code ```bash theme={null} /plugin install chainstream ``` The `.claude-plugin/plugin.json` in the skills repo provides the plugin metadata for Claude Code. Claude Code marketplace plugin is coming soon. Once published, install directly from the Claude Code plugin store. *** ## Codex ```bash theme={null} git clone https://github.com/chainstream-io/skills.git ~/.agents/skills/chainstream ``` See the instructions in `.codex/INSTALL.md` within the cloned repo. *** ## OpenCode ```bash theme={null} git clone https://github.com/chainstream-io/skills.git ~/.agents/skills/chainstream ``` See the instructions in `.opencode/INSTALL.md` within the cloned repo. *** ## Gemini CLI ```bash theme={null} gemini extensions install https://github.com/chainstream-io/skills ``` The `gemini-extension.json` in the repo root configures Gemini CLI to load the context file. *** ## MCP Server Configuration Skills work best when paired with the ChainStream MCP Server. Add this to your MCP client configuration: ```json theme={null} { "mcpServers": { "chainstream": { "url": "https://mcp.chainstream.io/mcp", "headers": { "X-API-KEY": "" } } } } ``` Add to `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows): ```json theme={null} { "mcpServers": { "chainstream": { "url": "https://mcp.chainstream.io/mcp", "headers": { "X-API-KEY": "" } } } } ``` Get your API Key from [ChainStream Dashboard](https://app.chainstream.io) or via [x402 / MPP payment](/en/docs/platform/billing-payments/x402-payments). *** ## Verify Installation After installation, test with a simple query: ```bash theme={null} # Via CLI npx @chainstream-io/cli token search --keyword PUMP --chain sol # Via AI assistant (if skills are loaded) # Ask: "search for PUMP tokens on Solana" ``` ## Next Steps Data queries: token, market, wallet Custom GraphQL analytics and JOINs DeFi execution: swap, launchpad, transaction Full `npx skills` flags and multi-agent targeting # Agent Skills Source: https://docs.chainstream.io/en/docs/ai-agents/agent-skills/introduction Structured AI capability packages for on-chain data and DeFi execution ## What Are Agent Skills Agent Skills are structured instruction packages (`SKILL.md` files) that teach AI coding assistants how to use ChainStream's on-chain data and DeFi capabilities. Unlike raw API docs, skills provide **decision trees, workflows, safety rules, and error recovery** — everything an AI agent needs to operate autonomously. **Tool pattern** — read-only on-chain data: token analytics, market trends, wallet profiling, WebSocket streams **Tool pattern** — custom GraphQL analytics over 27 cubes: cross-cube JOINs, aggregations, time-series **Process pattern** — irreversible DeFi execution: swap, launchpad, transaction broadcast ## Skills vs MCP vs SDK | Layer | What It Is | Best For | | ---------------- | ----------------------------------------------------------------------------------------- | ------------------------------------------------- | | **Agent Skills** | High-level AI instruction set (SKILL.md) with decision trees, workflows, and safety rules | AI coding assistants (Cursor, Claude Code, Codex) | | **MCP Server** | Model Context Protocol — 17 tools callable by AI models | AI chat assistants (Claude Desktop, ChatGPT) | | **CLI** | Command-line tool with wallet and x402 payment | Scripts, CI/CD, AI agents needing DeFi | | **SDK** | TypeScript/Python/Go/Rust client library | Custom applications | Skills sit at the **highest abstraction layer** — they reference MCP tools and CLI commands internally, routing the AI agent to the right tool for each task. ## Routing Decision Tree ```mermaid theme={null} flowchart TD Start["User request"] --> IsExec{"Executing transaction?"} IsExec -->|Yes| DefiSkill["chainstream-defi"] IsExec -->|No| IsData{"Reading data?"} IsData -->|No| NotCovered["Not a ChainStream task"] IsData -->|Yes| Custom{"Needs JOINs / custom
aggregation / time-series?"} Custom -->|Yes| GraphqlSkill["chainstream-graphql"] Custom -->|No| DataSkill["chainstream-data"] DataSkill --> HasMCP{"MCP configured?"} HasMCP -->|Yes| UseMCP["Use MCP tools"] HasMCP -->|No| UseCLI["Use CLI commands"] GraphqlSkill --> Schema["graphql schema --summary
graphql query --file ..."] DefiSkill --> HasWallet{"Wallet available?"} HasWallet -->|Yes| UseCLIDeFi["Use CLI for signing"] HasWallet -->|No| NeedWallet["Prompt: chainstream login"] ``` ## Skill Comparison | Aspect | chainstream-data | chainstream-graphql | chainstream-defi | | ----------------- | ------------------------------------------ | ------------------------------------------- | ------------------------------------------------------ | | Pattern | Tool (read-only) | Tool (read-only) | Process (execute) | | Risk Level | Low | Low | High (irreversible) | | Wallet Required | No (API Key sufficient) | No (API Key sufficient) | Yes (signing needed) | | MCP Support | Full (17 tools) | CLI-driven | Tools available, but execution requires wallet on host | | User Confirmation | Not required | Not required | **Mandatory** before every transaction | | Typical Actions | Search, analyze, track, stream | JOIN, aggregate, time-series, complex WHERE | Swap, create token, broadcast | | Best For | Standard analytics via pre-built endpoints | Custom analytics that REST doesn't expose | Trading, launching tokens, signing | ## Shared Resources All skills share common reference documents: | Resource | Content | | ------------------ | ---------------------------------------------------------------- | | **Authentication** | Four auth paths (API Key, wallet login, raw key, Tempo MPP) | | **x402 Payment** | x402 and MPP payment protocols, plan selection flow | | **Error Handling** | HTTP status codes, retry strategies, DeFi-specific errors | | **Chains** | Supported chains matrix, native token addresses, block explorers | ## Supported Platforms Skills work with any AI coding assistant that supports `SKILL.md` files: | Platform | Installation Method | | ----------- | ------------------------------------- | | Cursor | Auto-discovered via `.cursor-plugin/` | | Claude Code | `/plugin install chainstream` | | Codex | Clone + symlink | | OpenCode | Clone + symlink | | Gemini CLI | `gemini extensions install` | See [Installation Guide](/en/docs/ai-agents/agent-skills/installation) for setup instructions. ## Next Steps Set up skills on your platform Standard data queries and analytics Custom GraphQL analytics, JOINs, aggregations DeFi execution workflows Underlying MCP protocol # MCP Introduction Source: https://docs.chainstream.io/en/docs/ai-agents/mcp-server/introduction Learn about Model Context Protocol and ChainStream MCP Server ## What is MCP **MCP (Model Context Protocol)** is an open protocol proposed by Anthropic to standardize how AI applications connect to external data sources. Simply put, MCP enables AI to: * Discover available tools and data sources * Call external tools to perform operations * Understand returned structured data ### Traditional vs MCP | Method | Flow | | --------------- | -------------------------------------------------------------------- | | **Traditional** | User → Write code → Call API → Parse data → Input to AI → Get answer | | **MCP** | User → Natural language question → AI auto-calls tools → Get answer | ### Core Concepts | Concept | Description | | -------------- | ------------------------------------------------------------ | | **MCP Server** | Server providing tools and data, like ChainStream MCP Server | | **MCP Client** | Client using tools, like Claude Desktop, Cursor | | **Tools** | Functions callable by AI, like query balance, analyze wallet | | **Resources** | Data resources accessible by AI | *** ## Why MCP Matters ### AI Agents Need "Hands and Eyes" AI large models have powerful reasoning capabilities, but they: * ❌ Cannot directly access real-time data * ❌ Cannot execute external operations * ❌ Have knowledge cutoff dates MCP solves this by enabling AI to: * ✅ Get real-time on-chain data * ✅ Call professional tools for analysis * ✅ Interact with the external world **Analogy** MCP to AI is like: * **Eyes** → Let AI see real-time data * **Hands** → Let AI execute operations * **Tools** → Let AI use professional capabilities *** ## ChainStream MCP Capabilities ChainStream MCP Server exposes blockchain data and analysis capabilities to AI applications via the MCP protocol. **MCP Endpoint**: `https://mcp.chainstream.io/mcp` ### Capability Matrix ChainStream MCP Server supports all REST API and WebSocket subscription features in API Reference: | Feature | Description | | ------------------- | ----------------------------------- | | Token Search | Search tokens by name/symbol | | Token Info | Get token basic info and metadata | | Token Price | Real-time and historical prices | | Token Stats | Volume, market cap statistics | | Holder Analysis | Holder distribution and top holders | | Candlestick Data | OHLCV data for various periods | | Market Data | Liquidity, trading pair info | | Security Check | Token contract security analysis | | Creation Info | Token creator and time | | Mint/Burn History | Token minting and burning records | | Liquidity Snapshots | Historical liquidity data | | Feature | Description | | --------------- | --------------------------------- | | Balance Query | Wallet token balances | | PnL Calculation | Profit and loss analysis | | Wallet Stats | Transaction count, activity, etc. | | Balance History | Balance change records | | Feature | Description | | ---------------- | ---------------------------- | | Trade History | Get trade records | | Trade Activities | Real-time trading activities | | Top Traders | Top traders ranking | | Feature | Description | | ----------------- | ------------------------- | | Quote Query | Get trade quotes | | Route Calculation | Optimal trading path | | Swap Execution | Build swap transactions | | DEX List | Supported DEX information | | Feature | Description | | ------------- | -------------------------------- | | Hot Tokens | Ranking by time period | | New Tokens | Newly listed tokens | | Final Stretch | Near graduation on Bonding Curve | | Migrated | Migrated to DEX | | Subscription | Description | | --------------- | -------------------------------- | | Token Candles | Real-time candlestick updates | | Token Stats | Real-time statistics | | Token Holders | Holder changes | | New Tokens | New token creation notifications | | Wallet Balance | Real-time balance updates | | Wallet Trades | Real-time trade notifications | | Liquidity Pools | Pool balance changes | ### Supported Blockchains | Chain | Identifier | Type | Status | | -------- | ---------- | ---- | ------ | | Solana | `sol` | L1 | ✅ | | Ethereum | `eth` | L1 | ✅ | | BSC | `bsc` | L1 | ✅ | Use lowercase chain identifiers in all MCP tool parameters: `sol`, `eth`, `bsc`. *** ## Supported Platforms ### Claude Desktop Officially supported MCP client with the most complete feature support. | Feature | Status | | ------------------ | ------ | | Tool Calling | ✅ | | Multi-turn Dialog | ✅ | | Streaming Response | ✅ | ```json theme={null} // claude_desktop_config.json { "mcpServers": { "chainstream": { "url": "https://mcp.chainstream.io/mcp", "headers": { "X-API-KEY": "your-api-key" } } } } ``` ### Cursor IDE Developer-friendly AI coding assistant with MCP integration. | Feature | Status | | ------------ | ------ | | Tool Calling | ✅ | | Code Context | ✅ | ```json theme={null} // .cursor/mcp.json { "mcpServers": { "chainstream": { "url": "https://mcp.chainstream.io/mcp", "headers": { "X-API-KEY": "your-api-key" } } } } ``` ### Custom Agent Any client following MCP protocol can integrate. ```javascript theme={null} import { Client } from '@modelcontextprotocol/sdk/client/index.js'; import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js'; const transport = new StreamableHTTPClientTransport( new URL('https://mcp.chainstream.io/mcp'), { requestInit: { headers: { 'X-API-KEY': process.env.CHAINSTREAM_API_KEY } } } ); const client = new Client({ name: 'my-agent', version: '1.0.0' }); await client.connect(transport); // List available tools const { tools } = await client.listTools(); // Call a tool const result = await client.callTool({ name: 'wallets_profile', arguments: { address: '0x...', chain: 'eth' } }); ``` *** ## Typical Use Cases ### Case 1: AI Research Assistant **Need**: Use AI to analyze a specific wallet's trading behavior Analyze the trading style of address `0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045` Calls `wallets_profile` tool Based on analysis, this address (Vitalik) characteristics: * Wallet age: Over 5 years * Main holdings: ETH, various ERC-20 Tokens * Trading style: Long-term holding, occasional donations and project support * Active protocols: Uniswap, ENS, Gitcoin * Labels: Core developer, Philanthropist ### Case 2: Smart Money Tracking **Need**: Track Smart Money large trades Which Smart Money addresses have been buying ARB in the last 24 hours? Calls `market_trending` tool In the past 24 hours, the following Smart Money addresses bought ARB: 1. `0xabc...123` (Labels: whale, defi\_expert) * Amount: 500,000 ARB * Value: \$450,000 * Time: 2 hours ago 2. `0xdef...456` (Labels: institution) * Amount: 200,000 ARB * Value: \$180,000 * Time: 5 hours ago Overall trend: Smart Money net buying ARB ### Case 3: Token Security Analysis **Need**: Analyze token security Help me check if this token `0x...` is safe Calls `tokens_analyze` tool Token security check results: | Check Item | Result | | ---------------------- | ------------------ | | Contract Verified | ✅ | | No Malicious Functions | ✅ | | Liquidity Locked | ✅ | | Holder Distribution | ⚠️ Top 10 hold 45% | | Trading Tax | Buy 1% / Sell 1% | Risk Level: Medium (watch holder concentration) *** ## Technical Architecture ```mermaid theme={null} sequenceDiagram participant User participant AI as AI Client
(Claude / Cursor) participant MCP as ChainStream MCP
(17 Tools) participant API as ChainStream API
(SOL / ETH / BSC) User->>AI: "Is this token safe to buy?" AI->>AI: Select tokens_analyze tool AI->>MCP: tokens_analyze(chain, address) MCP->>API: GET /v2/token/{chain}/{address} MCP->>API: GET /v2/token/{chain}/{address}/security MCP->>API: GET /v2/token/{chain}/{address}/topHolders API-->>MCP: Token data + security flags + holders MCP-->>AI: Structured analysis result AI-->>User: "This token has no honeypot risk,
top 10 holders own 35%..." ``` ### Connection Modes | Mode | Endpoint | Best For | | ------------- | ---------------------------------- | ---------------------------------------------- | | **Cloud** | `https://mcp.chainstream.io/mcp` | Zero setup, always up-to-date | | **npm stdio** | `npx @chainstream-io/mcp` | Local IDE integration (Claude Desktop, Cursor) | | **npm HTTP** | `chainstream-mcp --transport http` | Team servers, cloud deployment | *** ## Difference from Traditional API | Feature | Traditional API | MCP | | ------------------ | ------------------- | -------------------------- | | Call Method | HTTP REST | Protocol Standardized | | Target User | Developers | AI Models | | Parameter Handling | Manual Construction | AI Auto-inference | | Error Handling | Status Codes | Semantic Errors | | Context | Stateless | Session Context Maintained | *** ## Authentication ChainStream MCP Server authenticates via **API Key**. Get your key from the [ChainStream Dashboard](https://www.chainstream.io/dashboard) and configure it based on your transport: | Transport | How to Pass API Key | | ----------------------- | ------------------------------------------------------------------ | | **npm package** (stdio) | `CHAINSTREAM_API_KEY` environment variable or `--api-key` CLI flag | | **Cloud endpoint** | `X-API-KEY` request header | ```bash theme={null} # Stdio: set env var export CHAINSTREAM_API_KEY=your-key chainstream-mcp # Stdio: or use CLI flag chainstream-mcp --api-key your-key ``` API Keys do not expire unless you set an expiration in the Dashboard. No token refresh is needed. *** ## Security Model Both connection modes authenticate via API Key. The npm package reads `CHAINSTREAM_API_KEY` from the environment. The cloud endpoint accepts the `X-API-KEY` header. Tools are categorized by risk level: * **Read-only tools**: Token search, wallet profile, market data — safe by default * **Trading tools** (`dex_swap`, `dex_create_token`, `transaction_send`): Marked as HIGH RISK, MCP clients should require explicit user confirmation All tool calls are fully logged and viewable in Dashboard. *** ## Next Steps Configure MCP Server in 5 minutes View all available tool details # MCP Setup Guide Source: https://docs.chainstream.io/en/docs/ai-agents/mcp-server/setup Complete ChainStream MCP Server setup in 5 minutes This guide helps you quickly configure ChainStream MCP Server. *** ## Prerequisites | Requirement | Details | How to Get | | ------------------- | --------------------------------------- | ----------------------------------------------- | | ChainStream Account | Registered account | [Sign up](https://www.chainstream.io/dashboard) | | API Key | `X-API-KEY` for authentication | Dashboard → Apps → Create App | | AI Client | Claude Desktop / Cursor / Custom client | Installed | *** ## MCP Endpoint ChainStream provides a hosted MCP Server. No local installation required — connect directly via: ``` https://mcp.chainstream.io/mcp ``` *** ## Configuration Steps 1. Log in to [ChainStream Dashboard](https://www.chainstream.io/dashboard) 2. Navigate to **Applications** 3. Click **Create New App** and copy your API Key **Config file path**: * macOS: `~/Library/Application Support/Claude/claude_desktop_config.json` * Windows: `%APPDATA%\Claude\claude_desktop_config.json` **Option A — Cloud endpoint (recommended)**: ```json theme={null} { "mcpServers": { "chainstream": { "url": "https://mcp.chainstream.io/mcp", "headers": { "X-API-KEY": "your_api_key" } } } } ``` **Option B — Local npm package (stdio)**: ```json theme={null} { "mcpServers": { "chainstream": { "command": "npx", "args": ["@chainstream-io/mcp"], "env": { "CHAINSTREAM_API_KEY": "your_api_key" } } } } ``` If the file doesn't exist, create it manually. If you have other MCP Server configurations, add the `chainstream` config to the existing `mcpServers` object. **Config file path**: `.cursor/mcp.json` (project-level) or Cursor Settings → Features → MCP Servers **Option A — Cloud endpoint**: ```json theme={null} { "mcpServers": { "chainstream": { "url": "https://mcp.chainstream.io/mcp", "headers": { "X-API-KEY": "your_api_key" } } } } ``` **Option B — Local npm package (stdio)**: ```json theme={null} { "mcpServers": { "chainstream": { "command": "npx", "args": ["@chainstream-io/mcp"], "env": { "CHAINSTREAM_API_KEY": "your_api_key" } } } } ``` Connect to the cloud endpoint via HTTP: | Endpoint | URL | Method | | ------------ | -------------------------------- | ------ | | MCP Endpoint | `https://mcp.chainstream.io/mcp` | POST | **Authentication**: pass API Key via `X-API-KEY` header. **Example Code**: ```javascript theme={null} import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js'; import { Client } from '@modelcontextprotocol/sdk/client/index.js'; const transport = new StreamableHTTPClientTransport( new URL('https://mcp.chainstream.io/mcp'), { requestInit: { headers: { 'X-API-KEY': process.env.CHAINSTREAM_API_KEY } } } ); const client = new Client({ name: 'my-client', version: '1.0.0' }); await client.connect(transport); const { tools } = await client.listTools(); console.log('Available tools:', tools.map(t => t.name)); ``` After configuration, completely quit and restart your AI client for changes to take effect. * **Claude Desktop**: Fully quit (not just minimize), then reopen * **Cursor**: Restart the IDE *** ## Verify Configuration ### Test Command Enter the following test question in your AI client: ``` What is the SOL token on Solana? Is it safe? ``` ### Expected Result If configured successfully, the AI should: 1. Call `tokens_search` to find the SOL token 2. Call `tokens_analyze` to get security and holder data 3. Return a natural language summary If the AI doesn't call the tool or returns an error, refer to [Troubleshooting](#troubleshooting) below. *** ## Troubleshooting **Possible causes**: 1. **API Key entered incorrectly** * Check for extra spaces * Confirm complete copy 2. **API Key revoked or expired** * Check key status in Dashboard * Create a new key if needed 3. **Wrong header name** * Cloud endpoint: use `X-API-KEY` header * npm package: use `CHAINSTREAM_API_KEY` env var **Solutions**: * Verify key in Dashboard → Applications * Test directly: `curl -H "X-API-KEY: your_key" https://api.chainstream.io/v2/blockchain` **Possible causes**: 1. **Network issues** * Check network connection * Confirm access to `https://mcp.chainstream.io` 2. **Configuration format error** * Check JSON format is correct * Confirm URL spelling is correct **Solution**: ```bash theme={null} curl -I https://mcp.chainstream.io/mcp ``` **Possible causes**: 1. **Config file path incorrect** * macOS: `~/Library/Application Support/Claude/claude_desktop_config.json` * Windows: `%APPDATA%\Claude\claude_desktop_config.json` 2. **JSON format error** * Use a JSON validator to check 3. **Client not restarted** * Fully quit and restart **Solution**: ```bash theme={null} cat ~/Library/Application\ Support/Claude/claude_desktop_config.json | python -m json.tool ``` **Possible causes**: 1. Plan quota exhausted 2. Request rate too high, triggering rate limit **Solutions**: * Check quota usage in Dashboard * Upgrade plan for more quota **Possible causes**: 1. Network latency 2. Query data volume too large **Solutions**: * Check network connection * Reduce data volume per query * Try again later *** ## Next Steps View all available tools and usage examples Build an AI trading assistant # Tools Catalog Source: https://docs.chainstream.io/en/docs/ai-agents/mcp-server/tools ChainStream MCP Server complete tools reference ChainStream MCP Server supports all interfaces defined in the API Reference. AI can directly call these tools to fetch on-chain data. MCP tool parameters and return values are identical to the REST API. For detailed field descriptions, refer to [API Reference](/en/api-reference/authentication/authenticate). *** ## Tools Overview | Tool Category | Functions | | ------------- | ----------------------------------------------------------- | | Token | Token search, info, price, candles, holders, security check | | Wallet | Balance, PnL, stats, balance updates | | Trade | Trade records, activities, top traders | | DexPool | Pool info, snapshots | | Ranking | Hot tokens, new tokens, final stretch, migrated | | Blockchain | Chain info, latest block | | Tool Category | Functions | | ------------- | -------------------------------- | | Dex | Quote, route, swap execution | | DeFi | Create token on Pumpfun/Moonshot | | Transaction | Send transaction, gas estimation | | RedPacket | Create/claim red packets | | Tool Category | Functions | | ------------- | --------------------------------------- | | Webhook | Endpoint management, event subscription | | Blockchain | Supported chains, latest block | | Subscription Type | Functions | | ----------------- | -------------------------------- | | Candles | Real-time price trends | | Token Stats | Real-time trading statistics | | New Tokens | New token creation notifications | | Wallet Balance | Balance change notifications | | Trade Activities | Real-time trade stream | | Pool | Pool state changes | *** ## Token Tools ### token\_search Search for tokens. ``` Search for PEPE-related tokens ``` ### token\_get Get token details. ``` View details of token So11111111111111111111111111111111111111112 ``` ### token\_get\_metadata Get token metadata (name, symbol, logo, etc.). ``` Get this token's logo and social media links ``` ### token\_get\_stats Get token statistics (volume, buy/sell counts, etc.). ``` View this token's trading statistics for the past 24 hours ``` ### token\_get\_price Get current token price. ``` What's the current price of BONK? ``` ### token\_get\_prices Get token price history. ``` View ETH price trend over the past week ``` ### token\_get\_candles Get token candlestick data. ``` Get the last 100 hourly candles for SOL ``` ### token\_get\_holders Get token holder information. ``` How many holders does this token have? ``` ### token\_get\_top\_holders Get top token holders list. ``` View the top 10 holders of this token ``` ### token\_get\_pools Get liquidity pools for a token. ``` Which DEXes have liquidity pools for this token? ``` ### token\_get\_security Get token security check results. ``` Check if this token is safe ``` ### token\_get\_creation Get token creation information. ``` When was this token created? Who created it? ``` ### token\_get\_mint\_and\_burn Get token mint and burn history. ``` View mint and burn history for this token ``` ### token\_list Get token list (with pagination and filters). ``` List recently created tokens on Solana ``` ### token\_get\_traders\_tag Get trader tag distribution for a token. ``` Analyze what types of traders are trading this token ``` ### token\_get\_liquidity\_snapshots Get token liquidity snapshots. ``` View this token's liquidity changes over the past week ``` ### token\_dev\_get\_tokens Get all tokens created by a developer. ``` What other tokens has this developer created? ``` *** ## Wallet Tools ### wallet\_get\_balance Get wallet balance. ``` Query all token balances for address 0x1234...abcd ``` ### wallet\_get\_balance\_updates Get wallet balance change history. ``` Show recent fund movements for this wallet ``` ### wallet\_get\_pnl Get wallet profit and loss data. ``` Calculate total returns and win rate for this address ``` ### wallet\_calculate\_pnl Calculate wallet PnL for specific conditions. ``` Calculate this address's returns over the past 30 days ``` ### wallet\_get\_stats Get wallet statistics. ``` Analyze this wallet's trading style and activity level ``` *** ## Trade Tools ### trade\_get Get trade records. ``` View the last 20 trades for 0x... ``` ### trade\_get\_activities Get trade activity stream. ``` Recent trading activities for this token ``` ### trade\_get\_top\_traders Get top traders. ``` View the most profitable traders for this token ``` *** ## DexPool Tools ### dexpool\_get Get pool information. ``` View details of this pool ``` ### dexpool\_get\_snapshots Get pool snapshot history. ``` This pool's liquidity changes over the past 24 hours ``` *** ## Ranking Tools ### ranking\_get\_hot\_tokens Get hot tokens ranking. ``` Top 10 hottest tokens today ``` ### ranking\_get\_new\_tokens Get new tokens list. ``` Tokens created in the last hour ``` ### ranking\_get\_stocks Get stock tokens (not graduated). ``` Which tokens are still on bonding curve on Pump.fun ``` ### ranking\_get\_final\_stretch Get tokens about to graduate. ``` Which tokens are about to graduate from Pump.fun ``` ### ranking\_get\_migrated Get graduated tokens list. ``` Recently graduated tokens to Raydium ``` *** ## Blockchain Tools ### blockchain\_list Get supported blockchain list. ``` Which blockchains does ChainStream support? ``` ### blockchain\_get\_latest\_block Get latest block information. ``` What's the latest block number on Ethereum? ``` *** ## Dex Tools ### dex\_list Get supported DEX list. ``` Which DEXes are supported on Solana? ``` ### dex\_get\_quote Get trade quote. ``` How much USDC can I get for 1 SOL? ``` ### dex\_get\_route Get optimal trade route. ``` Find the best route from ETH to ARB ``` ### dex\_swap Execute token swap. ``` Swap 0.5 SOL to BONK for me ``` ### dex\_create Create transaction (requires signing). ``` Create a transaction from USDC to ETH ``` *** ## DeFi Tools ### pumpfun\_create Create token on Pump.fun. ``` Create a new token on Pump.fun ``` ### moonshot\_create Create token on Moonshot. ``` Create a token on Moonshot ``` ### moonshot\_submit\_create\_token Submit Moonshot token creation transaction. ``` Submit Moonshot token creation transaction ``` *** ## Transaction Tools ### transaction\_send Send signed transaction. ``` Send this transaction ``` ### transaction\_get\_gas\_price Get current gas price. ``` What's the gas price on Ethereum right now? ``` ### transaction\_estimate\_gas\_limit Estimate transaction gas limit. ``` Estimate how much gas this transaction needs ``` *** ## RedPacket Tools ### redpacket\_create Create red packet. ``` Create a red packet with 10 SOL, split into 100 shares ``` ### redpacket\_claim Claim red packet. ``` Claim this red packet ``` ### redpacket\_get Get red packet information. ``` View details of this red packet ``` ### redpacket\_get\_claims Get red packet claim records. ``` Who claimed this red packet? ``` *** ## Webhook Tools ### webhook\_list\_endpoints Get configured webhook endpoints list. ``` View all my configured webhooks ``` ### webhook\_create\_endpoint Create new webhook endpoint. ``` Create a new webhook to receive token creation events ``` ### webhook\_update\_endpoint Update webhook endpoint configuration. ``` Update this webhook's callback URL ``` ### webhook\_delete\_endpoint Delete webhook endpoint. ``` Delete this webhook ``` ### webhook\_get\_secret Get webhook signing secret. ``` Get the signing secret for this webhook ``` ### webhook\_rotate\_secret Rotate webhook signing secret. ``` Regenerate this webhook's secret ``` *** ## WebSocket Subscriptions MCP service also supports WebSocket real-time subscriptions for the following data: ### Subscription Types | Type | Description | Example Prompt | | ---------------- | ----------------------- | -------------------------------------------------- | | Candles | Real-time price candles | "Subscribe to 1-minute candles for this token" | | Token Stats | Real-time trading stats | "Monitor trading data for this token in real-time" | | New Tokens | New token notifications | "Notify me of new tokens on Solana" | | Token Metadata | New token metadata | "Get detailed info for new tokens" | | Wallet Balance | Balance changes | "Monitor balance changes for this wallet" | | Wallet Trades | Trade notifications | "Notify me when this wallet makes a trade" | | Trade Activities | Real-time trade stream | "Show real-time trades for this token" | | Pool | Pool state | "Monitor liquidity changes for this pool" | | Rankings | Hot tokens updates | "Real-time hot token rankings update" | For detailed WebSocket subscription parameters and response formats, refer to [WebSocket API docs](/en/api-reference/endpoint/websocket/api). *** ## Supported Blockchains | Chain | Identifier | Type | | -------- | ---------- | -------- | | Solana | `sol` | L1 | | Ethereum | `eth` | L1 (EVM) | | BSC | `bsc` | L1 (EVM) | *** ## Prompt Best Practices ### Specify the Chain ``` ✅ Good: Query balance of 0x... on Ethereum ❌ Bad: Query balance of 0x... ``` ### Provide Full Address ``` ✅ Good: Analyze 0x1234567890abcdef1234567890abcdef12345678 ❌ Bad: Analyze 0x1234...5678 ``` ### Specify Time Range ``` ✅ Good: View trade records from the past 7 days ❌ Bad: View recent trades ``` ### Break Down Complex Tasks Split complex tasks into simpler questions: ``` ✅ Good: 1. First query this address's holdings 2. Then analyze its trade history 3. Finally determine its investment style ❌ Bad: Tell me everything about this address ``` ### Use Context for Follow-ups ``` User: Query holdings of 0x... AI: [Returns holdings list] User: Which of these tokens has the highest gain? User: Analyze reasons for holding PEPE ``` *** ## Related Documentation Learn about MCP protocol and capabilities Configure MCP Server Complete REST API documentation Real-time data subscriptions # AI Agents Source: https://docs.chainstream.io/en/docs/ai-agents/overview ChainStream's data and execution surfaces for AI agents — MCP Server, Agent Skills, CLI, and pay-per-call micropayments. ChainStream exposes the same [data products](/en/docs/data-products/overview) and execution primitives to AI agents as to any other client — but with the authentication, tool discovery and pay-per-call patterns that agents actually need. **AI Agents is a consumer surface, not a separate product.** Everything an agent can do is also available over REST, GraphQL, WebSocket, Kafka, the SDKs and the CLI. The pages in this section describe the shapes that make the catalog usable from LLMs. ## Two main surfaces A hosted (and self-hostable) Model Context Protocol server that exposes ChainStream's catalog as typed tools. Works out-of-the-box with Claude, Cursor, ChatGPT, Windsurf and any MCP-compatible client. Installable SKILL.md packs that teach an agent how to use ChainStream — three skills cover standard data (`chainstream-data`), custom GraphQL analytics (`chainstream-graphql`) and DeFi execution (`chainstream-defi`). Ships ready for Cursor, Claude Code and Codex. ## Why this matters for agents Traditional LLM access to blockchains fails in three ways: the model has a knowledge cutoff, it has no authenticated data source, and it cannot pay for reads without a pre-registered account. ChainStream solves each: Every data product is reachable as a structured tool call with a JSON schema. The agent gets canonical IDs, not screen-scraped text — so it can chain calls without re-parsing on every step. API keys work, OAuth works, and for autonomous agents there is [x402 / MPP](/en/docs/platform/billing-payments/x402-payments) — a per-call HTTP payment scheme that means an agent can pay in USDC and call immediately, with no prior account setup. DEX quotes, routing and swap submission are all available. Writes still require a signed transaction from a user-controlled wallet — agents can prepare transactions but not silently send from someone else's funds. ## Which surface should I pick? | Situation | Surface | | :------------------------------------------------------------------- | :------------------------------------------------------------------------------- | | You are using Claude / Cursor / ChatGPT and want ChainStream tools | [MCP Server](/en/docs/ai-agents/mcp-server/introduction) | | You want to install a ready-made agent skill for token research | [chainstream-data skill](/en/docs/ai-agents/agent-skills/chainstream-data) | | You need cross-cube JOINs, custom aggregations or time-series | [chainstream-graphql skill](/en/docs/ai-agents/agent-skills/chainstream-graphql) | | You want the agent to execute swaps / create tokens | [chainstream-defi skill](/en/docs/ai-agents/agent-skills/chainstream-defi) | | You are writing your own agent in Python / TS and want direct access | [SDKs](/en/sdks/overview) | | You want pay-per-call with USDC and no signup | [x402 Payments](/en/docs/platform/billing-payments/x402-payments) | | You want to pay with Tempo / Stripe / stablecoins | [MPP Payments](/en/docs/platform/billing-payments/mpp-payments) | | You want shell-native tools the agent can orchestrate | [CLI](/en/docs/access-methods/cli) | ## Quickstart for agents ```bash theme={null} CHAINSTREAM_API_KEY=your_api_key npx @chainstream-io/mcp ``` Full configuration snippets for Claude Desktop, Cursor and ChatGPT are in [MCP Server Setup](/en/docs/ai-agents/mcp-server/setup). *"Show me the top 10 Solana tokens by 24h volume and highlight any with KYT warnings."* The agent picks the right tools and chains the calls. ## Next How the MCP Server is organized and what tools it exposes. What Skills are, how they are installed and how to author new ones. HTTP-native micropayments for agent workloads. Build an agent end-to-end using ChainStream. # Compliance Integration Guide Source: https://docs.chainstream.io/en/docs/compliance/integration-guide Complete guide for integrating enterprise KYT/KYA compliance capabilities This guide covers how to integrate ChainStream KYT/KYA compliance capabilities into your application, including complete scenarios for CEX deposit/withdrawal risk control, wallet risk alerts, and batch screening. *** ## Prerequisites ### API Configuration | Config | Value | | :---------- | :------------------------------- | | Base URL | `https://api.chainstream.io/` | | Auth Domain | `dex.asia.auth.chainstream.io` | | Audience | `https://api.dex.chainstream.io` | ### KYT Related Scopes | Scope | Description | | :---------- | :------------------------------------------------------- | | `kyt.read` | KYT API read permission (query transaction risk) | | `kyt.write` | KYT API write permission (register transaction analysis) | ### Generate Access Token ```javascript JavaScript theme={null} import { AuthenticationClient } from 'auth0'; const auth0Client = new AuthenticationClient({ domain: 'dex.asia.auth.chainstream.io', clientId: 'your-client-id', clientSecret: 'your-client-secret' }); // Get Token with full KYT permissions const response = await auth0Client.oauth.clientCredentialsGrant({ audience: 'https://api.dex.chainstream.io', scope: 'kyt.read kyt.write' }); const accessToken = response.data.access_token; ``` ```python Python theme={null} from auth0.authentication import GetToken get_token = GetToken( 'dex.asia.auth.chainstream.io', 'your-client-id', client_secret='your-client-secret' ) token = get_token.client_credentials( audience='https://api.dex.chainstream.io', scope='kyt.read kyt.write' ) access_token = token['access_token'] ``` ### API Calls All requests must include the Token in the Header: ```javascript theme={null} const response = await fetch('https://api.chainstream.io/v1/kyt/transfer', { method: 'POST', headers: { 'Authorization': `Bearer ${accessToken}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ /* request body */ }) }); ``` *** ## CEX Deposit Risk Control Exchange deposit scenarios are the core use case for KYT, requiring risk assessment before funds are credited. ### Business Flow ```mermaid theme={null} flowchart TD A[On-chain Transaction Detected] --> B[Register Transaction to KYT] B --> C[Get Risk Assessment] C --> D{Risk Level Judgment} D -->|SEVERE| E[Freeze Funds + Compliance Report] D -->|HIGH| F[Delayed Credit + Manual Review] D -->|MEDIUM| G[Normal Credit + Flag for Monitoring] D -->|LOW| H[Normal Credit] ``` ### Integration Steps ```javascript theme={null} import { AuthenticationClient } from 'auth0'; // Generate Token (recommend caching, refresh before expiry) async function getAccessToken() { const auth0Client = new AuthenticationClient({ domain: 'dex.asia.auth.chainstream.io', clientId: process.env.CHAINSTREAM_CLIENT_ID, clientSecret: process.env.CHAINSTREAM_CLIENT_SECRET }); const { data } = await auth0Client.oauth.clientCredentialsGrant({ audience: 'https://api.dex.chainstream.io', scope: 'kyt.read kyt.write' }); return data.access_token; } ``` Monitor incoming transactions to user deposit addresses: ```javascript theme={null} async function onDepositDetected(tx) { const deposit = { network: 'ethereum', // Network: bitcoin, ethereum, Solana asset: tx.asset, // Asset type: ETH, SOL, etc. transferReference: tx.hash, // Transaction hash direction: 'received' // Direction: sent or received }; // Call KYT analysis const result = await registerTransfer(deposit); // Get risk assessment const risk = await getTransferSummary(result.externalId); // Execute decision await executeDecision(tx, risk); } ``` Call KYT API to register transaction: ```javascript theme={null} async function registerTransfer(deposit) { const response = await fetch('https://api.chainstream.io/v1/kyt/transfer', { method: 'POST', headers: { 'Authorization': `Bearer ${accessToken}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ network: deposit.network, asset: deposit.asset, transferReference: deposit.transferReference, direction: deposit.direction }) }); return await response.json(); } ``` Query transaction risk summary: ```javascript theme={null} async function getTransferSummary(transferId) { const response = await fetch( `https://api.chainstream.io/v1/kyt/transfers/${transferId}/summary`, { headers: { 'Authorization': `Bearer ${accessToken}` } } ); return await response.json(); } ``` Execute appropriate actions based on risk level: ```javascript theme={null} async function executeDecision(tx, risk) { const riskLevel = risk.rating; // SEVERE, HIGH, MEDIUM, LOW switch (riskLevel) { case 'SEVERE': await freezeDeposit(tx); await createSARReport(tx, risk); await notifyCompliance(tx, risk); break; case 'HIGH': await holdDeposit(tx, { hours: 24 }); await createManualReview(tx, risk); break; case 'MEDIUM': await creditDeposit(tx); await flagForMonitoring(tx, risk); break; case 'LOW': await creditDeposit(tx); break; } // Record audit log await auditLog.record({ action: 'DEPOSIT_RISK_DECISION', txHash: tx.hash, riskLevel, timestamp: new Date() }); } ``` *** ## Complete Flow Details The end-to-end compliance integration flow covers: Detect → Register → Poll → Risk Judgment → Release/Freeze ### 1. Detection Phase | Trigger Source | Description | Latency | | :------------------ | :------------------------ | :---------------------- | | On-chain Monitoring | Monitor deposit addresses | Block confirmation time | | User Submission | Withdrawal request | Instant | | Scheduled Scan | Catch-up mechanism | Configurable | ### 2. Registration Phase ```bash theme={null} POST https://api.chainstream.io/v1/kyt/transfer Authorization: Bearer Content-Type: application/json { "network": "ethereum", "asset": "ETH", "transferReference": "0x1234567890abcdef...", "direction": "received" } ``` **Response:** ```json theme={null} { "externalId": "123e4567-e89b-12d3-a456-426614174000", "asset": "ETH", "network": "ethereum", "transferReference": "0x1234567890abcdef...", "direction": "received", "updatedAt": "2024-01-15T10:30:00.000Z" } ``` ### 3. Query Phase ```javascript theme={null} async function pollForResult(transferId, maxAttempts = 10) { for (let i = 0; i < maxAttempts; i++) { const response = await fetch( `https://api.chainstream.io/v1/kyt/transfers/${transferId}/summary`, { headers: { 'Authorization': `Bearer ${accessToken}` } } ); const data = await response.json(); if (data.rating) { return data; } await new Promise(r => setTimeout(r, 3000)); // 3 second interval } throw new Error('Analysis timeout'); } ``` Get risk exposure details: ```javascript theme={null} // Get direct risk exposures const exposures = await fetch( `https://api.chainstream.io/v1/kyt/transfers/${transferId}/exposures/direct`, { headers: { 'Authorization': `Bearer ${accessToken}` } } ); // Get risk alerts const alerts = await fetch( `https://api.chainstream.io/v1/kyt/transfers/${transferId}/alerts`, { headers: { 'Authorization': `Bearer ${accessToken}` } } ); ``` ### 4. Judgment Phase Risk judgment rule configuration: ```yaml theme={null} risk_rules: severe: action: FREEZE auto_execute: true notify: - compliance@company.com - security@company.com high: action: MANUAL_REVIEW auto_execute: false hold_period: 24h escalation: 4h medium: action: FLAG auto_execute: true monitoring_period: 30d low: action: PASS auto_execute: true ``` ### 5. Execution Phase | Action | Trigger Condition | Follow-up | | :------ | :---------------- | :----------------------------- | | Release | LOW risk | Normal credit/payment | | Flag | MEDIUM risk | Credit but continue monitoring | | Hold | HIGH risk | Enter manual review queue | | Freeze | SEVERE risk | Freeze + Compliance report | *** ## Complete Service Implementation ```javascript JavaScript theme={null} import { AuthenticationClient } from 'auth0'; class ComplianceService { constructor() { this.accessToken = null; this.tokenExpiry = null; } // Get or refresh Token async getAccessToken() { if (this.accessToken && this.tokenExpiry > Date.now()) { return this.accessToken; } const auth0Client = new AuthenticationClient({ domain: 'dex.asia.auth.chainstream.io', clientId: process.env.CHAINSTREAM_CLIENT_ID, clientSecret: process.env.CHAINSTREAM_CLIENT_SECRET }); const { data } = await auth0Client.oauth.clientCredentialsGrant({ audience: 'https://api.dex.chainstream.io', scope: 'kyt.read kyt.write' }); this.accessToken = data.access_token; // Token usually valid 24 hours, refresh 1 hour early this.tokenExpiry = Date.now() + (23 * 60 * 60 * 1000); return this.accessToken; } // Deposit compliance check async checkDeposit(deposit) { const token = await this.getAccessToken(); // 1. Register transaction const registerResponse = await fetch('https://api.chainstream.io/v1/kyt/transfer', { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ network: deposit.network, asset: deposit.asset, transferReference: deposit.txHash, direction: 'received' }) }); const registered = await registerResponse.json(); // 2. Wait and get risk assessment const risk = await this.waitForAnalysis(token, registered.externalId); // 3. Generate decision const decision = this.makeDecision(risk); // 4. Record audit await this.auditLog(deposit, risk, decision); return decision; } async waitForAnalysis(token, transferId, maxAttempts = 10) { for (let i = 0; i < maxAttempts; i++) { const response = await fetch( `https://api.chainstream.io/v1/kyt/transfers/${transferId}/summary`, { headers: { 'Authorization': `Bearer ${token}` } } ); const result = await response.json(); if (result.rating) { return result; } await new Promise(r => setTimeout(r, 3000)); } throw new Error('Analysis timeout'); } makeDecision(risk) { const decisions = { 'SEVERE': { action: 'FREEZE', requireSAR: true, notify: ['compliance@company.com', 'security@company.com'] }, 'HIGH': { action: 'HOLD', requireReview: true, holdHours: 24 }, 'MEDIUM': { action: 'PASS', flagMonitoring: true }, 'LOW': { action: 'PASS' } }; return decisions[risk.rating] || decisions['LOW']; } async auditLog(deposit, risk, decision) { console.log({ timestamp: new Date().toISOString(), type: 'COMPLIANCE_CHECK', deposit, risk, decision }); } } // Usage example const compliance = new ComplianceService(); app.post('/deposit/process', async (req, res) => { const deposit = req.body; const decision = await compliance.checkDeposit(deposit); res.json(decision); }); ``` ```python Python theme={null} import os import time import requests from auth0.authentication import GetToken class ComplianceService: def __init__(self): self.access_token = None self.token_expiry = 0 self.base_url = 'https://api.chainstream.io' def get_access_token(self): if self.access_token and self.token_expiry > time.time(): return self.access_token get_token = GetToken( 'dex.asia.auth.chainstream.io', os.environ['CHAINSTREAM_CLIENT_ID'], client_secret=os.environ['CHAINSTREAM_CLIENT_SECRET'] ) token = get_token.client_credentials( audience='https://api.dex.chainstream.io', scope='kyt.read kyt.write' ) self.access_token = token['access_token'] self.token_expiry = time.time() + (23 * 60 * 60) return self.access_token def check_deposit(self, deposit: dict) -> dict: token = self.get_access_token() headers = { 'Authorization': f'Bearer {token}', 'Content-Type': 'application/json' } # Register transaction register_response = requests.post( f'{self.base_url}/v1/kyt/transfer', headers=headers, json={ 'network': deposit['network'], 'asset': deposit['asset'], 'transferReference': deposit['tx_hash'], 'direction': 'received' } ) registered = register_response.json() # Wait for result risk = self.wait_for_analysis(token, registered['externalId']) # Return decision return self.make_decision(risk['rating']) def wait_for_analysis(self, token, transfer_id, max_attempts=10): headers = {'Authorization': f'Bearer {token}'} for _ in range(max_attempts): response = requests.get( f'{self.base_url}/v1/kyt/transfers/{transfer_id}/summary', headers=headers ) result = response.json() if result.get('rating'): return result time.sleep(3) raise Exception('Analysis timeout') def make_decision(self, rating): decisions = { 'SEVERE': {'action': 'FREEZE', 'requireSAR': True}, 'HIGH': {'action': 'HOLD', 'requireReview': True}, 'MEDIUM': {'action': 'PASS', 'flagMonitoring': True}, 'LOW': {'action': 'PASS'} } return decisions.get(rating, decisions['LOW']) ``` *** ## CEX Withdrawal Risk Control Withdrawal scenarios require checking the risk of the destination address when users initiate withdrawals. ### Business Flow ```mermaid theme={null} flowchart TD A[User Withdrawal Request] --> B[Register Target Address] B --> C[Get Address Risk] C --> D{Risk Level Judgment} D -->|SEVERE| E[Block Withdrawal] D -->|HIGH| F[Require Confirmation] D -->|MEDIUM/LOW| G[Release Withdrawal] ``` ### Implementation Example ```javascript theme={null} async function handleWithdrawal(request) { const { toAddress } = request; const token = await complianceService.getAccessToken(); // 1. Register address const registerResponse = await fetch('https://api.chainstream.io/v1/kyt/address', { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ address: toAddress }) }); await registerResponse.json(); // 2. Get address risk const riskResponse = await fetch( `https://api.chainstream.io/v1/kyt/addresses/${toAddress}/risk`, { headers: { 'Authorization': `Bearer ${token}` } } ); const addressRisk = await riskResponse.json(); // 3. Risk handling switch (addressRisk.rating) { case 'SEVERE': return { status: 'REJECTED', reason: 'Target address is associated with known criminal activity', riskLevel: 'SEVERE' }; case 'HIGH': return { status: 'PENDING_CONFIRMATION', warning: 'This address has been flagged as high risk', riskDetails: addressRisk, requiresConfirmation: true }; default: return { status: 'APPROVED', riskLevel: addressRisk.rating }; } } // Express route example app.post('/withdraw/request', async (req, res) => { const result = await handleWithdrawal(req.body); res.json(result); }); ``` *** ## Wallet Risk Alerts In wallet applications, provide risk alerts before users initiate transfers. ### User Experience Flow ```mermaid theme={null} flowchart TD A[User Inputs Address] --> B[Real-time Address Risk Query] B --> C{Risk Level} C -->|HIGH/SEVERE| D[Show Risk Warning] C -->|MEDIUM| E[Show Notice] C -->|LOW| F[Normal Display] D --> G{User Confirms} G -->|Confirm| H[Continue Transfer] G -->|Cancel| I[Cancel Operation] ``` ### Frontend/Backend Integration Frontend should never expose clientSecret directly. Use backend API proxy to call ChainStream. ```javascript theme={null} // Trigger on address input change async function onAddressChange(address) { if (!isValidAddress(address)) return; setLoading(true); try { // Call backend proxy API const response = await fetch('/api/risk/check-address', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ address }) }); const risk = await response.json(); setRiskInfo({ level: risk.rating, labels: risk.labels, warnings: risk.warnings }); } finally { setLoading(false); } } ``` ```javascript theme={null} app.post('/api/risk/check-address', async (req, res) => { const { address } = req.body; const token = await complianceService.getAccessToken(); // Register address await fetch('https://api.chainstream.io/v1/kyt/address', { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ address }) }); // Get risk const riskResponse = await fetch( `https://api.chainstream.io/v1/kyt/addresses/${address}/risk`, { headers: { 'Authorization': `Bearer ${token}` } } ); const result = await riskResponse.json(); res.json({ rating: result.rating, riskScore: result.riskScore, labels: result.labels || [], warnings: generateWarnings(result) }); }); function generateWarnings(result) { const warnings = []; if (result.exposures?.direct?.severe > 0) { warnings.push('Directly linked to known criminal address'); } if (result.labels?.includes('Mixer User')) { warnings.push('Has interacted with mixing services'); } return warnings; } ``` *** ## Batch Address Screening Enterprise-level compliance screening for existing addresses. ### Use Cases * Regular compliance audits * New regulatory requirement implementation * M\&A due diligence * Risk screening ### Batch Screening Implementation ```javascript theme={null} async function batchScreenAddresses(addresses) { const token = await complianceService.getAccessToken(); const results = []; for (const address of addresses) { try { // Register address await fetch('https://api.chainstream.io/v1/kyt/address', { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ address }) }); // Get risk const riskResponse = await fetch( `https://api.chainstream.io/v1/kyt/addresses/${address}/risk`, { headers: { 'Authorization': `Bearer ${token}` } } ); const risk = await riskResponse.json(); results.push({ address, rating: risk.rating, riskScore: risk.riskScore }); } catch (error) { results.push({ address, error: error.message }); } } // Process high-risk addresses const highRiskAddresses = results.filter( r => r.rating === 'SEVERE' || r.rating === 'HIGH' ); return { all: results, highRisk: highRiskAddresses }; } ``` *** ## Best Practices ### Threshold Setting Recommendations Adjust risk thresholds based on business type: | Business Type | SEVERE Handling | HIGH Handling | MEDIUM Handling | | :------------ | :----------------- | :------------- | :-------------- | | Licensed CEX | Auto freeze | Manual review | Flag monitoring | | Wallet App | Strong warning | Warning | Notice | | DeFi Protocol | Reject interaction | Warning | Normal | | OTC Platform | Reject trade | Additional KYC | Normal | ### Audit Log Requirements Ensure complete audit trail: ```json theme={null} { "eventId": "evt_123456", "timestamp": "2024-01-15T10:30:00Z", "eventType": "RISK_DECISION", "subject": { "transferId": "123e4567-e89b-12d3-a456-426614174000", "txHash": "0x...", "userId": "user_789" }, "riskAssessment": { "rating": "HIGH", "riskScore": 72 }, "decision": { "action": "HOLD", "decidedBy": "SYSTEM", "reason": "Auto-hold per risk policy" }, "metadata": { "policyVersion": "1.2.0", "engineVersion": "2024.01" } } ``` *** ## Next Steps Detailed authentication guide KYT core concepts KYA core concepts KYT API complete documentation # KYA Core Concepts Source: https://docs.chainstream.io/en/docs/compliance/kya-concepts Understanding Know Your Address - core concepts, profiling dimensions, and risk assessment mechanisms ## What is KYA **KYA (Know Your Address)** is a comprehensive mechanism for profiling and risk assessment of cryptocurrency addresses. By analyzing an address's historical behavior, associated networks, and label information, it constructs a complete risk profile. **Core Question**: Is this address trustworthy? KYA helps you fully understand an address's historical behavior and risk status before interacting with it. ## KYA vs KYT KYA and KYT are complementary risk control tools that assess risk from different dimensions: | Dimension | KYT | KYA | | -------------------- | ------------------------- | ---------------------------- | | **Analysis Target** | Individual transaction | Overall address | | **Time Dimension** | Real-time snapshot | Historical accumulation | | **Core Question** | Is this transaction safe? | Is this address trustworthy? | | **Update Frequency** | Triggered per transaction | Periodic/on-demand | | **Data Depth** | Transaction level | Profile level | *** ## Profiling Dimensions KYA constructs address profiles from three core dimensions: ```mermaid theme={null} flowchart TD subgraph INPUT["KYA Profile System"] A[Entity Identification
Entity] --> D[Comprehensive Profile
Risk Profile] B[Behavior Labels
Behavior] --> D C[Risk Factors
Risk] --> D end ``` *** ## Entity Identification Identify the type of entity behind an address to understand its nature and trustworthiness. ### Entity Classification | Category | Description | Risk Weight | Identification Method | | ------------------ | -------------------------- | ----------- | ---------------------------------------------------- | | **CEX** | Centralized Exchange | Low | Known hot wallet addresses, deposit address patterns | | **DEX** | Decentralized Exchange | Low-Medium | Smart contract identification, router addresses | | **Individual** | Regular user address | Medium | Behavior pattern analysis, balance characteristics | | **Contract** | Smart contract | Varies | On-chain code verification | | **Known Criminal** | Confirmed criminal address | Very High | Law enforcement reports, sanctions lists | ### Entity Identification Flow ```mermaid theme={null} flowchart TD A[Input: Address] --> B[Entity Identification Engine] B --> C[Known Address Database
CEX/DEX] B --> D[Pattern Recognition
Cluster Analysis] C --> E[Match Result] D --> E E --> F[Entity Type + Confidence Score] ``` ### Confidence Levels Entity identification results include confidence scores to help you evaluate reliability: | Level | Confidence | Description | Recommended Use | | --------------------- | ---------- | ------------------------------------------------ | ------------------ | | **Confirmed** | >95% | Officially confirmed or law enforcement reported | Use directly | | **High Confidence** | 80-95% | Strong feature matching | Recommended to use | | **Medium Confidence** | 50-80% | Partial feature matching | Use as reference | | **Low Confidence** | \<50% | Speculation | For reference only | *** ## Behavior Labels Based on on-chain behavioral characteristics, the system automatically assigns corresponding labels. Reflect the address's role in the on-chain ecosystem: | Label | Definition | Risk Implication | | ------------- | ------------------------------------ | --------------------- | | `whale` | Large holdings address (>\$1M) | High market influence | | `trader` | High-frequency trading behavior | Normal activity | | `holder` | Long-term holding without movement | Low risk | | `bot` | Programmatic trading characteristics | Needs attention | | `smart_money` | Smart money | Professional trader | Reflect specific behavioral patterns: | Label | Definition | Risk Implication | | ------------- | ----------------------------------- | ----------------- | | `mixer_user` | Has used mixing services | High risk | | `bridge_user` | Cross-chain bridge user | Medium risk | | `defi_active` | Frequent DeFi protocol interactions | Normal | | `nft_trader` | Active NFT trading | Normal | | `new_address` | Newly created address | Needs observation | Identified ownership entities: | Label | Description | | ------------------- | ------------------ | | `exchange:binance` | Binance Exchange | | `exchange:coinbase` | Coinbase Exchange | | `defi:uniswap` | Uniswap Protocol | | `bridge:multichain` | Cross-chain Bridge | | `sanctions` | Sanctioned address | ### Label Combination Risk Certain label combinations amplify risk signals: **High Risk Combination Example** `mixer_user` + `high_value` + `new_address` **Risk Level**: HIGH **Reason**: New address receiving large funds from mixer matches money laundering patterns **Low Risk Combination Example** `whale` + `holder` + `exchange:binance` **Risk Level**: LOW **Reason**: Exchange-associated long-term large holder, normal behavior *** ## Risk Factors Core metrics for quantifying risk assessment, used to calculate comprehensive risk scores. ### Core Risk Factors | Factor | Description | Calculation Method | | ------------------------- | ------------------------------------------------ | ------------------------------ | | **Blacklist Exposure** | Degree of association with blacklisted addresses | Direct/indirect exposure ratio | | **Anomaly Index** | Degree of deviation from normal behavior | Statistical anomaly detection | | **Privacy Service Usage** | Mixer/privacy protocol usage | Interaction history analysis | | **Geographic Risk** | High-risk jurisdiction association | IP/exchange correlation | | **Temporal Anomaly** | Abnormal time patterns | Transaction time analysis | *** ## Use Cases ### 1. Counterparty Due Diligence Collect wallet address from OTC trading counterparty ```bash theme={null} POST https://api.chainstream.io/v1/kyt/address Authorization: Bearer Content-Type: application/json { "address": "0x1234567890abcdef1234567890abcdef12345678" } ``` ```bash theme={null} GET https://api.chainstream.io/v1/kyt/addresses/{address}/risk Authorization: Bearer ``` * `Severe/High` → Reject transaction * `Medium` → Request additional KYC * `Low` → Proceed normally ### 2. Batch Address Screening Periodically screen existing user addresses: ```javascript theme={null} async function batchScreenAddresses(addresses) { const results = []; for (const address of addresses) { // 1. Register address await fetch('https://api.chainstream.io/v1/kyt/address', { method: 'POST', headers: { 'Authorization': `Bearer ${accessToken}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ address }) }); // 2. Get risk assessment const riskResponse = await fetch( `https://api.chainstream.io/v1/kyt/addresses/${address}/risk`, { headers: { 'Authorization': `Bearer ${accessToken}` } } ); const risk = await riskResponse.json(); results.push({ address, risk: risk.risk, addressType: risk.addressType }); } return results; } ``` **Business Flow**: 1. Export user address list 2. Batch register and query risk 3. Filter high-risk addresses 4. Trigger follow-up processing ### 3. Real-time Risk Alerts Provide risk alerts before wallet users transfer: ```mermaid theme={null} flowchart TD A[User Enters Recipient Address] --> B[Call KYA API] B --> C{Risk Level} C -->|High/Severe| D[Show Risk Warning] C -->|Medium| E[Show Notice] C -->|Low| F[Normal Display] D --> G{User Choice} G -->|Confirm| H[Continue Transfer] G -->|Cancel| I[Cancel Operation] ``` *** ## Data Elements ### Input Data | Field | Required | Description | | ------- | -------- | ---------------- | | address | ✅ | Address to query | ### Output Data ```json theme={null} { "address": "0x0038AC785dfB6C82b2c9A7B3B6854e08a10cb9f1", "risk": "Low", "riskReason": null, "addressType": "PRIVATE_WALLET", "cluster": null, "addressIdentifications": [], "exposures": [ { "category": "sanctions", "value": 0.0 } ], "triggers": [], "status": "COMPLETE" } ``` ### Response Field Description | Field | Type | Description | | ---------------------- | ------ | ------------------------------------------------------------ | | address | string | Queried address | | risk | string | Risk level: `Severe`, `High`, `Medium`, `Low` | | riskReason | string | Risk reason (can be null) | | addressType | string | Address type: `PRIVATE_WALLET`, `EXCHANGE`, `CONTRACT`, etc. | | cluster | string | Associated cluster name (can be null) | | addressIdentifications | array | Address identification labels | | exposures | array | Risk exposure list | | triggers | array | Triggered risk rules | | status | string | Analysis status: `COMPLETE`, `PENDING` | *** ## Synergy with KYT KYA and KYT should be used together in practice to achieve comprehensive risk management. ### Synergy Pattern ```mermaid theme={null} flowchart TD A[Transaction Event] --> B[KYT Transaction Analysis] A --> C[KYA Address Profile] B --> D[Comprehensive Risk Decision] C --> D ``` ### Decision Matrix | KYT Result | KYA Result | Combined Decision | | ---------- | ----------- | --------------------- | | SEVERE | Any | Immediate freeze | | HIGH | HIGH/SEVERE | Freeze pending review | | HIGH | LOW/MEDIUM | Manual review | | MEDIUM | HIGH/SEVERE | Manual review | | MEDIUM | MEDIUM | Enhanced monitoring | | LOW | LOW | Auto-approve | | LOW | HIGH | Flag for monitoring | *** ## Best Practices ### 1. Caching Strategy KYA results can be cached moderately: | Risk Level | Recommended Cache Duration | Reason | | ---------- | -------------------------- | ------------------- | | SEVERE | No caching | May have updates | | HIGH | 1 hour | Needs fresh data | | MEDIUM | 6 hours | Balance performance | | LOW | 24 hours | Low risk is stable | ### 2. Incremental Update For monitoring existing addresses: **Recommended Approach** 1. Initial full query to establish baseline 2. Daily incremental update for HIGH and above addresses 3. Weekly incremental update for MEDIUM addresses 4. Monthly full refresh ### 3. Threshold Tuning Adjust thresholds based on business scenarios: | Scenario | Recommended Adjustment | | ------------------ | ------------------------------------------------- | | High-value clients | Raise MEDIUM threshold | | New users | Strictly use default thresholds | | Batch screening | Slightly relax to avoid excessive false positives | *** ## Next Steps Start integrating KYA Learn about transaction-level risk control Understand authentication methods View API documentation # KYT Core Concepts Source: https://docs.chainstream.io/en/docs/compliance/kyt-concepts Understanding Know Your Transaction - core concepts and risk assessment mechanisms ## What is KYT **KYT (Know Your Transaction)** is a risk identification mechanism for individual cryptocurrency transactions, providing real-time analysis of each on-chain transaction to determine its risk level and provide handling recommendations. **Core Question**: Is this transaction safe? KYT helps you quickly identify the risk level and associated risk entities before processing each transaction. ## Comparison with Traditional Finance | Dimension | Traditional Finance | Crypto KYT | | --------------------- | --------------------------- | ----------------------------- | | **Monitoring Method** | Bank transaction monitoring | On-chain transaction analysis | | **Data Foundation** | Account history based | Address association based | | **Processing Time** | T+1 batch processing | Real-time/near real-time | | **Rule Engine** | Primarily manual rules | Algorithm + label driven | ## How It Works ```mermaid theme={null} flowchart TD subgraph input [Input] tx[Transaction Hash/Details] end subgraph analysis [Analysis Engine] trace[Fund Tracing] entity[Entity Identification] pattern[Pattern Detection] sanction[Sanctions Screening] end subgraph output [Output] score[Risk Score] exposure[Risk Exposure] alerts[Alerts] action[Recommendations] end input --> analysis analysis --> output ``` ### Analysis Flow 1. **Fund Tracing**: Trace fund sources and destinations forward/backward 2. **Entity Identification**: Identify known entities involved in transactions (exchanges, protocols, labeled addresses) 3. **Pattern Detection**: Identify suspicious transaction patterns (splitting, obfuscation, layering) 4. **Sanctions Screening**: Match against sanctions lists *** ## Risk Level Definitions ChainStream uses a four-tier risk classification system: | Level | Indicator | Definition | Typical Triggers | | ---------- | --------- | -------------------------- | ----------------------------------------------------------------- | | **SEVERE** | 🔴 | Known criminal association | Sanctioned addresses, confirmed hacker addresses, darknet markets | | **HIGH** | 🟠 | High-risk patterns | Mixer outputs, scam associations, unlicensed gambling | | **MEDIUM** | 🟡 | Requires attention | High-risk exchanges, privacy coin swaps, anomalous patterns | | **LOW** | 🟢 | Normal | Known compliant entities, regular user behavior | ### Level Details * **Definition**: Direct association with confirmed criminal activity * **Data Sources**: OFAC sanctions list, law enforcement reports, confirmed hacking incidents * **False Positive Rate**: Very low (\<0.1%) * **Recommended Action**: Immediate freeze, report to regulators * **Definition**: High-risk characteristics but unconfirmed criminal activity * **Data Sources**: Mixer identification, scam address clustering, behavior pattern analysis * **False Positive Rate**: Low (\<5%) * **Recommended Action**: Manual review, delayed processing * **Definition**: Risk signals present but requires further evaluation * **Data Sources**: Association analysis, behavioral anomaly detection * **False Positive Rate**: Moderate (5-15%) * **Recommended Action**: Enhanced monitoring, may proceed * **Definition**: No obvious risk characteristics * **Data Sources**: Normal transaction patterns, known compliant entities * **Recommended Action**: Process normally *** ## Recommended Action Mapping Based on risk level, the system provides standardized action recommendations: | Risk Level | Recommended Action | Automation Level | SLA | | ---------- | ------------------- | ---------------------------- | --------- | | **SEVERE** | Freeze | Automatic | Immediate | | **HIGH** | Manual Review | Requires manual confirmation | 4 hours | | **MEDIUM** | Enhanced Monitoring | Semi-automatic | 24 hours | | **LOW** | Pass | Automatic | Immediate | ### Action Flow ```mermaid theme={null} flowchart TD input[Transaction Input] --> analysis[KYT Analysis] analysis --> severe{SEVERE?} severe -->|Yes| freeze[Freeze + SAR Report] severe -->|No| high{HIGH/MEDIUM?} high -->|Yes| queue[Manual Review Queue] high -->|No| pass[Auto-approve] queue --> decision{Review Decision} decision --> approve[Approve] decision --> reject[Reject] decision --> report[Escalate] ``` *** ## Exposure Types ChainStream distinguishes between two types of risk exposure: **Definition**: Transaction directly interacts with a risk address ``` Risk Address ──────────────> Target Address Direct Transfer Exposure Type: DIRECT Risk Transmission: 100% ``` **Characteristics**: * One-hop association * High certainty of risk * Typically triggers immediate response **Example Scenarios**: * Receiving funds from known hacker address * Sending to sanctioned address * Receiving directly from mixer output ```json theme={null} { "type": "DIRECT", "category": "SANCTIONS", "entity": "OFAC Sanctioned Address", "percentage": 100 } ``` **Definition**: Associated with risk address through N hops ``` Risk Address ──> Intermediate1 ──> Intermediate2 ──> Target Address N-hop Association Exposure Type: INDIRECT Risk Transmission: Decay calculation ``` **Characteristics**: * Multi-hop association (typically 2-5 hops) * Risk decays with distance * Requires comprehensive evaluation **Decay Model**: `Risk Score = Base Risk × (Decay Factor ^ Hops)` Example: Base risk 100, decay factor 0.5, after 3 hops = 100 × 0.5³ = 12.5 ```json theme={null} { "type": "INDIRECT", "category": "MIXER", "entity": "Tornado Cash", "percentage": 12.5, "hops": 3 } ``` ### Exposure Handling Guidelines | Scenario | Direct Handling | Indirect Handling | | ------------- | ---------------- | ------------------------------------------- | | SEVERE source | Immediate freeze | Freeze within 2 hops, 3+ hops manual review | | HIGH source | Manual review | Flag for monitoring | | MEDIUM source | Process normally | Ignore | *** ## Business Flow ### Standard KYT Flow Submit transaction information to KYT API ```bash theme={null} POST https://api.chainstream.io/v1/kyt/transfer Authorization: Bearer Content-Type: application/json { "network": "ethereum", "asset": "ETH", "transferReference": "0x1234...abcd:0xRecipientAddress", "direction": "received" } ``` Wait for analysis completion via polling (typically within 30 seconds) Retrieve risk assessment results ```bash theme={null} GET https://api.chainstream.io/v1/kyt/transfers/{externalId}/summary Authorization: Bearer ``` Execute business logic based on risk level and recommendations ### Processing Times | Stage | Target Time | SLA Commitment | | ------------------------ | ----------- | -------------- | | Transaction Registration | \<100ms | 99.9% | | Risk Analysis | \<30s | 95% | | Result Return | \<30s | 95% | | End-to-end | \<1min | 90% | Valid transactions complete analysis within 30 seconds. Complex associations may require longer processing time. *** ## Data Elements ### Input Data (Register Transfer) | Field | Required | Description | | ------------------- | -------- | ---------------------------------------- | | `network` | ✅ | Network: `bitcoin`, `ethereum`, `Solana` | | `asset` | ✅ | Asset type: `BTC`, `ETH`, `SOL`, etc. | | `transferReference` | ✅ | Transfer reference (tx hash:address) | | `direction` | ✅ | Direction: `sent` or `received` | ### Input Data (Register Withdrawal) | Field | Required | Description | | ------------------ | -------- | ---------------------------------------- | | `network` | ✅ | Network: `bitcoin`, `ethereum`, `Solana` | | `asset` | ✅ | Asset type | | `address` | ✅ | Withdrawal destination address | | `assetAmount` | ✅ | Asset amount | | `attemptTimestamp` | ✅ | Attempt timestamp | | `assetPrice` | Optional | Asset price | ### Output Data ```json theme={null} { "externalId": "393905a7-bb96-394b-9e20-3645298c1079", "asset": "ETH", "network": "ethereum", "transferReference": "0x1234...abcd:0xAddress", "direction": "received", "tx": "0x1234...abcd", "outputAddress": "0xAddress", "assetAmount": "1.5", "usdAmount": "3000.00", "timestamp": "2024-01-15T10:30:00.000Z", "updatedAt": "2024-01-15T10:30:15.000Z" } ``` ### Response Field Description | Field | Type | Description | | ----------------- | ------ | ----------------------------------------------- | | externalId | string | Transfer ID (UUID), used for subsequent queries | | asset | string | Asset type | | network | string | Blockchain network | | transferReference | string | Transfer reference | | direction | string | Transfer direction | | tx | string | Transaction hash | | outputAddress | string | Output address | | assetAmount | string | Asset amount | | usdAmount | string | USD amount | | timestamp | string | Transaction timestamp | | updatedAt | string | Update time | *** ## API Usage ### Register Deposit Transaction (Transfer) ```bash theme={null} POST https://api.chainstream.io/v1/kyt/transfer Authorization: Bearer Content-Type: application/json { "network": "ethereum", "asset": "ETH", "transferReference": "0x9f318afbad2a183f97750bc51a75b582ad8f9e9c:0x17A16QmavnUfCW11DAApi", "direction": "received" } ``` ### Register Withdrawal Transaction ```bash theme={null} POST https://api.chainstream.io/v1/kyt/withdrawal Authorization: Bearer Content-Type: application/json { "network": "Solana", "asset": "SOL", "address": "D1Mc6j9xQWgR1o1Z7yU5nVVXFQiAYx7FG9AW1aVfwrUM", "assetAmount": "5", "attemptTimestamp": "2024-01-15T10:30:00.000Z" } ``` ### Get Assessment Details ```bash theme={null} # Get transfer summary GET https://api.chainstream.io/v1/kyt/transfers/{externalId}/summary # Get direct risk exposure GET https://api.chainstream.io/v1/kyt/transfers/{externalId}/exposures/direct # Get risk alerts GET https://api.chainstream.io/v1/kyt/transfers/{externalId}/alerts # Get network identifications GET https://api.chainstream.io/v1/kyt/transfers/{externalId}/network-identifications ``` ### Withdrawal Related Queries ```bash theme={null} # Get withdrawal summary GET https://api.chainstream.io/v1/kyt/withdrawal/{withdrawalId}/summary # Get withdrawal direct exposure GET https://api.chainstream.io/v1/kyt/withdrawal/{withdrawalId}/exposures/direct # Get withdrawal alerts GET https://api.chainstream.io/v1/kyt/withdrawal/{withdrawalId}/alerts # Get fraud assessment GET https://api.chainstream.io/v1/kyt/withdrawal/{withdrawalId}/fraud-assessment ``` *** ## Best Practices Adjust thresholds based on business risk appetite: | Business Type | SEVERE Threshold | HIGH Threshold | Recommendation | | -------------- | ---------------- | -------------- | -------------- | | Licensed CEX | Default | Default | Strict mode | | Wallet Service | Default | Raise 10% | Balanced mode | | DeFi Protocol | Default | Raise 20% | Relaxed mode | Establish a false positive feedback mechanism: 1. Record all manually overturned cases 2. Regularly analyze false positive patterns 3. Submit false positive feedback to ChainStream 4. Adjust local threshold configuration Ensure compliance audit requirements: * Save all KYT requests and responses * Record manual decisions with reasoning * Retain for at least 5 years (per regulatory requirements) * Support export in standard report formats Risk status may change (e.g., address subsequently sanctioned). Recommendations: * Periodically re-evaluate historical transactions * Monitor new activity from associated addresses * Establish alert mechanism for risk status changes *** ## Related Resources Learn about address-level risk control Start integrating KYT Understand authentication methods View API documentation # Compliance (KYT / KYA) Source: https://docs.chainstream.io/en/docs/compliance/overview Built-in Know-Your-Transaction and Know-Your-Address inside the same API as the data. Compliance checks live inside the same ChainStream API as the data itself — no second vendor, no second invoice, no second data-exfiltration surface. Score a transfer, fingerprint an address, flag a withdrawal, produce a Travel-Rule-ready summary — all from your existing integration. Risk-score any incoming or outgoing transfer. Returns risk bands, exposure categories, alert codes and the reasoning trail. Fingerprint a counterparty address — entity tags, risk level, sanctions matches, historical behaviour. ## When you need it Run every incoming deposit through KYT before crediting the user. Block or hold if the transfer matches sanctions lists, mixers or darknet markets. Use the withdrawal endpoints to get a fraud-assessment score and network-identification breakdown for the destination address before you release funds. Fingerprint addresses that interact with your wallet before allowing swaps, staking or deposits. Export per-transfer summaries that match the fields regulators require for FATF Travel-Rule messages. Before signing, surface the risk band of the counterparty pool, token creator or receiving address. ## How compliance fits alongside the data KYT and KYA are just more data products — queried the same way as tokens, trades and wallets. That means you can: * Attach KYT results to every row in your **Trades** and **Transfers** pipeline * Join KYA entity labels against **Wallets** and **Smart Money** cohorts * Run compliance filters inside the same **GraphQL** query that pulls your primary data * Consume **Kafka** transfer topics together with REST-scored risk data, side-by-side ## Start here What KYT returns, how risk is computed, what each field means. How addresses are fingerprinted and what labels ChainStream assigns. Step-by-step wiring into deposit, withdrawal and on-chain flows. Every endpoint — address, transfer, withdrawal, alerts, exposures. End-to-end tutorial that plugs KYT into a real deposit flow. Data handling and retention for compliance payloads. # Blockchain Core Source: https://docs.chainstream.io/en/docs/data-products/blockchain-core Raw blocks, transactions, gas metrics and chain-level state — when you need the facts beneath the normalized products. The **Blockchain Core** data product is the raw substrate beneath everything else ChainStream publishes. Use it when you need facts that aren't expressed in the higher-level products (Tokens, Trades, Wallets), or when you're verifying / auditing something end-to-end. Most integrations should start with Tokens / Trades / Wallets rather than here — the higher-level products are cheaper to query and already de-noised. ## What's inside | Dataset | Key fields | | :------------ | :------------------------------------------------------------------------------- | | Blocks | `number`, `hash`, `parentHash`, `timestamp`, `gasUsed`, `baseFeePerGas`, `miner` | | Transactions | `hash`, `from`, `to`, `value`, `input`, `status`, `gasUsed`, `effectiveGasPrice` | | Logs / Events | `txHash`, `logIndex`, `address`, `topics[]`, `data`, `removed` | | Gas metrics | `blockGasUsage`, `chainGasOracle` (EIP-1559 base / priority fees) | | Chain state | `latestBlock`, `finality`, `reorgsLast1h` | ## Coverage & freshness * Raw data from every supported chain, back-filled to genesis where possible. * Latency: blocks and logs delivered within 1–2 s of finalization. ## Access `/v2/blockchain`, `/v2/blockchain/{chain}/latest_block`. `{chain}.dex.trades`, `{chain}.v1.transfers.proto`, `{chain}.balances` Protobuf topics per chain. Query blocks joined with transactions and decoded events. Typed wrappers for blocks/transactions/logs. ## Common use cases * Independent verification of a higher-level data point * Custom indexing pipelines that need raw logs * Gas-price oracles and fee-estimation services * Chain-health dashboards (reorgs, uncle rate, base-fee drift) ## Billing Raw-data endpoints charge per item returned. Kafka topics priced per delivered message, discounted in streaming tiers. ## Next Per-chain list of raw topics and schemas. Latency expectations per chain and per surface. # Candles (OHLC) Source: https://docs.chainstream.io/en/docs/data-products/candles-ohlc Multi-interval OHLC bars for tokens, pairs and pools — pre-aggregated from the full trade stream. The **Candles (OHLC)** data product is the pre-aggregated bars (Open / High / Low / Close / Volume) you'd otherwise have to compute from [Trades](/en/docs/data-products/trades) yourself. Bars are available at multiple intervals, for tokens, trading pairs and specific pools. ## What's inside | Field | Description | | :--------------------------------------- | :------------------------------------------- | | `open`, `high`, `low`, `close` | USD or quote-token denominated, configurable | | `volumeUsd`, `volumeBase`, `volumeQuote` | Volumes per side | | `trades` | Trade count in the bar | | `buyers`, `sellers` | Unique address counts (where available) | | `timestamp` | Bar open-time, UTC | ## Intervals | Interval | Earliest lookback | Typical use | | :---------------- | :---------------- | :------------------------- | | `1s` | recent hours | Scalping, live charts | | `1m`, `5m`, `15m` | days | Intraday charts and alerts | | `1h`, `4h` | months | Swing-trading dashboards | | `1d`, `1w` | project lifetime | Long-term analytics | ## Access `/v2/token/{chain}/{tokenAddress}/candles`, `/v2/token/{chain}/pool/{poolAddress}/candles`, `/v2/token/{chain}/pair/{pair}/candles`. `dex-candle:{chain}_{tokenAddress}_{resolution}` (USD) and `dex-candle-in-native:...` (native). SDK: `client.stream.subscribeTokenCandles({ chain, tokenAddress, resolution, callback })`. Fetch bars alongside token metadata in one query. `client.token.getCandles(chain, tokenAddress, { resolution })` returns typed arrays. ## Common use cases * Render TradingView-style price charts * Feed backtesting engines with historical OHLC * Compute technical indicators (RSI, MACD, VWAP) downstream * Drive time-series anomaly alerts ## Billing REST / GraphQL: pagination-priced per bar returned. WebSocket: per-bar-update. ## Next Use if you need tick-level granularity or custom aggregation. Pool-specific OHLC is derived from pool trades. # Data Freshness & SLA Source: https://docs.chainstream.io/en/docs/data-products/data-freshness Latency, refresh intervals and backfill behaviour for every data product, per chain and per surface. This page is the single source of truth for **how fresh** each data product is. If you're sizing a trading bot, a compliance alerting system or an agent feedback loop, these numbers are what matters. ## End-to-end latency model ``` [chain event] → [ingestion] → [normalization] → [Kafka] → [REST / WS / GraphQL cache] ~0 <200ms <200ms <500ms +50–500ms ``` ## Per-surface latency | Surface | Target p50 | Target p99 | Notes | | :-------------- | :--------- | :--------- | :------------------------------------------------ | | Kafka Streams | 800 ms | 2 s | Closest to source; used for low-latency pipelines | | WebSocket | 1.0 s | 3 s | Same source as Kafka; adds fan-out overhead | | REST (cached) | 1.5 s | 5 s | Cache TTLs vary per endpoint — see each one | | REST (uncached) | 3 s | 10 s | Rare; for deep historical lookups | | GraphQL | 2 s | 6 s | Joins multiple products; adds planning time | ## Per-product refresh | Product | Real-time? | Snapshot cadence | | :------------------------------ | :--------- | :--------------------- | | Tokens — market | yes | price tick every trade | | Tokens — security | delayed | minutes after creation | | Trades | yes | per block | | Pools | yes | per event | | Wallets — holdings | yes | seconds after transfer | | Wallets — net worth history | no | hourly | | Candles (OHLC) | yes | bar closes at interval | | Holders (table) | yes | per transfer | | Holders (distribution metrics) | no | every 5 min | | Smart Money (cohort membership) | no | weekly (Mon 00:00 UTC) | | Smart Money (flow events) | yes | per trade | | Blockchain Core | yes | per block | | Rankings | yes (most) | 1 min / block-level | | Compliance (KYT / KYA) | yes | on request | ## Backfill behaviour * **Solana / EVM** archival data backfilled from genesis where feasible. * **New chains** start with ≥ 30 days of backfill at launch, full history streamed in within the first 90 days. * **Reorgs** cause rewrites of the affected slot/block in all downstream streams; consumers should be idempotent on `(chainId, txHash)` + `logIndex`. ## Incidents & status Current incidents and historical uptime live at [status.chainstream.io](https://status.chainstream.io) (link to be finalized). ## Next Per-plan throughput limits and headers. Exact topic names and retention per chain. # DEX Pools Source: https://docs.chainstream.io/en/docs/data-products/dex-pools Pool state, reserves, fee tiers, TVL and liquidity snapshots over time for every indexed AMM and CLMM. The **DEX Pools** data product gives you the state of every liquidity pool ChainStream indexes — from classic Uniswap-v2 constant-product pools to concentrated-liquidity v3/v4 pools, Solana AMMs and more — with normalized fields. ## What's inside | Field group | Examples | | :---------- | :--------------------------------------------------------------------- | | Identity | `chainId`, `poolAddress`, `dex`, `pairType` (v2/v3/v4/CLMM/StableSwap) | | Tokens | `token0`, `token1`, `decimals0`, `decimals1`, `reserve0`, `reserve1` | | Economics | `tvlUsd`, `volume24hUsd`, `feeTierBps`, `apy7d` | | State | `priceToken0InToken1`, `sqrtPriceX96`, `tick`, `liquidity` | | Provenance | `createdAtBlock`, `factoryAddress`, `initCodeHash` | ## Coverage & freshness * Pool creations detected at block-level; state fields update on every swap, add or remove event (typically seconds). * Historical TVL and volume series aggregated at 1h and 1d granularities. ## Access `/v2/dexpools/{chain}/{poolAddress}`, `/v2/dexpools/{chain}/{poolAddress}/snapshots`. Join pools with tokens and trades in one query. `dex-pool-balance:{chain}_{poolAddress}` for live pool liquidity; pool creation events are consumed from Kafka `{chain}.dex.pools`. SDK: `client.stream.subscribeDexPoolBalance`. `{chain}.dex.pools`, `{chain}.dex.pools.processed` topics per chain. ## Common use cases * Build an "all-pools" screener with TVL / volume filters * Detect brand-new pools for snipe / launch alerts * Monitor specific pool depth before submitting a swap * Drive a routing layer that requires up-to-date reserves ## Billing Per-pool lookups: **1 read unit**. Search and list calls scale with `limit`. ## Next The trade stream that flows through these pools. Pool-level OHLC if you want bars instead of state snapshots. # Holders Source: https://docs.chainstream.io/en/docs/data-products/holders Top holders, distribution, concentration and change-over-time for any token. The **Holders** data product exposes per-token holder tables and distribution metrics, so you can answer "who owns this token?", "how concentrated is it?" and "who just moved?" without scraping explorers. ## What's inside | Field group | Examples | | :------------- | :--------------------------------------------------------------------------- | | Table | `rank`, `address`, `balance`, `shareOfSupply`, `entityLabel`, `costBasisUsd` | | Distribution | `giniCoefficient`, `top10Share`, `top100Share` | | Changes | `changesLast24h` (additions, exits, net rank movement) | | Classification | `bucket` — whale / shrimp / contract / exchange / liquidity-pool | ## Coverage & freshness * Available on every chain in [Supported Chains](/en/docs/supported-chains). * Holder balances refreshed within seconds of matching transfer events. * Distribution metrics recomputed every 5 minutes. ## Access `/v2/token/{chain}/{tokenAddress}/holders`, `/v2/token/{chain}/{tokenAddress}/topholders`. `dex-token-holding:{chain}_{tokenAddress}` — holder distribution and balance-tag counts streamed live. SDK: `client.stream.subscribeTokenHolders`. Join Holders with Wallets for enriched rows. `tokens_analyze` tool for agents — returns holder list, top-N concentration, Gini and bucket classification in one call. ## Common use cases * Detect whale accumulation or distribution * Airdrop eligibility snapshots * Concentration-risk scoring for token due-diligence * Chart top-10 share over time ## Billing Per-call **1 read unit**; large holder tables paginated. ## Next Drill into any holder for full profile and PnL. Detect when smart-money cohorts appear in the holder list. # Data Products Source: https://docs.chainstream.io/en/docs/data-products/overview Every dataset ChainStream publishes — what it contains, how fresh it is, and how to access it. ChainStream is organized as a catalog of **data products**. Each product is a normalized, multi-chain dataset with a defined shape, refresh cadence and delivery surface. Pick a product below to see its fields, coverage, SLAs and which access method fits best. ## Catalog Metadata, market data, prices, holders, security info, creation events. DEX swaps normalized across chains — price, size, maker/taker, router. Balances, PnL, net-worth curves, transfer history, first-tx timing. Pool state, reserves, fee tiers, liquidity snapshots over time. Curated lists — hot, new, migrated, final-stretch, stock-like tokens. Multi-interval OHLC for token, pair and pool addresses. Top holders, distribution, concentration and change over time. Curated wallet cohorts with labels, win-rate and flow aggregates. Raw blocks, transactions, gas metrics and chain-level state. Latency, refresh intervals and backfill behaviour per dataset. ## How data products are organized Every dataset is described the same way, so you can assess fit quickly: What is in the dataset, in plain English — with the canonical schema. Which chains the dataset is available on, and any per-chain caveats. Real-time tick, near-real-time (seconds), or snapshot (minutes/hours). Which interfaces expose it — REST, GraphQL, WebSocket, Kafka, SDK, CLI, MCP. Expected throughput per chain — useful for sizing consumers. Which plan tier and unit cost applies when you call it. ## Relationship between products Most products cross-reference each other by the same canonical IDs: * A `tokenAddress` in **Tokens** is the same one used in **Trades**, **Candles**, **Holders** and **Pools**. * A `walletAddress` in **Wallets** flows through **Trades**, **Transfers** and **Smart Money**. * A `poolAddress` in **DEX Pools** is the source of its own **Candles** and **Trades** slice. This lets you join across products without reconciling IDs by hand. ## Pick your entry point Jump into Tokens / Trades / Wallets / Pools directly. Pick the right access method — REST / GraphQL / WebSocket / Kafka. Follow a tutorial that touches several products end-to-end. Go straight to the API Reference. # Rankings Source: https://docs.chainstream.io/en/docs/data-products/rankings Curated token lists — hot, new, migrated, final-stretch, stock-like — ready for discovery UIs and agents. The **Rankings** data product is a set of opinionated, continuously-recomputed token lists. Each list is a discovery surface: the logic behind it is documented so you can decide whether it fits your use case. ## Available lists | List | What it surfaces | Refresh | | :-------------------------- | :-------------------------------------------------------------------------------------------- | :---------- | | `hot` | Tokens with the fastest growth in unique buyers + volume in the last 1h / 24h | 1 min | | `new` | Freshly-created tokens passing minimum liquidity and holder checks | block-level | | `migrated` | Tokens that recently migrated from a launchpad to a full DEX | 1 min | | `final-stretch` | Launchpad tokens approaching migration thresholds | 1 min | | `stock-like` | Tokens with behaviour profiles similar to traditional equities (low vol, steady accumulation) | hourly | | `top-gainers`, `top-losers` | Price movers over 1h / 24h / 7d windows | 5 min | See [API Reference → Rankings](/en/api-reference/endpoint/data/ranking/v2/ranking-chain-hottokens-duration-get) for the full list of endpoints and parameters. ## Access `/v2/ranking/{chain}/hottokens/{duration}`, `/v2/ranking/{chain}/newtokens`, `/v2/ranking/{chain}/migrated`, `/v2/ranking/{chain}/finalstretch`, `/v2/ranking/{chain}/stocks`. `dex-ranking-list:{chain}_{ranking_type}` for membership; `dex-ranking-token-stats-list:{chain}_{channelType}` for live per-token stats. SDK: `client.stream.subscribeRankingTokensList` / `subscribeRankingTokensStats`. `market_trending` tool — common entry-point for discovery agents. `chainstream market trending --chain solana --duration 24h` ## Common use cases * "What's hot right now?" home-page widget * New-token sniper feeds * Agent-driven daily-digest reports * Seeding backtests with real historical lists (via the replay endpoint) ## Billing Each list call is **1 read unit** regardless of list size (lists are capped). ## Next Look up each ranked token for full metadata and security. Uses Rankings + WebSocket end-to-end. # Smart Money Methodology Source: https://docs.chainstream.io/en/docs/data-products/smart-money ChainStream Smart Money identification methodology explained ChainStream's Smart Money feature helps developers track and analyze "smart money" — addresses that consistently achieve above-market returns in the crypto market. This document details the Smart Money identification methodology and data update mechanisms. *** ## What is Smart Money ### Definition Smart Money refers to addresses that demonstrate the following characteristics in the crypto market: * Consistently outperform market benchmarks * Enter quality projects early * Maintain high win rates * Professional risk management capabilities ### Smart Money Types | Type | Description | Typical Characteristics | | :---------------------- | :------------------------------------------ | :--------------------------------------------------------- | | Institutional Investors | Professional investment institutions, funds | Large trades, long-term holding, diversified investments | | Professional Traders | Full-time cryptocurrency traders | High-frequency trading, technical analysis, multi-strategy | | Early Investors | Early project participants | Primary market participation, long-term lockups | | KOL/Influencer Wallets | Industry notable figures | Community influence, information advantage | ### Comparison with Regular Addresses | Dimension | Smart Money | Regular Address | | :------------------ | :---------------------------------------- | :------------------------------- | | Returns | Consistent positive returns, beats market | High volatility, frequent losses | | Entry Timing | Early discovery, buy at lows | Chase pumps, buy at highs | | Win Rate | > 60% | \< 50% | | Position Management | Clear take-profit/stop-loss strategy | Random trading, no discipline | | Capital Scale | Usually > \$100K | Widely distributed | *** ## Identification Methodology ### Data Sources ChainStream analyzes the following on-chain data: * All DEX trading records * Token holding changes * Fund flow trajectories * Trading time distribution * Gas fee patterns ### Candidate Pool Selection Method ChainStream uses a reverse-tracking method based on new launch token performance to build the Smart Money candidate pool: #### Selection Process From all newly launched tokens in the past 60 days, select the top 1000 best-performing tokens based on market cap growth/trading volume metrics For the above tokens, identify addresses that bought in the early stage (within 24 hours after launch) Exclude the following address types: * DEV/project addresses (identified by trading patterns) * Market maker addresses (identified by high-frequency wash trading) * CEX hot wallet addresses (matched against known address database) * Sybil attack addresses (identified by correlation analysis) Count each address's early buy frequency in the top 1000 tokens, take the top 200 addresses with highest frequency as the Smart Money candidate pool ### Dynamic Rolling Update Mechanism To maintain timeliness and accuracy of Smart Money data, ChainStream implements a weekly rolling update with weight decay: | Configuration | Value | | :------------- | :----------------------------------------------------------- | | Update Cycle | Every Monday UTC 00:00 | | Window Size | 60 days (approximately 8 weeks) | | Rolling Method | Remove oldest week's data weekly, include latest week's data | #### Weight Decay Model | Data Period | Weight | | :------------ | :----- | | Last 1 week | 100% | | 2 weeks ago | 85% | | 3 weeks ago | 70% | | 4 weeks ago | 55% | | 5-8 weeks ago | 40% | Rolling updates mean the Smart Money list changes dynamically. Historical Smart Money addresses with poor recent performance will gradually be removed from the candidate pool. *** ## Data Update Cycle ### Real-time Updates | Data Type | Update Latency | | :------------------ | :------------- | | New trade detection | \< 1 minute | | Position changes | \< 5 minutes | ### Periodic Updates | Data Type | Update Cycle | | :------------------ | :--------------------- | | Smart Money list | Every Monday UTC 00:00 | | Score recalculation | Every 24 hours | | Full re-evaluation | Every 30 days | *** ## Use Cases Monitor Smart Money buy signals to assist trading decisions. Analyze new projects that Smart Money is interested in: * Multiple Smart Money buying simultaneously * Continuous accumulation rather than quick flips Judge market sentiment through Smart Money behavior: * Heavy buying: Bullish signal * Concentrated selling: Bearish signal Monitor abnormal fund flows: * Whale large transfers * Project team address movements *** ## Usage Guidelines Smart Money signals are for reference only and do not constitute investment advice. ### Correct Usage * Use as a research starting point to discover tokens worth attention * Combine with fundamental analysis to make independent judgments * Understand signal latency — on-chain transactions need confirmation time * Focus on multiple signal convergence to improve accuracy ### Incorrect Usage * Blindly copy trading without any research * Ignore trading costs (Gas, slippage) * Ignore market environment and macro factors * Over-rely on a single signal source *** ## Limitations ### 1. Information Delay ```mermaid theme={null} flowchart TD A[SM discovers opportunity] --> B[SM on-chain trade] B --> C[Block confirmation] C --> D[ChainStream detection] D --> E[You receive signal] C -.->|3-30 second delay| E ``` ### 2. Counter-trading Risk * Some SM may realize they're being tracked and deliberately counter-trade * Large buys may be creating false signals for dumping ### 3. Market Capacity Limits * Following SM buys will push up prices * Small market cap tokens have limited capacity, copy trading effectiveness diminishes ### 4. Past Performance Doesn't Guarantee Future Results * Historical high returns don't guarantee future performance * Market environment changes may cause strategies to fail *** ## Next Hands-on: build a Smart Money tracking system end-to-end. WebSocket and Kafka channels for live Smart Money flow. The underlying product Smart Money is built on. The trade stream filtered to Smart Money cohorts. # Tokens Source: https://docs.chainstream.io/en/docs/data-products/tokens Token metadata, market data, prices, stats, creation events and security signals across every supported chain. The **Tokens** data product is the canonical source of truth for every fungible token ChainStream indexes. One schema, one address space per chain, one set of fields — whether you're looking up a blue-chip ERC-20, a brand-new Solana meme coin or a BSC pair. ## What's inside | Field group | Examples | | :---------- | :-------------------------------------------------------------- | | Identity | `chainId`, `address`, `name`, `symbol`, `decimals`, `logo` | | Market | `priceUsd`, `priceChange24h`, `marketCap`, `fdv`, `volume24h` | | Supply | `totalSupply`, `circulatingSupply`, `holderCount` | | Creation | `createdAtBlock`, `creatorAddress`, `firstTxHash`, `launchpad` | | Security | `isHoneypot`, `canBuy`, `canSell`, `taxBuy`, `taxSell`, `owner` | | Social | `website`, `twitter`, `telegram`, `verifiedSources` | Security and social fields are best-effort — see [Data Freshness](/en/docs/data-products/data-freshness) for confidence levels. ## Coverage & freshness Solana, Ethereum, BSC, Base, Polygon, Arbitrum, Optimism, Avalanche, zkSync, Sui — plus anything in [Supported Chains](/en/docs/supported-chains). Metadata: minutes after creation. Market data: seconds (near-real-time). Creation events: block-level (sub-second on Solana, 1–12 s on EVM). ## Access `/v2/token/search`, `/v2/token/{chain}/{tokenAddress}`, `/v2/token/{chain}/metadata/multi`, `/v2/token/{chain}/{tokenAddress}/security`. Join Tokens with Trades, Holders, Candles in one query. `dex-token-stats:{chain}_{tokenAddress}` for live price/volume, `dex-new-token:{chain}` for new listings. SDK: `client.stream.subscribeTokenStats` / `subscribeNewToken`. `{chain}.tokens`, `{chain}.tokens.created` topics per chain. `client.token.search()`, `client.token.getToken()`, `client.token.getTokenSecurity()` in TS / Py / Go / Rust. `tokens_search`, `tokens_analyze` MCP tools; `chainstream token search` / `chainstream token info` CLI. ## Common use cases * Resolve a symbol like `PEPE` to the right address on the chain the user actually meant * Render a token page with price, supply, security score and socials * Detect new launches on a chain with a created-at filter * Rank tokens by volume, market cap or holder growth * Feed an LLM with a token "snapshot" for analysis ## Billing Each REST / GraphQL call consumes **1 read unit**; security and full-meta endpoints may cost more. WebSocket and Kafka charge per message delivered. See [Billing & units](/en/docs/platform/billing-payments/plans-and-units). ## Next Every DEX swap for this token, with maker/taker and router labels. Distribution, concentration and top-holder movements. Multi-interval OHLC data for price charts. End-to-end example using the Tokens product. # Trades Source: https://docs.chainstream.io/en/docs/data-products/trades Normalized DEX swap events across all supported chains — price, size, maker/taker, router, slippage. The **Trades** data product is every DEX swap that ChainStream indexes, normalized so you can query by token, wallet, pool or router without caring which AMM emitted the event. ## What's inside | Field group | Examples | | :------------- | :-------------------------------------------------------------------- | | Identity | `chainId`, `txHash`, `logIndex`, `blockNumber`, `timestamp` | | Parties | `makerAddress`, `takerAddress`, `router`, `dex` | | Economics | `tokenIn`, `tokenOut`, `amountIn`, `amountOut`, `priceUsd`, `sizeUsd` | | Context | `poolAddress`, `feeTier`, `slippageBps`, `gasUsedUsd` | | Classification | `side` (buy/sell), `type` (open/close/add/remove), `isFirstBuy` | ## Coverage & freshness * **Chains**: every chain in [Supported Chains](/en/docs/supported-chains). * **DEXes**: Uniswap v2/v3/v4, Raydium, Meteora, PancakeSwap, Aerodrome, Jupiter-routed, + more — see [per-chain support tables](/en/api-reference/kafka-topics/evm). * **Latency**: block-level — Kafka delivers within 1–2 s of finalization, REST within 5–10 s. ## Access `/v2/trade/{chain}`, `/v2/trade/{chain}/activities`, `/v2/trade/{chain}/top-traders`. Flexible filters: join Trades with Tokens and Wallets. `dex-trade:{chain}_{tokenAddress}` (by token) and `dex-wallet-trade:{chain}_{walletAddress}` (by wallet). SDK: `client.stream.subscribeTokenTrade` / `subscribeWalletTrade`. `{chain}.dex.trades` topics per chain, Protobuf-encoded. `client.trade.list()`, `chainstream market trades --chain solana --token `. `trades_recent` tool for agents (filter by token, wallet or pool). ## Common use cases * Render a live trade tape for a token * Compute realized PnL for a wallet * Trigger alerts on first-buy or large-trade events * Feed a trading bot with maker/taker context * Aggregate to OHLC at custom intervals (or use [Candles](/en/docs/data-products/candles-ohlc)) ## Billing REST / GraphQL: per-page cost scales with `limit`. WebSocket and Kafka charge per delivered message, discounted for high-volume tiers. ## Next Pre-aggregated price bars if you don't need tick-level detail. Trades filtered to high-performing wallet cohorts. # Wallets Source: https://docs.chainstream.io/en/docs/data-products/wallets Balances, PnL, net-worth curves, transfer history and activity for any on-chain address. The **Wallets** data product turns any on-chain address into a queryable profile — current holdings, historical PnL, activity patterns, and first-transaction timing — across every chain we support, without you having to stitch multiple RPCs together. ## What's inside | Field group | Examples | | :------------- | :----------------------------------------------------------------------------------- | | Identity | `chainId`, `address`, `ens`/`sns`, `tags`, `firstSeenAt` | | Holdings | `holdings[]` with `token`, `balance`, `valueUsd`, `costBasisUsd`, `unrealizedPnlUsd` | | Net worth | `netWorthUsd`, `netWorthHistory[]` at hour/day granularity | | Activity | `txCount24h`, `tradeCount30d`, `avgTradeSizeUsd`, `activeChains[]` | | Classification | `walletType` (EOA / contract / exchange / smart-money), `riskScore` | ## Coverage & freshness * **Cross-chain**: balances and PnL aggregated across every supported chain by default; filter per-chain if needed. * **Freshness**: holdings refresh within seconds of a matching transfer/trade; net-worth history snapshots hourly. ## Access `/v2/wallet/{chain}/{walletAddress}/pnl`, `/v2/wallet/{chain}/{walletAddress}/net-worth`, `/v2/wallet/{chain}/{walletAddress}/tokens-balance`, `/v2/wallet/{chain}/{walletAddress}/transfers`. Query holdings-joined-trades in a single request. Per-wallet channels: `dex-wallet-balance:{chain}_{walletAddress}`, `dex-wallet-trade:{chain}_{walletAddress}`, `dex-wallet-token-pnl:` / `dex-wallet-pnl-list:`. SDK: `client.stream.subscribeWalletBalance` / `subscribeWalletTrade` / `subscribeWalletPnl`. Built by consuming `{chain}.v1.transfers.proto` + `{chain}.dex.trades` topics and filtering by address. `client.wallet.getPnl()`, `client.wallet.getNetWorth()`, `client.wallet.getTokensBalance()`. `wallets_profile`, `wallets_activity` for agents. ## Common use cases * Portfolio dashboards for retail users * Whale / smart-money follower feeds * KYC-lite "who is this wallet?" previews * Per-campaign attribution (airdrops, rewards) * Compliance-triage input ([see KYA](/en/docs/compliance/kya-concepts)) ## Billing Profile and holdings endpoints are **1 read unit**; time-series PnL and history scale with the returned range. ## Next Curated high-performing wallet cohorts built on top of Wallets. Risk-scored profile for any wallet address. # n8n Integration Source: https://docs.chainstream.io/en/docs/ecosystem/n8n/overview Connect ChainStream to n8n workflow automation with the n8n-nodes-chainstream community node. # n8n Integration `n8n-nodes-chainstream` is a community node that brings ChainStream's on-chain data directly into [n8n](https://n8n.io) workflow automation. Query token metadata, monitor trades, and track wallet activity -- all without writing code. **Package:** `n8n-nodes-chainstream` v0.0.92 | **Versions published:** 63 | Listed on the [n8n Creator Portal](https://n8n.io) ## Installation 1. Open your n8n instance. 2. Go to **Settings > Community Nodes**. 3. Click **Install** and enter: ``` n8n-nodes-chainstream ``` 4. Confirm the installation and restart n8n if prompted. ## Authentication The node authenticates via API credentials issued from your ChainStream dashboard. 1. In your ChainStream dashboard, navigate to **Settings > API Keys**. 2. Create a new key pair. You will receive: * **API Client ID** * **API Client Secret** 3. In n8n, go to **Credentials > New Credential > ChainStream API**. 4. Enter the Client ID and Client Secret, then save. ```json theme={null} { "credentials": { "chainstreamApi": { "clientId": "cs_live_xxxxxxxxxxxxxxxx", "clientSecret": "your_client_secret_here" } } } ``` ## Supported Resources & Operations | Resource | Operations | | ---------- | -------------------------------------------------------------------------------------------------- | | **Token** | Get metadata, get prices, list holders, query liquidity, run security audit, list mint/burn events | | **Trade** | List trades, get activities, view leaderboards | | **Wallet** | Query balances, get PnL, list activity | ## Node Configuration Below is a sample n8n node configuration for querying token metadata: ```json theme={null} { "nodes": [ { "parameters": { "resource": "token", "operation": "getMetadata", "chain": "solana", "tokenAddress": "So11111111111111111111111111111111111111112" }, "name": "ChainStream", "type": "n8n-nodes-chainstream.chainstream", "typeVersion": 1, "position": [450, 300], "credentials": { "chainstreamApi": { "id": "1", "name": "ChainStream API" } } } ] } ``` Fetching token price data: ```json theme={null} { "parameters": { "resource": "token", "operation": "getPrice", "chain": "solana", "tokenAddress": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", "currency": "usd" }, "name": "Get Token Price", "type": "n8n-nodes-chainstream.chainstream", "typeVersion": 1, "position": [450, 300] } ``` Querying wallet balances: ```json theme={null} { "parameters": { "resource": "wallet", "operation": "getBalances", "chain": "solana", "walletAddress": "9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM" }, "name": "Get Wallet Balance", "type": "n8n-nodes-chainstream.chainstream", "typeVersion": 1, "position": [650, 300] } ``` ## Example Workflows ### 1. Price Alert Bot Monitor a token price and send a Telegram notification when it crosses a threshold. ```json theme={null} { "nodes": [ { "parameters": { "resource": "token", "operation": "getPrice", "chain": "solana", "tokenAddress": "So11111111111111111111111111111111111111112", "currency": "usd" }, "name": "Get SOL Price", "type": "n8n-nodes-chainstream.chainstream", "typeVersion": 1, "position": [450, 300] }, { "parameters": { "conditions": { "number": [ { "value1": "={{ $json.price }}", "operation": "largerEqual", "value2": 200 } ] } }, "name": "Price Threshold", "type": "n8n-nodes-base.if", "position": [650, 300] }, { "parameters": { "chatId": "-100XXXXXXXXXX", "text": "SOL price alert: ${{ $json.price }}" }, "name": "Telegram Alert", "type": "n8n-nodes-base.telegram", "position": [850, 200] } ] } ``` ### 2. Portfolio Tracker Run on a schedule to fetch wallet balances and append rows to a Google Sheet. ```json theme={null} { "nodes": [ { "parameters": { "rule": { "interval": [{ "field": "hours", "hoursInterval": 1 }] } }, "name": "Every Hour", "type": "n8n-nodes-base.scheduleTrigger", "position": [250, 300] }, { "parameters": { "resource": "wallet", "operation": "getBalances", "chain": "solana", "walletAddress": "YOUR_WALLET_ADDRESS" }, "name": "Fetch Balances", "type": "n8n-nodes-chainstream.chainstream", "typeVersion": 1, "position": [450, 300] }, { "parameters": { "operation": "append", "sheetId": "YOUR_SHEET_ID", "range": "Sheet1!A:D" }, "name": "Google Sheets", "type": "n8n-nodes-base.googleSheets", "position": [650, 300] } ] } ``` ### 3. Whale Watcher Detect large wallet activity and send a Slack notification. ```json theme={null} { "nodes": [ { "parameters": { "resource": "wallet", "operation": "getActivity", "chain": "solana", "walletAddress": "WHALE_WALLET_ADDRESS" }, "name": "Whale Activity", "type": "n8n-nodes-chainstream.chainstream", "typeVersion": 1, "position": [450, 300] }, { "parameters": { "channel": "#whale-alerts", "text": "Whale movement detected: {{ $json.type }} of {{ $json.amount }} {{ $json.token }}" }, "name": "Slack Notification", "type": "n8n-nodes-base.slack", "position": [650, 300] } ] } ``` ### 4. Compliance Scanner When a new deposit arrives, run a KYT (Know Your Transaction) check and flag suspicious activity. ```json theme={null} { "nodes": [ { "parameters": { "resource": "wallet", "operation": "getActivity", "chain": "ethereum", "walletAddress": "DEPOSIT_WALLET_ADDRESS", "activityType": "deposit" }, "name": "New Deposits", "type": "n8n-nodes-chainstream.chainstream", "typeVersion": 1, "position": [250, 300] }, { "parameters": { "resource": "token", "operation": "securityAudit", "chain": "ethereum", "tokenAddress": "={{ $json.tokenAddress }}" }, "name": "KYT Check", "type": "n8n-nodes-chainstream.chainstream", "typeVersion": 1, "position": [450, 300] }, { "parameters": { "conditions": { "boolean": [ { "value1": "={{ $json.flagged }}", "operation": "equal", "value2": true } ] } }, "name": "Flagged?", "type": "n8n-nodes-base.if", "position": [650, 300] } ] } ``` ## Next Steps Set up real-time event-driven triggers with ChainStream webhooks. Explore the full ChainStream API that powers this node. # Trigger Node Source: https://docs.chainstream.io/en/docs/ecosystem/n8n/trigger-node Receive real-time on-chain events in n8n using the ChainStream Trigger node. # ChainStream Trigger Node The `ChainstreamTrigger` node enables event-driven workflows in n8n. Instead of polling for changes on a schedule, this node receives real-time events from ChainStream via webhooks and kicks off your workflow the moment something happens on-chain. ## How It Works ``` ChainStream Event ──webhook POST──> n8n Webhook URL ──> ChainstreamTrigger Node ──> Your Workflow ``` 1. n8n exposes a webhook endpoint when the trigger node is active. 2. You register that endpoint in your ChainStream dashboard. 3. When a matching on-chain event occurs, ChainStream sends a POST request to the webhook. 4. The trigger node parses the payload and starts the workflow. ## Setup ### Step 1 -- Add the Trigger Node In the n8n workflow editor: 1. Click **Add Node** and search for **ChainStream Trigger**. 2. Drag the node onto the canvas as the first node in your workflow. 3. Select the **Event Type** you want to listen for (see table below). ### Step 2 -- Copy the Webhook URL Once the trigger node is placed: 1. Open the node settings. 2. Copy the **Webhook URL** displayed at the top. It will look like: ``` https://your-n8n-instance.com/webhook/chainstream-trigger/XXXXXXXX ``` In production mode, use the **Production URL** (not the test URL) so the trigger remains active when the workflow editor is closed. ### Step 3 -- Register the Webhook in ChainStream 1. In your ChainStream dashboard, go to **Settings > Webhooks**. 2. Click **Create Webhook**. 3. Paste the n8n webhook URL. 4. Select the event types to subscribe to. 5. Save and activate. ### Step 4 -- Test the Connection 1. In n8n, click **Listen for Test Event** on the trigger node. 2. In ChainStream, click **Send Test Event** on the webhook you just created. 3. Verify that the trigger node receives the payload. ## Supported Events | Event | Description | Example Payload Field | | ---------------------- | --------------------------------------------------------- | ----------------------------------------- | | `token.price.change` | A token price moves beyond a configured threshold | `tokenAddress`, `price`, `changePercent` | | `token.transfer.large` | A transfer exceeds a specified value | `from`, `to`, `amount`, `tokenAddress` | | `token.new` | A new token is detected on a monitored chain | `tokenAddress`, `chain`, `name`, `symbol` | | `trade.activity` | Trade activity is detected for a monitored pair or wallet | `tradeType`, `amount`, `wallet`, `pair` | ## Node Configuration ```json theme={null} { "nodes": [ { "parameters": { "event": "token.price.change", "options": { "chain": "solana", "tokenAddress": "So11111111111111111111111111111111111111112", "threshold": 5 } }, "name": "ChainStream Trigger", "type": "n8n-nodes-chainstream.chainstreamTrigger", "typeVersion": 1, "position": [250, 300], "webhookId": "chainstream-trigger", "credentials": { "chainstreamApi": { "id": "1", "name": "ChainStream API" } } } ] } ``` ## Event Payloads ### token.price.change ```json theme={null} { "event": "token.price.change", "timestamp": "2026-03-26T12:00:00Z", "data": { "chain": "solana", "tokenAddress": "So11111111111111111111111111111111111111112", "symbol": "SOL", "price": 185.42, "previousPrice": 176.10, "changePercent": 5.29, "currency": "usd" } } ``` ### token.transfer.large ```json theme={null} { "event": "token.transfer.large", "timestamp": "2026-03-26T12:05:00Z", "data": { "chain": "solana", "tokenAddress": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", "symbol": "USDC", "from": "9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM", "to": "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1", "amount": 2500000, "txSignature": "5K4u...xQ7p" } } ``` ### token.new ```json theme={null} { "event": "token.new", "timestamp": "2026-03-26T12:10:00Z", "data": { "chain": "solana", "tokenAddress": "NEW_TOKEN_MINT_ADDRESS", "name": "Example Token", "symbol": "EXT", "decimals": 9, "creator": "CREATOR_WALLET_ADDRESS" } } ``` ### trade.activity ```json theme={null} { "event": "trade.activity", "timestamp": "2026-03-26T12:15:00Z", "data": { "chain": "solana", "tradeType": "buy", "wallet": "TRADER_WALLET_ADDRESS", "pair": "SOL/USDC", "amount": 1500, "price": 185.42, "dex": "raydium", "txSignature": "3Fj2...mN8k" } } ``` ## Example: Large Transfer to Telegram Alert A complete workflow that sends a Telegram message when a large USDC transfer is detected. ```json theme={null} { "nodes": [ { "parameters": { "event": "token.transfer.large", "options": { "chain": "solana", "tokenAddress": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", "minAmount": 1000000 } }, "name": "Large Transfer Trigger", "type": "n8n-nodes-chainstream.chainstreamTrigger", "typeVersion": 1, "position": [250, 300], "webhookId": "large-transfer", "credentials": { "chainstreamApi": { "id": "1", "name": "ChainStream API" } } }, { "parameters": { "chatId": "-100XXXXXXXXXX", "text": "Large USDC transfer detected:\nFrom: {{ $json.data.from }}\nTo: {{ $json.data.to }}\nAmount: {{ $json.data.amount }} USDC\nTx: {{ $json.data.txSignature }}" }, "name": "Telegram", "type": "n8n-nodes-base.telegram", "position": [450, 300] } ], "connections": { "Large Transfer Trigger": { "main": [[{ "node": "Telegram", "type": "main", "index": 0 }]] } } } ``` ## Troubleshooting | Issue | Solution | | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | Trigger not firing | Verify the webhook is **active** in the ChainStream dashboard and the workflow is **activated** in n8n (not just open in the editor). | | Test events work but live events do not | Make sure you are using the **production** webhook URL, not the test URL. | | Duplicate events | ChainStream may retry on timeout. Ensure your n8n instance responds within 10 seconds. Use the `txSignature` or event `timestamp` to deduplicate. | | Authentication errors | Confirm your ChainStream API credentials are correctly configured in the n8n credential store. | ## Next Steps See all available resources and operations in the ChainStream n8n node. Manage webhook subscriptions programmatically via the ChainStream API. # Cross-Agent Compatibility Source: https://docs.chainstream.io/en/docs/ecosystem/openclaw/cross-agent-compatibility Compatibility table and configuration details for installing ChainStream skills across 40+ AI agents. ## Overview The ChainStream skill package (`chainstream-io/skills`) is distributed through the [Vercel Skills CLI](https://skills.dev), which supports **40+ AI agents**. A single command installs and configures the ChainStream MCP tools for your agent of choice. ```bash theme={null} npx skills add chainstream-io/skills ``` ## Compatibility Table The table below lists the most commonly used agents with their install commands and configuration file locations. | Agent | Install Command | Config Location | | -------------- | ----------------------------------------------------- | ---------------------------------- | | OpenClaw | `npx skills add chainstream-io/skills -a openclaw` | `skills/` or `~/.openclaw/skills/` | | Claude Code | `npx skills add chainstream-io/skills -a claude-code` | `.claude.json` | | Cursor | `npx skills add chainstream-io/skills -a cursor` | Cursor MCP settings | | Cline | `npx skills add chainstream-io/skills -a cline` | Cline config | | GitHub Copilot | `npx skills add chainstream-io/skills -a copilot` | `.github/copilot/` | | Codex | `npx skills add chainstream-io/skills -a codex` | Codex config | ## Agent-Specific Details ### OpenClaw The Skills CLI writes the configuration to the OpenClaw skills directory: * **Project-level**: `./skills/chainstream.yaml` * **User-level**: `~/.openclaw/skills/chainstream.yaml` Generated configuration: ```yaml theme={null} skills: chainstream: type: mcp url: https://mcp.chainstream.io/mcp env: CHAINSTREAM_API_KEY: ${CHAINSTREAM_API_KEY} ``` Set the environment variable before running your agent: ```bash theme={null} export CHAINSTREAM_API_KEY=your-key openclaw run ``` ### Claude Code The Skills CLI adds the MCP server entry to `.claude.json` in your project root: ```json theme={null} { "mcpServers": { "chainstream": { "command": "npx", "args": ["@chainstream-io/mcp"], "env": { "CHAINSTREAM_API_KEY": "your-key" } } } } ``` See also: [Stdio Transport](/en/docs/ai-agents/mcp-server/setup) for manual Claude Code setup. ### Cursor The Skills CLI configures the MCP server in Cursor's settings. The configuration appears under **Settings > Features > MCP Servers**: | Field | Value | | ------- | ------------------------- | | Name | `chainstream` | | Type | `stdio` | | Command | `npx @chainstream-io/mcp` | For project-level config, the CLI writes to `.cursor/mcp.json`: ```json theme={null} { "mcpServers": { "chainstream": { "command": "npx", "args": ["@chainstream-io/mcp"], "env": { "CHAINSTREAM_API_KEY": "your-key" } } } } ``` ### Cline The Skills CLI adds the server to Cline's MCP configuration: ```json theme={null} { "mcpServers": { "chainstream": { "command": "npx", "args": ["@chainstream-io/mcp"], "env": { "CHAINSTREAM_API_KEY": "your-key" } } } } ``` ### GitHub Copilot The Skills CLI writes configuration to `.github/copilot/mcp.json` in your repository: ```json theme={null} { "mcpServers": { "chainstream": { "command": "npx", "args": ["@chainstream-io/mcp"], "env": { "CHAINSTREAM_API_KEY": "your-key" } } } } ``` ### Codex The Skills CLI adds the MCP server to your Codex agent configuration: ```json theme={null} { "mcpServers": { "chainstream": { "command": "npx", "args": ["@chainstream-io/mcp"], "env": { "CHAINSTREAM_API_KEY": "your-key" } } } } ``` ## Auto-Detection When you run `npx skills add chainstream-io/skills` without the `-a` flag, the CLI auto-detects your environment by checking for: 1. Agent-specific config files in the current directory 2. Agent CLI tools installed globally 3. IDE-specific directories and settings If multiple agents are detected, the CLI prompts you to choose. ## Updating To update the ChainStream skill to the latest version: ```bash theme={null} npx skills update chainstream-io/skills ``` ## Removing To remove the ChainStream skill: ```bash theme={null} npx skills remove chainstream-io/skills ``` This removes the configuration entry from your agent's config file but does not delete your API key. ## Next Steps Explore all 15 MCP tools available after installation. Security considerations for the ChainStream integration. # OpenClaw Integration Source: https://docs.chainstream.io/en/docs/ecosystem/openclaw/overview Add on-chain intelligence to OpenClaw agents with ChainStream's MCP tools, token analytics, and DEX execution. ## Overview [OpenClaw](https://openclaw.ai) is an open-source AI agent framework with **300K+ GitHub stars**, widely used for building autonomous agents that interact with tools, APIs, and external systems. ChainStream integrates with OpenClaw as an **on-chain intelligence layer**, giving agents the ability to query blockchain data, analyze tokens, profile wallets, execute trades, and receive real-time alerts -- all through the standard MCP protocol. ## What Agents Can Do With ChainStream connected, OpenClaw agents gain access to the full on-chain toolkit: | Capability | Description | Example Tools | | ------------------------ | --------------------------------------------------------------- | --------------------------------------------------- | | **Token Analysis** | Search, analyze, and compare tokens across 10 chains | `tokens_search`, `tokens_analyze`, `tokens_compare` | | **Wallet Profiling** | Profile wallet holdings, PnL, and transaction history | `wallets_profile`, `wallets_activity` | | **DEX Execution** | Get quotes and execute swaps on decentralized exchanges | `dex_quote`, `dex_swap` | | **Compliance Screening** | Check token security flags, honeypot detection, authority risks | `tokens_analyze` (security fields) | | **Real-Time Alerts** | Set up webhook-based notifications for on-chain events | `webhooks_manage` | | **Market Discovery** | Find trending, new, and graduating tokens | `market_trending`, `tokens_discover` | ## Integration Paths There are two ways to connect ChainStream to your OpenClaw agents: Install the ChainStream skill from ClawHub or via the cross-agent Vercel Skills CLI. Fastest setup -- works in under a minute. Connect via the cloud MCP endpoint or the local npm package. Best for custom agent configurations. ## Architecture ``` ┌─────────────────┐ MCP Protocol ┌──────────────────┐ │ │ ◄──────────────────► │ │ │ OpenClaw Agent │ 15 Tools │ ChainStream MCP │ │ │ 4 Prompts │ Server │ │ │ 4 Resources │ │ └─────────────────┘ └────────┬─────────┘ │ ┌────────▼─────────┐ │ ChainStream API │ │ 10 Chains │ │ 8+ DEXes │ └──────────────────┘ ``` The OpenClaw agent communicates with ChainStream through the MCP protocol. Whether you install via ClawHub or self-host, the agent sees the same 15 tools, 4 prompts, and 4 resources. ## Prerequisites Before setting up the integration: 1. **ChainStream API Key** -- Sign up at [app.chainstream.io](https://app.chainstream.io) and create an API key 2. **OpenClaw** -- An existing OpenClaw agent or project ([OpenClaw docs](https://docs.openclaw.ai)) 3. **Node.js 18+** -- Required for the MCP server and CLI tools ## Next Steps Three ways to install: Vercel Skills CLI, ClawHub, or direct MCP config. Security considerations and best practices for production use. # Security Considerations Source: https://docs.chainstream.io/en/docs/ecosystem/openclaw/security Security review, risk flags, and best practices for using ChainStream with OpenClaw agents. ## ClawHub Security Review The ChainStream skill published on ClawHub (`chainstream/chainstream-data`) has been flagged as **suspicious** with **medium confidence** by ClawHub's automated security scanner. This flag does not mean the skill is malicious. It indicates that certain patterns in the skill's behavior warrant careful review before production use. ### Flagged Behaviors The scanner identified three behaviors that triggered the warning: | Behavior | Risk Level | Description | | ---------------------------------------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------- | | Wallet creation with private key storage | High | The skill includes instructions for creating wallets and storing private keys, which could expose sensitive cryptographic material | | x402 auto-payment | Medium | The x402 payment protocol can automatically authorize spending, reducing visibility into outgoing transactions | | Remote npm execution | Low | The skill uses `npx` to fetch and execute packages from npm at runtime | ### What This Means * **Wallet creation**: Some ChainStream tools (`dex_swap`, `dex_create_token`, `transaction_send`) require wallet access. The skill documentation includes wallet setup instructions that involve private key handling. * **x402 auto-payment**: The x402 protocol enables machine-to-machine micropayments. When enabled, agents can authorize small payments without explicit per-transaction approval. * **Remote npm execution**: Using `npx @chainstream-io/mcp` downloads and executes the package from the npm registry. While this is standard practice, it introduces a supply chain dependency. ## Best Practices Follow these guidelines to use ChainStream safely with OpenClaw agents in production. ### 1. Prefer Dashboard API Keys Over Wallet Creation Use API keys generated from the [ChainStream Dashboard](https://app.chainstream.io) for authentication. API keys provide read access to on-chain data without requiring wallet creation or private key management. ```yaml theme={null} skills: chainstream: type: mcp url: https://mcp.chainstream.io/mcp env: CHAINSTREAM_API_KEY: your-dashboard-key # No wallet needed ``` API keys are sufficient for all read-only tools: token search, analysis, wallet profiling, market data, and trade history. Wallet access is only required for execution tools (`dex_swap`, `dex_create_token`, `transaction_send`). ### 2. Never Import Production Private Keys If your use case requires execution tools, **never import private keys** from wallets holding significant funds. * Create a dedicated test wallet with minimal funds * Fund it only with the amount needed for the specific operation * Treat any wallet connected to an AI agent as a hot wallet with elevated risk ``` DO: Create a fresh wallet with 0.1 SOL for testing swaps DON'T: Import your main wallet with 100 SOL into an agent config ``` ### 3. Verify npm Packages Before Running Before running `npx @chainstream-io/mcp`, verify the package: ```bash theme={null} # Check package details on npm npm view @chainstream-io/mcp # Check the publisher npm view @chainstream-io/mcp maintainers # Pin a specific version instead of using latest npx @chainstream-io/mcp@0.0.3 ``` For production deployments, install a pinned version globally rather than using `npx`: ```bash theme={null} npm install -g @chainstream-io/mcp@0.0.3 ``` ### 4. Run in Isolated Environments Run the MCP server and OpenClaw agent in isolated environments to limit blast radius: * **Docker containers** with restricted network access * **Dedicated VMs** or cloud instances * **Sandboxed agent runtimes** with limited filesystem access ```dockerfile theme={null} FROM node:20-slim # Non-root user RUN useradd -m agent USER agent RUN npm install -g @chainstream-io/mcp@0.0.3 CMD ["chainstream-mcp"] ``` ### 5. Require Explicit Approval for Payment Flows Configure your OpenClaw agent to require human-in-the-loop confirmation for any tool that moves funds: * `dex_swap` -- executes token swaps * `dex_create_token` -- creates tokens (may require SOL) * `transaction_send` -- broadcasts signed transactions In your OpenClaw agent configuration: ```yaml theme={null} agent: confirmation_required: - dex_swap - dex_create_token - transaction_send ``` If using x402 auto-payment, set explicit spending limits: ```yaml theme={null} agent: x402: max_per_transaction: 0.01 # USD max_daily: 1.00 # USD require_approval_above: 0.10 # USD ``` ### 6. Monitor Wallet Transactions If you connect a wallet to your agent, actively monitor its activity: * Set up webhook alerts for outgoing transactions using `webhooks_manage` * Review wallet activity regularly using `wallets_activity` * Use a block explorer to independently verify agent-initiated transactions ```bash theme={null} # Example: Set up a webhook for wallet activity # (via the agent or direct API call) webhooks_manage action=create url=https://your-server.com/alerts events=["wallet_transfer"] ``` ## Security Checklist Use this checklist before deploying ChainStream with OpenClaw in production: * [ ] API key stored in environment variables, not in code or config files * [ ] No production private keys imported into agent configuration * [ ] npm package version pinned (not using `latest`) * [ ] Agent runs in an isolated environment (Docker, VM, sandbox) * [ ] Execution tools (`dex_swap`, `dex_create_token`, `transaction_send`) require human approval * [ ] x402 auto-payment disabled or capped with spending limits * [ ] Wallet monitoring and alerting configured * [ ] Regular review of agent transaction logs ## Reporting Issues If you discover a security vulnerability in the ChainStream MCP server or ClawHub skill: * **ChainStream**: Email [security@chainstream.io](mailto:security@chainstream.io) * **ClawHub**: Report via the ClawHub skill page at [clawhub.ai/chainstream/chainstream-data](https://clawhub.ai/chainstream/chainstream-data) ## Next Steps Choose an installation method that fits your security requirements. Run your own MCP server for maximum control. # Installation Methods Source: https://docs.chainstream.io/en/docs/ecosystem/openclaw/skills-install Three ways to install ChainStream skills for OpenClaw agents: Vercel Skills CLI, ClawHub, or direct MCP configuration. ## Overview There are three ways to connect ChainStream to your OpenClaw agent. Choose the method that best fits your workflow. | Method | Best For | Setup Time | | ------------------------------------------------ | ---------------------------------------------- | ------------ | | [Vercel Skills CLI](#method-1-vercel-skills-cli) | Cross-agent compatibility, supports 40+ agents | \~30 seconds | | [ClawHub](#method-2-clawhub) | OpenClaw-native, community ecosystem | \~1 minute | | [Direct MCP Config](#method-3-direct-mcp-config) | Full control, custom deployments | \~2 minutes | ## Method 1: Vercel Skills CLI The Vercel Skills CLI is a cross-agent package manager that installs ChainStream skills into any supported AI agent with a single command. ### Quick Install ```bash theme={null} npx skills add chainstream-io/skills ``` This auto-detects your agent environment and configures the ChainStream MCP tools accordingly. ### Agent-Specific Install To target a specific agent: ```bash theme={null} npx skills add chainstream-io/skills -a openclaw ``` ### Supported Agents The Vercel Skills CLI supports **40+ agents**, including: | Agent | Install Command | | -------------- | ----------------------------------------------------- | | OpenClaw | `npx skills add chainstream-io/skills -a openclaw` | | Claude Code | `npx skills add chainstream-io/skills -a claude-code` | | Cursor | `npx skills add chainstream-io/skills -a cursor` | | Cline | `npx skills add chainstream-io/skills -a cline` | | GitHub Copilot | `npx skills add chainstream-io/skills -a copilot` | | Codex | `npx skills add chainstream-io/skills -a codex` | See [Cross-Agent Compatibility](/en/docs/ecosystem/openclaw/cross-agent-compatibility) for the full compatibility table and config file locations. After installation, set your API key as an environment variable: ```bash theme={null} export CHAINSTREAM_API_KEY=your-key ``` ## Method 2: ClawHub [ClawHub](https://clawhub.ai) is the native skill marketplace for OpenClaw. The ChainStream skill is published as a community package. ### Skill Details | Field | Value | | --------- | ------------------------------------------------------------------------------------------ | | URL | [clawhub.ai/chainstream/chainstream-data](https://clawhub.ai/chainstream/chainstream-data) | | Version | 3.1.1 | | MCP Tools | 17 | | License | MIT-0 | ### Install via CLI ```bash theme={null} openclaw skills install chainstream-data ``` ### Install via ClawHub UI 1. Visit [clawhub.ai/chainstream/chainstream-data](https://clawhub.ai/chainstream/chainstream-data) 2. Click **Install** 3. Follow the on-screen instructions to configure your API key ### Configure API Key After installing from ClawHub, set the API key in your OpenClaw agent configuration: ```yaml theme={null} skills: chainstream-data: env: CHAINSTREAM_API_KEY: your-key ``` The ClawHub skill exposes 17 MCP tools (the 15 core tools plus 2 ClawHub-specific utilities). See the [Tools Reference](/en/docs/ai-agents/mcp-server/introduction) for details on the core toolset. ## Method 3: Direct MCP Config Configure the ChainStream MCP server directly in your OpenClaw agent's configuration file. ChainStream offers two connection modes: ### Cloud Endpoint (Recommended) Connect to the hosted MCP endpoint — zero installation, always up-to-date: ```yaml theme={null} skills: chainstream: type: mcp url: https://mcp.chainstream.io/mcp env: CHAINSTREAM_API_KEY: your-key ``` ### Local npm Package Run the MCP server locally via the `@chainstream-io/mcp` npm package. The package connects to ChainStream's API on your behalf — useful when your agent framework requires a local stdio process: ```yaml theme={null} skills: chainstream: type: mcp command: npx args: - "@chainstream-io/mcp" env: CHAINSTREAM_API_KEY: your-key ``` See [MCP Server Setup](/en/docs/ai-agents/mcp-server/setup) for detailed configuration with Claude Desktop, Cursor, and other clients. ## Verify Installation After installing with any method, verify the tools are available by asking your OpenClaw agent: ``` What ChainStream tools do you have access to? ``` The agent should list the available tools, including `tokens_search`, `tokens_analyze`, `wallets_profile`, and others. ## Next Steps Full compatibility table for all supported agents and their config locations. Important security considerations for production deployments. # ChainStream Documentation Source: https://docs.chainstream.io/en/docs/home The multi-chain Web3 data service — one API for on-chain data, compliance, and DeFi execution. ChainStream is a **multi-chain Web3 data service**. One API, one GraphQL endpoint, one WebSocket stream and one Kafka cluster give you every token, trade, wallet and pool across Solana, Ethereum, BSC, Base, Polygon, Arbitrum, Optimism and more — with built-in KYT/KYA compliance and first-class AI-agent support. Solana, Ethereum, BSC, Base, Polygon, Arbitrum, Optimism, Avalanche, zkSync, Tron **\<100 ms** Kafka p99, \<2 ms WebSocket tick **99.99%** multi-region SLA Tokens · Trades · Wallets · Pools · Candles · Holders · KYT ## Start here Make your first authenticated API call in under 5 minutes. Browse every dataset we publish — fields, refresh rate, coverage. Pick REST, GraphQL, WebSocket, Kafka, an SDK or the CLI. Every endpoint, topic and tool — fully documented and playable. ## What ChainStream gives you ### Unified multi-chain data A single schema across every supported chain. Token prices, DEX trades, wallet PnL, pool liquidity, holder distributions, OHLC candles, Smart-Money activity and raw blockchain core data — all reachable through the same authentication, the same IDs, and the same dimensional filters. ### Real-time delivery that fits your stack Request-response. Ideal for dashboards, user-facing lookups and ad-hoc analytics. Sub-second pushes to browsers, mobile apps and backend services that need live UI updates. Exactly-once delivery for latency-sensitive backends — trading engines, indexers, alert pipelines. ### Built-in compliance KYT (Know Your Transaction) and KYA (Know Your Address) sit inside the same API as the data itself. Score a transfer, fingerprint a counterparty, produce Travel-Rule-ready reports — no second vendor, no second invoice, no second data-exfiltration surface. ### First-class support for AI agents ChainStream is reachable from AI agents the same way it is from any other client. A hosted MCP Server exposes our catalog as typed tools, Agent Skills ship as installable SKILL.md packs, and agent-friendly authentication (API keys, OAuth or x402/MPP micropayments) means agents can pay-per-query without prior account setup. ## How teams use it Real-time balances, PnL and transfer history; KYT screening on deposits and withdrawals. DEX trades, candles and order-flow streams straight into trading engines and research notebooks. MCP Server and Agent Skills for Claude, ChatGPT, Cursor and custom agents. KYT/KYA for transfers, addresses, withdrawals; exportable reports. Swap quotes, routing, transaction submission — across 10+ chains with unified signing. GraphQL over a normalized cube — aggregate, group, filter without per-chain boilerplate. ## Why ChainStream
| | **ChainStream** | Birdeye | Alchemy | DexScreener | Bitquery | | :------------------- | :--------------------- | :----------- | :--------- | :---------- | :---------- | | Multi-chain coverage | 10+ chains, one schema | Solana-first | 30+ chains | Multi-chain | 40+ chains | | Stream delivery | WebSocket + Kafka | WebSocket | WebSocket | WebSocket | Streaming | | Smart Money | Native dataset | Supported | — | — | Via queries | | KYT / KYA compliance | Built-in | — | — | — | — | | DEX execution | Quote + route + swap | — | Limited | — | — | | AI-agent surface | MCP + Skills + x402 | MCP (beta) | — | — | — | | Enterprise SLA | 99.99% | Limited | Enterprise | Limited | Limited |
## Next steps Start with REST for lookups or GraphQL for analytics. Pick WebSocket for clients, Kafka Streams for services. Wire up the MCP Server or install an Agent Skill. KYT, KYA, transfers, withdrawals — all in one API. # Authentication Source: https://docs.chainstream.io/en/docs/platform/authentication/api-keys-oauth How to authenticate with ChainStream API — three methods for different use cases ## Architecture All API requests pass through a **gateway** that validates credentials before forwarding to backend services. The gateway delegates authentication and quota checking to an internal **auth & billing service**, ensuring every request is verified in a single hop. ```mermaid theme={null} sequenceDiagram participant Client participant GW as Gateway participant Auth as Auth & Billing participant Backend as Data / DeFi API Client->>GW: API request + credentials GW->>Auth: Validate credentials Note over Auth: API Key / JWT / Wallet Signature Auth-->>GW: Authenticated (identity + quota) GW->>Backend: Proxied request Backend-->>Client: Response ``` When authentication fails, the gateway returns an error directly (401 Unauthorized, or 402 Payment Required when x402 is enabled) without hitting the backend. *** ## Three Authentication Methods ChainStream supports **three** credential types, evaluated in this order: | Priority | Method | Header | Best For | | -------- | --------------------------- | ----------------------------- | -------------------------------------------------- | | 1 | **Wallet Signature (SIWX)** | `Authorization: SIWX ` | AI agents with on-chain wallets (x402 subscribers) | | 2 | **API Key** | `X-API-KEY: ` | Applications, scripts, CLI, MCP Server | | 3 | **JWT Bearer Token** | `Authorization: Bearer ` | Dashboard apps using OAuth 2.0 Client Credentials | If no valid credentials are found and x402 is enabled, the gateway returns **HTTP 402 Payment Required** with a pointer to `/x402/purchase`. This allows AI agents to auto-purchase a subscription. *** ## Method 1: API Key (Recommended) The simplest authentication method. Create an API Key in the Dashboard and pass it in the `X-API-KEY` header. ### Get an API Key Visit [ChainStream Dashboard](https://www.chainstream.io/dashboard) and login Find "Applications" in the sidebar Click "Create New App" to generate your API Key ### Use the API Key ```bash theme={null} curl https://api.chainstream.io/v2/token/sol/So11111111111111111111111111111111111111112 \ -H "X-API-KEY: your_api_key" ``` ```typescript theme={null} import { ChainStreamClient } from "@chainstream-io/sdk"; const cs = new ChainStreamClient({ apiKey: "your_api_key", }); const token = await cs.token.getToken("So11111111111111111111111111111111111111112", "solana"); ``` ```bash theme={null} chainstream config set --key apiKey --value your_api_key chainstream token info --chain sol --address So11111111111111111111111111111111111111112 ``` ```bash theme={null} export CHAINSTREAM_API_KEY=your_api_key npx @chainstream-io/mcp ``` ### How It Works 1. The gateway extracts the `X-API-KEY` header 2. The auth service validates the key against the database 3. On success, the request is forwarded with the associated organization and permission context 4. The key must be `active` and not expired Keep your API Key secure. Never commit it to code repositories. If compromised, revoke it immediately in the Dashboard. *** ## Method 2: JWT Bearer Token (OAuth 2.0) For applications that use the OAuth 2.0 Client Credentials flow. Exchange your Client ID and Client Secret for a JWT access token. ### Generate Access Token ```bash theme={null} curl -X POST "https://dex.asia.auth.chainstream.io/oauth/token" \ -H "Content-Type: application/json" \ -d '{ "client_id": "YOUR_CLIENT_ID", "client_secret": "YOUR_CLIENT_SECRET", "audience": "https://api.dex.chainstream.io", "grant_type": "client_credentials" }' ``` ```javascript theme={null} const response = await fetch('https://dex.asia.auth.chainstream.io/oauth/token', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ client_id: 'YOUR_CLIENT_ID', client_secret: 'YOUR_CLIENT_SECRET', audience: 'https://api.dex.chainstream.io', grant_type: 'client_credentials' }) }); const { access_token } = await response.json(); ``` ```python theme={null} import requests response = requests.post( 'https://dex.asia.auth.chainstream.io/oauth/token', json={ 'client_id': 'YOUR_CLIENT_ID', 'client_secret': 'YOUR_CLIENT_SECRET', 'audience': 'https://api.dex.chainstream.io', 'grant_type': 'client_credentials' } ) access_token = response.json()['access_token'] ``` ### Use the Token ```bash theme={null} curl https://api.chainstream.io/v2/token/sol/So11111111111111111111111111111111111111112 \ -H "Authorization: Bearer YOUR_ACCESS_TOKEN" ``` ### How It Works 1. The gateway extracts the `Authorization: Bearer ` header 2. The auth service validates the JWT signature, issuer, and audience 3. The `client_id` claim is resolved to an organization for quota tracking ### Token Details * **Validity**: 24 hours by default * **Algorithm**: RS256 * **Issuer**: `https://dex.asia.auth.chainstream.io/` * **Audience**: `https://api.dex.chainstream.io` ### Scope Permissions Certain endpoints require specific scopes: | Scope | Description | Applicable Endpoints | | --------------- | -------------------- | ------------------------------------------------- | | `webhook.read` | Webhook read access | Query Webhook configuration | | `webhook.write` | Webhook write access | Create/modify/delete Webhooks | | `kyt.read` | KYT read access | Query risk assessment results | | `kyt.write` | KYT write access | Submit transactions/addresses for risk assessment | ```javascript theme={null} const response = await auth0Client.oauth.clientCredentialsGrant({ audience: 'https://api.dex.chainstream.io', scope: 'webhook.read webhook.write kyt.read kyt.write' }); ``` If no scope is specified, the token can access all general API endpoints. Scope is only required for Webhook and KYT endpoints. *** ## Method 3: Wallet Signature (SIWX) For AI agents with on-chain wallets that have purchased a subscription via [x402 payment](/en/docs/platform/billing-payments/x402-payments). Uses the **Sign-In with X (SIWX)** standard (EIP-4361 for EVM, equivalent for Solana). ### How It Works 1. The agent constructs a standard sign-in message with domain, address, nonce, and expiration 2. The agent signs the message with their wallet private key 3. The signed token is sent as `Authorization: SIWX base64(message).signature` 4. The auth service verifies the signature and checks for a valid x402 subscription 5. If a valid, non-expired subscription exists, authentication succeeds ### Token Format ``` Authorization: SIWX base64(message).signature ``` The message follows the EIP-4361 format: ``` api.chainstream.io wants you to sign in with your Ethereum account: 0xYourWalletAddress Sign in to ChainStream API URI: https://api.chainstream.io Version: 1 Chain ID: 8453 Nonce: abc123 Issued At: 2026-03-26T10:00:00Z Expiration Time: 2026-03-27T10:00:00Z ``` ### Supported Chains | Chain | Address Format | Signature Type | | -------------------- | --------------------------- | ---------------------- | | EVM (Base, Ethereum) | `0x` prefixed, 40 hex chars | EIP-191 personal\_sign | | Solana | Base58 encoded, 32-44 chars | Ed25519 | ### SDK Usage ```typescript theme={null} const cs = new ChainStreamClient({ auth: { type: "siwx", address: "0xYourWalletAddress", signMessage: async (message: string) => { return await wallet.signMessage(message); }, }, }); ``` SIWX authentication requires an active x402 subscription. If the subscription has expired, the request will be rejected. See [x402 Payment](/en/docs/platform/billing-payments/x402-payments) for purchasing a subscription. *** ## WebSocket Authentication WebSocket connections use the same three authentication methods. The gateway: 1. Detects WebSocket upgrade requests 2. Validates credentials before allowing the handshake 3. Tracks the session for usage metering 4. Reports usage metrics (bytes transferred, duration) on disconnect WebSocket tokens can also be passed as a query parameter: ``` wss://realtime-dex.chainstream.io/connection/websocket?token=YOUR_ACCESS_TOKEN ``` *** ## Authentication Priority When multiple credentials are present in a single request, they are evaluated in this order: 1. **SIWX** -- if `Authorization` header starts with `SIWX ` and x402 is configured 2. **API Key** -- if `X-API-KEY` header is present 3. **JWT Bearer** -- if `Authorization` header starts with `Bearer ` 4. **402 Payment Required** -- if no credentials match and x402 is enabled The first successful match wins. Subsequent methods are not evaluated. *** ## API Endpoints | Service | URL | | -------------------- | -------------------------------------------------------- | | Mainnet API | `https://api.chainstream.io/` | | WebSocket | `wss://realtime-dex.chainstream.io/connection/websocket` | | Auth Service (OAuth) | `https://dex.asia.auth.chainstream.io/` | | x402 Pricing | `https://api.chainstream.io/x402/pricing` | | x402 Purchase | `https://api.chainstream.io/x402/purchase` | *** ## Choosing an Auth Method **Best for**: Applications, scripts, CLI, MCP Server Simplest setup. Create in Dashboard, pass as header. No token refresh needed. **Best for**: Dashboard apps, server-to-server Standard OAuth 2.0 flow. Supports scoped permissions. 24h token TTL. **Best for**: AI agents with on-chain wallets Wallet-native auth via x402 subscription. No API key management needed. *** ## FAQ **API Key** is recommended for most use cases. It's the simplest to set up and works with all ChainStream products (SDK, CLI, MCP Server). Use **JWT** if you need OAuth 2.0 integration with scoped permissions. Use **SIWX** if you're building an AI agent with its own wallet and want to pay via x402. For JWT: generate a new token using your Client ID and Client Secret. For SIWX: sign a new message with a future expiration time. API Keys do not expire unless you set an expiration date in the Dashboard. Only one method is evaluated per request. If you send both `X-API-KEY` and `Authorization: Bearer`, the API Key takes priority (SIWX > API Key > JWT). When no valid credentials are found and x402 is enabled, the gateway returns HTTP 402 with instructions to purchase a subscription at `/x402/purchase`. This enables AI agents to auto-purchase access. See [x402 Payment](/en/docs/platform/billing-payments/x402-payments). **API Key**: Delete the App in the Dashboard. The key is invalidated immediately. **JWT**: Revoke the Client ID/Secret in the Dashboard. **SIWX**: The subscription expires naturally; there is no manual revocation. # Wallet Authentication (SIWX) Source: https://docs.chainstream.io/en/docs/platform/authentication/wallet-auth-siwx Authenticate with ChainStream using a wallet signature instead of an API key, supporting EVM and Solana. Sign-In with X (SIWX) lets you authenticate with ChainStream by signing a message with your wallet on every API request — no API Key or OAuth token needed. This is designed for **AI agents with on-chain wallets** that have purchased a subscription via [x402 payment](/en/docs/platform/billing-payments/x402-payments). SIWX replaces the API Key. Instead of passing `X-API-KEY`, you pass `Authorization: SIWX ` on each request. The gateway verifies the signature and checks for a valid x402 subscription in real time. ## How It Works Unlike traditional challenge/response flows, SIWX is **stateless and self-contained**. The client constructs and signs the message locally, then attaches it to every request. ```mermaid theme={null} sequenceDiagram participant Agent as AI Agent participant GW as Gateway participant Auth as Auth & Billing Note over Agent: Construct EIP-4361 message
(domain, address, nonce, expiry) Note over Agent: Sign with wallet private key Agent->>GW: API request + Authorization: SIWX token GW->>Auth: Validate SIWX signature Note over Auth: 1. Verify signature (EVM/Solana)
2. Check x402 subscription exists
3. Subscription not expired Auth-->>GW: Authenticated (org + quota) GW->>Agent: API response ``` ### Step-by-Step 1. **Construct an EIP-4361 message** with your wallet address, domain, nonce, and expiration time 2. **Sign the message** with your wallet private key 3. **Encode as SIWX token**: `base64(message).signature` 4. **Attach to every API request**: `Authorization: SIWX ` 5. The gateway verifies the signature and checks that the wallet has an active x402 subscription 6. If valid, the request proceeds normally (same as API Key auth) ## Token Format ``` Authorization: SIWX base64(message).signature ``` The message follows the EIP-4361 standard: ``` api.chainstream.io wants you to sign in with your Ethereum account: 0xYourWalletAddress Sign in to ChainStream API URI: https://api.chainstream.io Version: 1 Chain ID: 8453 Nonce: abc123def456 Issued At: 2026-03-26T10:00:00Z Expiration Time: 2026-03-27T10:00:00Z ``` ### Required Fields | Field | Description | | --------------- | ---------------------------------------------------------- | | Domain | Must be `api.chainstream.io` | | Address | Your wallet address (EVM `0x...` or Solana base58) | | URI | `https://api.chainstream.io` | | Version | `1` | | Nonce | A random string (client-generated, for replay protection) | | Issued At | ISO 8601 timestamp | | Expiration Time | ISO 8601 timestamp (the token is rejected after this time) | The expiration time is set by the client. You can sign a message valid for minutes, hours, or days. A longer expiration means fewer re-signs, but a shorter one is more secure. ## Supported Chains | Chain | Address Format | Signature Verification | | -------------------- | --------------------------- | -------------------------------- | | EVM (Base, Ethereum) | `0x` prefixed, 40 hex chars | EIP-191 `personal_sign` recovery | | Solana | Base58 encoded, 32-44 chars | Ed25519 signature verification | ## Prerequisites SIWX authentication requires an **active x402 subscription** linked to the wallet address. Without a subscription, the gateway rejects the request with an error. To get a subscription: ```bash theme={null} # Via CLI (automatic) chainstream login chainstream token info --chain sol --address So11111111111111111111111111111111111111112 # → 402 triggers plan selection → x402 payment → API Key saved # Or via direct x402 purchase curl https://api.chainstream.io/x402/purchase?plan=nano # → Follow x402 payment flow ``` See [x402 Payment](/en/docs/platform/billing-payments/x402-payments) for details. ## Usage Examples ### cURL ```bash theme={null} # 1. Construct and sign the message (using your preferred tool) # 2. Base64-encode the message and append the signature TOKEN="base64EncodedMessage.signatureHex" # 3. Use on any API call curl https://api.chainstream.io/v2/token/sol/So11111111111111111111111111111111111111112 \ -H "Authorization: SIWX $TOKEN" ``` ### SDK ```typescript theme={null} import { ChainStreamClient } from "@chainstream-io/sdk"; const cs = new ChainStreamClient({ auth: { type: "siwx", address: "0xYourWalletAddress", signMessage: async (message: string) => { return await wallet.signMessage(message); }, }, }); const token = await cs.token.getToken("So11111111111111111111111111111111111111112", "sol"); ``` ### CLI The CLI uses SIWX automatically when you log in with a wallet: ```bash theme={null} chainstream login chainstream token info --chain sol --address So11111111111111111111111111111111111111112 ``` ## SIWX vs API Key | | SIWX | API Key | | ------------------------- | -------------------------------- | --------------------------- | | **Header** | `Authorization: SIWX ` | `X-API-KEY: ` | | **Credential management** | No key to store — sign on demand | Store and protect the key | | **Prerequisite** | Wallet + x402 subscription | Dashboard account | | **Best for** | AI agents with wallets | Applications, scripts, MCP | | **Token expiry** | Set by client (per-message) | Set in Dashboard (or never) | ## Security Considerations * **Stateless**: No server-side session. Each request is independently verified. * **Expiration**: The client controls token lifetime via the `Expiration Time` field. Expired tokens are rejected. * **Domain binding**: The message includes `api.chainstream.io` as the domain. Signatures for other domains are rejected. * **No private key exposure**: The wallet only signs a plaintext message — the private key is never transmitted. * **Subscription check**: Even with a valid signature, the request is rejected if the wallet has no active x402 subscription. # MPP Payment Protocol Source: https://docs.chainstream.io/en/docs/platform/billing-payments/mpp-payments Machine Payment Protocol — pay for API access with stablecoins on Tempo or credit cards via Stripe. MPP (Machine Payment Protocol) is a payment protocol designed for AI agents and automated systems. It is the superset of x402, supporting both **Tempo stablecoin payments** and **Stripe card payments** in a single unified flow. Unlike x402 which only supports on-chain USDC, MPP adds Tempo network stablecoins and traditional card payments as additional options. ## How It Works ```mermaid theme={null} sequenceDiagram participant Agent as AI Agent participant API as ChainStream API participant MPP as MPP Service Agent->>API: GET /mpp/purchase?plan=nano API->>MPP: Route to MPP handler MPP-->>Agent: 402 + payment challenge (Tempo / Stripe options) Note over Agent: Agent selects payment method
and completes payment Agent->>API: Retry with Payment credential MPP-->>Agent: 200 { apiKey, plan, expiresAt } Note over Agent: API Key saved for future use ``` ### Detailed Flow 1. **Agent calls** `GET /mpp/purchase?plan=` without payment credentials 2. **MPP service returns 402** with a `WWW-Authenticate: Payment` challenge containing amount, currency, and recipient 3. **Agent signs the payment** using Tempo Wallet or Stripe 4. **Agent retries** the purchase request with `Authorization: Payment` credential 5. **MPP service verifies payment**, creates a subscription, and returns an API Key ## Supported Payment Methods | Method | Network | Currency | Gas Fee | Best For | | ---------- | --------------------- | --------------- | ---------------------------- | ----------------------------------------- | | **Tempo** | Tempo (chain ID 4217) | USDC.e (ERC-20) | **Free** (gas in stablecoin) | AI agents, no ETH needed | | **Stripe** | Traditional | USD (card) | N/A | Agents with card access, no crypto needed | Tempo payments do not require native gas tokens — gas is paid in the stablecoin directly. This makes it ideal for AI agents that only hold stablecoins. ## API Endpoints | Endpoint | Method | Description | | --------------------------- | ---------- | ---------------------------------------- | | `/mpp/purchase?plan=` | GET / POST | Purchase a subscription via MPP | | `/mpp/pricing` | GET | List available plans and payment methods | | `/mpp/health` | GET | Health check | ### Pricing Response ```bash theme={null} curl https://api.chainstream.io/mpp/pricing ``` ```json theme={null} { "plans": [ { "name": "nano", "priceUsd": 5, "quotaTotal": 500000, "durationDays": 30 }, { "name": "starter", "priceUsd": 199, "quotaTotal": 10000000, "durationDays": 30 } ], "currency": "USD", "paymentMethods": ["tempo", "stripe"], "note": "Prices in USD. Pay via MPP (Tempo stablecoin or Stripe card)." } ``` ### Purchase Response (Success) ```json theme={null} { "status": "ok", "plan": "nano", "expiresAt": "2026-04-25T12:00:00.000Z", "apiKey": "cs_live_..." } ``` ## CLI Usage The ChainStream CLI supports MPP as a payment option during the auto-purchase flow: ```bash theme={null} chainstream token info --chain sol --address So11111111111111111111111111111111111111112 # → 402 → plan selection → choose "MPP Tempo" → payment → API Key saved ``` For agents without a ChainStream wallet, the CLI prints the Tempo command: ```bash theme={null} tempo request "https://api.chainstream.io/mpp/purchase?plan=nano" ``` ## Manual Integration (Tempo Wallet) ### Setup Install the Tempo Wallet CLI and log in (one-time passkey authentication via browser): ```bash theme={null} curl -fsSL https://tempo.xyz/install | bash tempo wallet login ``` Tempo Wallet uses passkey (WebAuthn) authentication. The first setup requires a browser interaction. After that, the session persists and agent operations work without further browser interaction. ### Purchase ```bash theme={null} # Check your balance tempo wallet balance # Purchase a plan (auto-handles 402 → sign → retry) tempo request "https://api.chainstream.io/mpp/purchase?plan=nano" ``` The Tempo CLI handles the `WWW-Authenticate: Payment` challenge automatically, signs the transaction, and returns the API Key on success. ### Compatible Wallets Tempo is EVM-compatible (chain ID 4217). Any wallet holding USDC.e on Tempo works: * **Tempo Wallet CLI** (`tempo request`) — recommended, passkey auth, built-in MPP support * Any EVM wallet (MetaMask, Coinbase CDP, Privy) — add Tempo as custom network ## MPP vs x402 | | MPP | x402 | | -------------------------- | ------------------------------ | ------------------------------- | | **Payment methods** | Tempo stablecoin + Stripe card | On-chain USDC only | | **Networks** | Tempo (chain ID 4217) + Stripe | Base (EVM) + Solana | | **Gas fee** | Free (Tempo) / N/A (Stripe) | Free (facilitator) | | **Requires crypto wallet** | No (Stripe option available) | Yes | | **Purchase endpoint** | `/mpp/purchase` | `/x402/purchase` | | **Protocol** | MPP (HTTP 402) | x402 protocol | | **Best for** | Agents without crypto wallets | Agents with USDC on Base/Solana | ## Next Steps On-chain USDC payments via the x402 protocol Understand CU consumption and plan details # Billing and Units Source: https://docs.chainstream.io/en/docs/platform/billing-payments/plans-and-units Understanding ChainStream's billing model and quota management ## Overview ChainStream uses a **Unit-based billing model**. Different APIs consume different amounts of Units, and you can choose a plan that fits your business needs. *** ## Billing Model ### Plan Types **\$0 / month** * 30K Units/month * No overage * For development, POC **\$199 / month** * 10M Units/month * Overage: \$12.9/M * For small projects, MVP **\$699 / month** * 50M Units/month * Overage: \$9.9/M * For production, medium traffic **\$1,699 / month** * 200M Units/month * Overage: \$6.9/M * For large enterprises, high concurrency **Custom pricing** * Custom Units quota * Custom overage rate * Private deployment, dedicated SLA All plans will be blocked (return 403 error) when quota is exhausted. Paid plans can purchase additional quota in Dashboard to restore service. ### Plan Selection Guide **Use cases:** * Local development and debugging * Feature validation and demos * Learning and evaluating ChainStream API **Typical usage estimate:** * 300 price queries per day → \~9,000 Units/month **Limitations:** * Data may have 1-2 second delay * No SLA guarantee * Cannot continue calling after quota exhaustion **Use cases:** * Individual developer's small dApps * Trading bot prototypes * Small market display websites **Typical usage estimate:** * Market dashboard (10 tokens, refresh every minute) → \~43,200 Units/month * Small trading bot (1 query/second) → \~86,400 Units/month (single token) **Example scenario:** Building a Solana token market website showing 20 popular tokens, refreshing every 30 seconds: ``` 20 tokens × 2 times/min × 60 min × 24 hours × 30 days = 1,728,000 requests At 1 Unit/request = 1,728,000 Units/month ``` This scenario recommends Pro plan. **Use cases:** * Small/medium exchange or wallet data needs * Professional trading tools * Businesses requiring KYT/KYA risk control **Typical usage estimate:** * Medium market platform (100 tokens, real-time WebSocket) → \~500,000 Units/month * Deposit risk control (1000 KYT checks/day) → \~150,000 Units/month **Example scenario:** Running a small exchange that needs: * Market data: 50 trading pairs, WebSocket real-time push * Deposit risk control: 500 deposits/day, each with KYT check ``` WebSocket: 50 × 0.1 Unit/message × 86400 sec × 30 days ≈ 12,960,000 messages = 1,296,000 Units KYT: 500 × 5 Units × 30 days = 75,000 Units Total: ~1,371,000 Units/month ``` This scenario recommends Pro plan + overage budget, or contact sales for Enterprise quote. **Use cases:** * Large exchanges * Institutional quantitative trading * Private deployment or custom SLA requirements **Includes:** * Unlimited API calls * Dedicated technical support * Custom SLA (99.99%+) * Optional private deployment Contact sales for pricing. *** ## Units Calculation ### What is a Unit Unit is ChainStream's billing unit. Different APIs consume different amounts of Units - more complex APIs consume more. ### Data API Consumption Unit costs are tiered by computational complexity. Simple lookups cost less; aggregation-heavy and on-chain execution endpoints cost more. | API | CU | Endpoint | | :------------------ | :--- | :-------------------------------------------------------- | | Token Search | 0.25 | `GET /v2/token/search` | | Token Detail | 1.00 | `GET /v2/token/{chain}/{tokenAddress}` | | Batch Detail | 0.75 | `GET /v2/token/{chain}/multi` | | Token Metadata | 0.05 | `GET /v2/token/{chain}/{tokenAddress}/metadata` | | Batch Metadata | 0.05 | `GET /v2/token/{chain}/metadata/multi` | | Token Price | 0.10 | `GET /v2/token/{chain}/{tokenAddress}/price` | | Price History | 0.10 | `GET /v2/token/{chain}/{tokenAddress}/prices` | | Market Data | 0.10 | `GET /v2/token/{chain}/{tokenAddress}/marketData` | | Batch Market Data | 0.10 | `GET /v2/token/{chain}/marketData/multi` | | Token Stats | 2.50 | `GET /v2/token/{chain}/{tokenAddress}/stats` | | Batch Stats | 2.50 | `GET /v2/token/{chain}/stats/multi` | | Candles (OHLCV) | 0.25 | `GET /v2/token/{chain}/{tokenAddress}/candles` | | Pair Candles | 0.25 | `GET /v2/token/{chain}/pair/{pair}/candles` | | Pool Candles | 0.25 | `GET /v2/token/{chain}/pool/{poolAddress}/candles` | | Holders | 0.50 | `GET /v2/token/{chain}/{tokenAddress}/holders` | | Batch Holders | 0.50 | `GET /v2/token/{chain}/{tokenAddress}/holders/multi` | | Top Holders | 0.50 | `GET /v2/token/{chain}/{tokenAddress}/topHolders` | | Pools | 2.50 | `GET /v2/token/{chain}/{tokenAddress}/pools` | | Security | 0.50 | `GET /v2/token/{chain}/{tokenAddress}/security` | | Creation Info | 0.10 | `GET /v2/token/{chain}/{tokenAddress}/creation` | | Mint/Burn | 0.50 | `GET /v2/token/{chain}/{tokenAddress}/mintAndBurn` | | Traders by Tag | 0.50 | `GET /v2/token/{chain}/{tokenAddress}/traders/{tag}` | | Liquidity Snapshots | 0.50 | `GET /v2/token/{chain}/{tokenAddress}/liquiditySnapshots` | | Token List | 0.05 | `GET /v2/token/{chain}/list` | | Dev Tokens | 0.50 | `GET /v2/token/{chain}/dev/{devAddress}/tokens` | | Transfer Total | 0.25 | `GET /v2/token/{chain}/{tokenAddress}/transfer-total` | | Transfers | 0.25 | `GET /v2/token/{chain}/{tokenAddress}/transfers` | | API | CU | Endpoint | | :---------------- | :--- | :--------------------------------------------------------- | | Token Balances | 1.00 | `GET /v2/wallet/{chain}/{walletAddress}/tokens-balance` | | Balance Updates | 0.50 | `GET /v2/wallet/{chain}/{walletAddress}/balance-updates` | | PnL | 1.00 | `GET /v2/wallet/{chain}/{walletAddress}/pnl` | | PnL by Token | 1.00 | `GET /v2/wallet/{chain}/{walletAddress}/pnl-by-token` | | PnL Details | 1.50 | `GET /v2/wallet/{chain}/{walletAddress}/pnl-details` | | Calculate PnL | 1.50 | `POST /v2/wallet/{chain}/{walletAddress}/calculate-pnl` | | Net Worth | 1.00 | `GET /v2/wallet/{chain}/{walletAddress}/net-worth` | | Net Worth Chart | 1.00 | `GET /v2/wallet/{chain}/{walletAddress}/net-worth-chart` | | Net Worth Details | 1.00 | `GET /v2/wallet/{chain}/{walletAddress}/net-worth-details` | | Net Worth Tokens | 1.00 | `GET /v2/wallet/{chain}/{walletAddress}/net-worth/tokens` | | Transfers | 0.25 | `GET /v2/wallet/{chain}/{walletAddress}/transfers` | | Transfer Total | 0.25 | `GET /v2/wallet/{chain}/{walletAddress}/transfer-total` | | First Transaction | 0.10 | `GET /v2/wallet/{chain}/first-tx` | | Net Worth Summary | 1.00 | `GET /v2/wallet/{chain}/net-worth-summary` | | PnL by Wallet | 1.00 | `GET /v2/wallet/{chain}/pnl-by-wallet` | | Add to Watchlist | 0.05 | `POST /v2/watchlist/{chain}/{walletAddress}` | | API | CU | Endpoint | | :------------- | :--- | :-------------------------------------------- | | Trades | 0.25 | `GET /v2/trade/{chain}` | | Activities | 0.25 | `GET /v2/trade/{chain}/activities` | | Top Traders | 0.50 | `GET /v2/trade/{chain}/top-traders` | | Gainers/Losers | 0.50 | `GET /v2/trade/{chain}/trader-gainers-losers` | | API | CU | Endpoint | | :------------- | :--- | :------------------------------------------------- | | Pool Info | 0.50 | `GET /v2/dexpools/{chain}/{poolAddress}` | | Pool Snapshots | 0.50 | `GET /v2/dexpools/{chain}/{poolAddress}/snapshots` | | API | CU | Endpoint | | :-------------- | :--- | :--------------------------------------------- | | Hot Tokens | 0.25 | `GET /v2/ranking/{chain}/hotTokens/{duration}` | | New Tokens | 0.25 | `GET /v2/ranking/{chain}/newTokens` | | Migrated Tokens | 0.25 | `GET /v2/ranking/{chain}/migrated` | | Final Stretch | 0.25 | `GET /v2/ranking/{chain}/finalStretch` | | Stock Tokens | 0.25 | `GET /v2/ranking/{chain}/stocks` | | API | CU | Endpoint | | :------------- | :--- | :---------------------------- | | Supported DEXs | 0.05 | `GET /v2/dex` | | Quote | 0.25 | `GET /v2/dex/{chain}/quote` | | Route | 0.25 | `POST /v2/dex/{chain}/route` | | Token Creation | 5.00 | `POST /v2/dex/{chain}/create` | | Execute Swap | 5.00 | `POST /v2/dex/{chain}/swap` | | Job Status | 0.05 | `GET /v2/job/{id}` | | Job Streaming | 0.05 | `GET /v2/job/{id}/streaming` | | API | CU | Endpoint | | :--------------- | :--- | :------------------------------------------------ | | Supported Chains | 0.05 | `GET /v2/blockchain` | | Latest Block | 0.05 | `GET /v2/blockchain/{chain}/latest_block` | | Gas Price | 0.10 | `GET /v2/transaction/{chain}/gas-price` | | Gas Estimate | 0.25 | `POST /v2/transaction/{chain}/estimate-gas-limit` | | Send Transaction | 5.00 | `POST /v2/transaction/{chain}/send` | | API | CU | Endpoint | | :-------------- | :--- | :--------------------------------------------- | | List Endpoints | 0.05 | `GET /v2/webhook/endpoint` | | Create Endpoint | 0.05 | `POST /v2/webhook/endpoint` | | Get Endpoint | 0.05 | `GET /v2/webhook/endpoint/{id}` | | Update Endpoint | 0.05 | `PATCH /v2/webhook/endpoint` | | Delete Endpoint | 0.05 | `DELETE /v2/webhook/endpoint/{id}` | | Get Secret | 0.05 | `GET /v2/webhook/endpoint/{id}/secret` | | Rotate Secret | 0.10 | `POST /v2/webhook/endpoint/{id}/secret/rotate` | | API | CU | Endpoint | | :----------------- | :--- | :---------------------------------------------- | | List Red Packets | 0.05 | `GET /v2/redpacket` | | Get Red Packet | 0.05 | `GET /v2/redpacket/{id}` | | Get Claims | 0.05 | `GET /v2/redpacket/{id}/claims` | | Wallet Claims | 0.05 | `GET /v2/redpacket/wallet/{address}/claims` | | Wallet Red Packets | 0.05 | `GET /v2/redpacket/wallet/{address}/redpackets` | | Create Red Packet | 5.00 | `POST /v2/redpacket/{chain}/create` | | Claim Red Packet | 5.00 | `POST /v2/redpacket/{chain}/claim` | | Send Red Packet | 5.00 | `POST /v2/redpacket/{chain}/send` | ### CU Pricing Tiers | Tier | CU Cost | Description | Examples | | :----- | :------ | :-------------------------------- | :---------------------------------------------------- | | Tier 1 | 0.05 | Metadata, list, simple lookups | Token list, blockchain info, webhook CRUD, job status | | Tier 2 | 0.10 | Single-field queries | Price, market data, creation info, gas price | | Tier 3 | 0.25 | Search, trades, rankings, candles | Token search, OHLCV, trade activities, rankings | | Tier 4 | 0.50 | Holders, security, snapshots | Holders, security audit, pool snapshots, top traders | | Tier 5 | 1.00 | Full profile, PnL, net worth | Token detail, wallet PnL, net worth | | Tier 6 | 1.50 | Compute-heavy analytics | PnL details, calculate PnL | | Tier 7 | 2.50 | Aggregation-heavy | Token stats, pools (multi-source aggregation) | | Tier 8 | 5.00 | On-chain execution | Swap, token creation, send transaction | *** ## WebSocket Real-time Subscription Billing WebSocket real-time data subscriptions are billed separately, charged by data bytes: | Item | Rate | Description | | :------------------- | :------------------ | :------------------------------------ | | WebSocket Data | **0.005 Unit/byte** | Charged by push data bytes | | WebSocket Connection | Free | No charge for establishing connection | | Heartbeat Messages | Free | Heartbeat packets not charged | ### Supported Subscription Channels | Channel | Description | | :----------------------------------------------- | :-------------------- | | `dex-candle:{chain}_{tokenAddress}_{resolution}` | Real-time candle data | | Channel | Description | | :-------------------------------------------------- | :-------------------- | | `dex-token-stats:{chain}_{tokenAddress}` | Token statistics | | `dex-token-holding:{chain}_{tokenAddress}` | Holder statistics | | `dex-token-supply:{chain}_{tokenAddress}` | Supply and market cap | | `dex-token-general-stat-num:{chain}_{tokenAddress}` | Liquidity stats | | `dex-new-token:{chain}` | New token info | | `dex-new-tokens-metadata:{chain}` | New token metadata | | Channel | Description | | :----------------------------------------------------- | :------------------- | | `dex-ranking-list:{chain}_{ranking_type}` | Ranking token list | | `dex-ranking-token-stats-list:{chain}_{channelType}` | Ranking token stats | | `dex-ranking-token-holding-list:{chain}_{channelType}` | Ranking holder stats | | `dex-ranking-token-supply-list:{chain}_{channelType}` | Ranking supply | | Channel | Description | | :--------------------------------------------- | :--------------- | | `dex-wallet-balance:{chain}_{walletAddress}` | Wallet balance | | `dex-wallet-token-pnl:{chain}_{walletAddress}` | Token-level PnL | | `dex-wallet-pnl-list:{chain}_{walletAddress}` | Wallet-level PnL | | Channel | Description | | :----------------------------------------- | :------------ | | `dex-trade:{chain}_{tokenAddress}` | Token trades | | `dex-wallet-trade:{chain}_{walletAddress}` | Wallet trades | | Channel | Description | | :--------------------------------------- | :----------- | | `dex-pool-balance:{chain}_{poolAddress}` | Pool balance | ### WebSocket Usage Estimation Examples ``` Scenario: Monitor 10 tokens' real-time candles (1-minute resolution) Calculation: - Candle message ~200 bytes each - Each token ~1 candle message per minute - 10 tokens × 1 msg/min × 60 min × 24 hrs × 30 days = 432,000 messages - Total data: 432,000 × 200 = 86,400,000 bytes - Monthly: 86,400,000 × 0.005 = 432,000 Units Scenario: Monitor 50 tokens' stats (real-time, ~1 update/second) Calculation: - Token stats message ~500 bytes each - 50 tokens × 1 msg/sec × 86,400 sec × 30 days = 129,600,000 messages - Total data: 129,600,000 × 500 = 64,800,000,000 bytes (~64.8 GB) - Monthly: 64,800,000,000 × 0.005 = 324,000,000 Units (~324M) ``` Batch APIs typically have discounts. Refer to API Reference for exact consumption. WebSocket message frequency depends on market activity; high volatility periods will increase message volume. *** ## KYT/KYA Service Billing KYT/KYA APIs **do not consume plan Units**. They are charged from a separate KYT account balance (in USD). Please top up at Dashboard → KYT Service. | API | Cost | Endpoint | | :------------------------------ | :---------- | :---------------------------------------------------------------------- | | Register Transfer | \$0.25/call | `POST /v2/kyt/transfer` | | Register Withdrawal | \$0.25/call | `POST /v2/kyt/withdrawal` | | Register Address | \$1.25/call | `POST /v2/kyt/address` | | Query Risk / Alerts / Exposures | Included | `GET /v2/kyt/addresses/*/risk`, `GET /v2/kyt/transfers/*/summary`, etc. | *** ### Cost Estimation Examples **Scenario:** A DeFi market website showing 50 token prices, refreshing every 10 seconds ``` Calculation: - Request frequency: 50 tokens × 6 times/min = 300 requests/min - Monthly requests: 300 × 60 × 24 × 30 = 12,960,000 requests - CU per request: 0.10 (Token Price endpoint) - Monthly CU: 12,960,000 × 0.10 = 1,296,000 CU Recommended: Starter plan (10M CU) ``` **Scenario:** An arbitrage bot monitoring 5 trading pairs, querying price every second ``` REST approach: - 5 × 1/sec × 86,400 × 30 = 12,960,000 requests - CU: 12,960,000 × 0.10 = 1,296,000 CU WebSocket approach (recommended): - 5 pairs × ~200 bytes/msg × 1 msg/sec × 86,400 × 30 - = 2,592,000,000 bytes × 0.005 CU/byte = 12,960,000 CU Recommended: Pro plan for REST; Starter for WebSocket ``` **Scenario:** Small exchange, 1000 deposits/day requiring KYT check ``` Calculation: - Daily: 1,000 KYT transfer registrations - Monthly: 1,000 × 30 = 30,000 calls - Cost: 30,000 × $0.25 = $7,500/month (KYT billed separately in USD) Note: KYT does not consume plan CU. Top up KYT balance separately. ``` *** ## Quota Management ### View Usage in Dashboard Visit [ChainStream Dashboard](https://www.chainstream.io/dashboard) Check current month usage, remaining quota, and historical trends on the Usage page ### Quota Alert Settings You can set quota alerts to receive notifications when usage reaches thresholds: | Alert Level | Trigger Condition | Notification Method | | :---------- | :---------------- | :---------------------- | | Reminder | 50% usage | Email | | Warning | 80% usage | Email + Dashboard alert | | Critical | 100% usage | Email + Dashboard alert | We recommend enabling at least the 80% alert to avoid unexpected service interruption. *** ## Quota Exhaustion Handling ### What Happens When Quota Runs Out When monthly quota is exhausted, API will return 403 error and cannot continue to be called. Paid plan users can manually purchase additional quota to restore service. | Plan | Handling Method | | :------------------------- | :---------------------------------------------------------------------- | | Free | API returns 403 error, wait for next month's quota reset | | Starter / Pro / Enterprise | API returns 403 error, can purchase additional quota to restore service | | Custom | Per contract terms | ### Purchase Additional Quota Paid plan users can purchase additional quota in Dashboard, priced according to the plan's overage rate: | Plan | Additional Quota Price | | :--------- | :--------------------- | | Starter | \$12.9 / 1M Units | | Pro | \$9.9 / 1M Units | | Enterprise | \$6.9 / 1M Units | Service is interrupted immediately when quota is exhausted (returns 403 error). We recommend setting 80% usage alerts and purchasing additional quota in advance to avoid business impact. *** ## Payment Methods ### Supported Payment Methods | Method | Description | Applicable Plans | | :------------- | :--------------------------- | :---------------- | | Credit Card | Visa, MasterCard, AMEX | All plans | | Cryptocurrency | USDT, USDC (ERC-20 / TRC-20) | Starter and above | | Bank Transfer | Contact sales | Enterprise | ### Billing Cycle * **Monthly plans:** Invoice generated on the 1st for the previous month * **Annual plans:** Get 2 months free (equivalent to 16.7% discount) *** ## AI Agent Payment (x402 / MPP) For AI agents that need programmatic access without dashboard signup, ChainStream supports two on-chain payment protocols: ### x402 (Base / Solana USDC) The [x402 protocol](https://www.x402.org/) enables HTTP-native micropayments. When an API call returns 402, the agent's wallet signs a USDC transfer and retries — no account registration required. | Property | Value | | -------- | --------------------------------------------------------- | | Networks | Base (chain ID 8453), Solana | | Currency | USDC | | Standard | EIP-3009 (Base), native transfer (Solana) | | Gas Fee | **Free** — ChainStream's facilitator covers all gas costs | You only pay the subscription price in USDC. ChainStream operates its own x402 facilitator that submits the on-chain transaction and pays the gas fee on your behalf — the agent wallet does not need ETH or SOL for gas. ### MPP (Tempo USDC.e) MPP uses the Tempo network for payments. Gas is paid in USDC.e directly — no ETH needed. | Property | Value | | -------- | --------------------- | | Network | Tempo (chain ID 4217) | | Currency | USDC.e | ### How It Works 1. Agent calls any ChainStream API 2. Server returns 402 (no active subscription) 3. Agent fetches available plans from `/x402/pricing` 4. Agent purchases a plan via x402 or MPP 5. Server returns an **API Key** — agent saves it for all future calls Full details on x402 and MPP payment flows *** ## FAQ We recommend starting with the Free plan to evaluate actual usage, then choose based on monthly consumption: * \< 30K Units: Free * 30K - 10M Units: Starter * 10M - 50M Units: Pro * \> 50M Units: Enterprise Yes. Upgrades take effect immediately with prorated charges. Downgrades take effect in the next billing cycle. No. Monthly quotas reset at the end of each month and do not roll over. Download historical invoices from Dashboard → Billing → Invoices. Enterprise customers can contact sales for custom invoices. *** ## Next Steps Common questions Understand API security configuration Start calling APIs # x402 Payment Protocol Source: https://docs.chainstream.io/en/docs/platform/billing-payments/x402-payments Use the HTTP 402 Payment Required protocol for seamless API micropayments with USDC. x402 is a payment protocol built on the HTTP 402 Payment Required status code. It enables machine-to-machine micropayments for API access without manual billing, credit cards, or subscription management. Pay per request with USDC, and get instant API access. ## How It Works ```mermaid theme={null} sequenceDiagram participant Agent as AI Agent participant API as ChainStream API participant Facilitator as x402 Facilitator Agent->>API: GET /x402/purchase?plan=nano API-->>Agent: 402 + X-Payment-Required (payment challenge) Note over Agent: Sign USDC transfer
(EIP-3009 on Base / native on Solana) Agent->>API: Retry with Payment-Signature header API->>Facilitator: Verify signature + settle on-chain Note over Facilitator: Facilitator pays gas fee Facilitator-->>API: Settlement confirmed API-->>Agent: 200 { apiKey, plan, expiresAt } Note over Agent: API Key saved for future use ``` ### Detailed Flow 1. **Client sends a request** to the ChainStream API without an API key or with an expired key. 2. **Gateway returns HTTP 402** with a message pointing to `/x402/purchase`. 3. **Client calls `GET /x402/purchase?plan=`** (without payment header). The server returns HTTP 402 with the x402 payment requirements: | Response Header | Description | | -------------------- | ------------------------------------------ | | `X-Payment-Required` | Base64-encoded JSON with payment details | | `Payment-Required` | Same value (for x402 client compatibility) | The decoded JSON body follows the x402 v2 protocol: ```json theme={null} { "x402Version": 2, "resource": { "url": "/x402/purchase?plan=nano", "description": "ChainStream API access: nano plan" }, "accepts": [ { "scheme": "exact", "network": "eip155:8453", "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", "amount": "5000000", "payTo": "0xRecipientAddress", "maxTimeoutSeconds": 60 }, { "scheme": "exact", "network": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp", "asset": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", "amount": "5000000", "payTo": "SolanaRecipientAddress", "maxTimeoutSeconds": 60 } ] } ``` 4. **Client signs a USDC transfer** using the `@x402` SDK and retries `GET /x402/purchase?plan=` with the payment proof: | Request Header | Description | | ------------------- | ------------------------------------- | | `Payment-Signature` | Base64-encoded signed payment payload | 5. **Server verifies and settles the payment**, then returns the subscription details: ```json theme={null} { "status": "ok", "plan": "nano", "chain": "evm", "address": "0xPayerAddress", "expiresAt": "2026-04-25T12:00:00.000Z", "txHash": "0xabc123...", "apiKey": "cs_live_..." } ``` The client saves the `apiKey` for all future API calls. ## CLI Integration The ChainStream CLI handles x402 payments automatically via `callWithAutoPayment`. When any command hits a 402, the CLI guides you through plan selection and payment. ### Automatic Flow When the CLI encounters a 402 response, it: 1. Fetches available plans from `/x402/pricing` and displays a selection table 2. Prompts you to choose a plan 3. Asks for payment method: **x402** (USDC on Base/Solana) or **MPP** (USDC.e on Tempo) 4. If x402: signs and sends payment via `@x402/fetch`, saves the returned API Key to config 5. If MPP: prints the `tempo request` command for manual purchase 6. Retries the original command with the new API Key ```bash theme={null} $ chainstream token info --chain sol --address So11111111111111111111111111111111111111112 [chainstream] No active subscription. Available plans: # Plan Price Quota Duration ── ────────── ──────── ──────────────── ──────── 1 nano $5 500,000 CU 30 days 2 starter $199 10,000,000 CU 30 days 3 pro $699 50,000,000 CU 30 days Select plan (1-3): 1 [chainstream] Choose payment method: 1. x402 (USDC on Base/Solana) 2. MPP Tempo (USDC.e on Tempo) Select method (1-2): 1 [chainstream] Purchasing nano plan via x402... [chainstream] Subscription activated: nano (expires: 2026-04-25T12:00:00.000Z) [chainstream] API Key saved to config. ``` If you only have an API Key (no wallet), the CLI skips x402 and prints MPP instructions instead. ### Wallet Setup The CLI needs a funded wallet for x402 payments: ```bash theme={null} # Create a ChainStream TEE wallet (recommended) chainstream login # Or import a raw private key (dev/testing only) chainstream wallet set-raw --chain base ``` ## Manual Integration For custom integrations, you can implement the x402 flow using the `@x402` package family. ### Dependencies ```bash theme={null} npm install @x402/core @x402/evm @x402/svm @x402/fetch ``` | Package | Purpose | | ------------- | --------------------------------------------------- | | `@x402/core` | Protocol types, header parsing, verification logic | | `@x402/evm` | EVM payment execution (built on viem) | | `@x402/svm` | Solana payment execution (built on @solana/kit) | | `@x402/fetch` | Drop-in `fetch` wrapper with automatic 402 handling | ### Using @x402/fetch (Recommended) The simplest integration -- wrap the standard `fetch` with x402 support: ```typescript theme={null} import { createX402Fetch } from "@x402/fetch"; import { createWalletClient, http } from "viem"; import { base } from "viem/chains"; import { privateKeyToAccount } from "viem/accounts"; // Create a wallet for payments const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`); const walletClient = createWalletClient({ account, chain: base, transport: http(), }); // Create an x402-enabled fetch const x402Fetch = createX402Fetch({ evm: { walletClient }, autoApprove: true, // auto-pay without prompting maxAmount: "10.00", // safety cap per request }); // Use it like normal fetch -- 402 payments are handled automatically const response = await x402Fetch( "https://api.chainstream.io/v2/token/eth/0x1234abcd" ); const data = await response.json(); console.log(data); ``` ### Manual Flow (Advanced) For full control over the payment flow: ```typescript theme={null} import { parsePaymentHeaders, createPaymentProof } from "@x402/core"; import { sendPayment } from "@x402/evm"; // 1. Make the initial request (no auth, no payment yet) const response = await fetch("https://api.chainstream.io/v2/token/eth/0x1234abcd"); if (response.status === 402) { // 2. Parse payment details from headers const payment = parsePaymentHeaders(response.headers); console.log(`Payment required: ${payment.amount} USDC on ${payment.chain}`); // 3. Send the USDC payment const txHash = await sendPayment({ walletClient, to: payment.address, amount: payment.amount, token: payment.token, memo: payment.memo, }); // 4. Retry with payment signature const retryResponse = await fetch( "https://api.chainstream.io/x402/purchase?plan=nano", { headers: { "Payment-Signature": paymentSignature, }, } ); // 5. Extract the API key from the response const result = await retryResponse.json(); console.log("API key for future use:", result.apiKey); console.log("Expires at:", result.expiresAt); } ``` ## Supported Chains for Payment | Chain | Token | Confirmation Time | | ------ | ----- | ----------------- | | Base | USDC | \~2 seconds | | Solana | USDC | \~400ms | ## Zero Gas Fee ChainStream operates its own **x402 facilitator** that submits the on-chain payment transaction on behalf of the agent. This means: * **No gas fee** — the facilitator covers all gas costs (Base ETH / Solana SOL) * **Agent wallet only needs USDC** — no need to hold native tokens for gas * The agent signs a USDC transfer authorization; the facilitator broadcasts and pays for execution This removes the biggest friction point for AI agents: acquiring and managing native gas tokens across multiple chains. ## Security Considerations * **Payment caps**: Always set a `maxAmount` when using `@x402/fetch` to prevent unexpected charges. * **Verification**: The facilitator verifies the signed payment on-chain before settling. Invalid signatures are rejected. * **Idempotency**: If a payment is settled but the response fails (network error), the same `Payment-Signature` can be resubmitted. Payments are only consumed once. * **Compliance**: Payer addresses are screened before settlement. Sanctioned addresses are rejected. # API Security Source: https://docs.chainstream.io/en/docs/platform/security/api-security API security best practices and configuration guide ChainStream employs multiple security mechanisms to protect API access. This document covers API security best practices, common threat protection, and security configuration guidelines. **Last Updated:** February 2026 | **Version:** v2.0 *** ## Authentication Security ### Access Token Mechanism ChainStream uses an OAuth 2.0-based authentication mechanism. You generate a JWT Access Token using your Client ID and Client Secret for API authentication. **Authentication Flow:** ```mermaid theme={null} flowchart TD A[Create App in Dashboard] --> B[Get Client ID / Client Secret] B --> C[Call Auth0 Service for Token] C --> D[Get Access Token - JWT Format] D --> E[REST API: Authorization Header] D --> F[WebSocket: URL Parameter] ``` **Credential Specifications** | Item | Specification | | :------------- | :----------------------------------------- | | Client ID | Application unique identifier | | Client Secret | 64 random characters | | Access Token | JWT format, includes expiration and scopes | | Token Validity | 24 hours | ### Access Token Generation ```javascript JavaScript theme={null} import { AuthenticationClient } from 'auth0'; const auth0Client = new AuthenticationClient({ domain: 'dex.asia.auth.chainstream.io', clientId: process.env.CHAINSTREAM_CLIENT_ID, clientSecret: process.env.CHAINSTREAM_CLIENT_SECRET }); const { data } = await auth0Client.oauth.clientCredentialsGrant({ audience: 'https://api.dex.chainstream.io' }); const accessToken = data.access_token; ``` ```python Python theme={null} from auth0.authentication import GetToken get_token = GetToken( 'dex.asia.auth.chainstream.io', os.environ['CHAINSTREAM_CLIENT_ID'], client_secret=os.environ['CHAINSTREAM_CLIENT_SECRET'] ) token = get_token.client_credentials( audience='https://api.dex.chainstream.io' ) access_token = token['access_token'] ``` ### Credential Security **Storage Requirements** Client Secret is a core credential for accessing ChainStream services. Leakage may result in service abuse and financial loss. | Storage Method | Security Level | Notes | | :------------------------ | :------------- | :----------------------------------------- | | Environment Variables | ✅ Recommended | Not in version control | | Secret Management Service | ✅ Best | AWS Secrets Manager, HashiCorp Vault, etc. | | Config Files | ⚠️ Caution | Must add to .gitignore | | Hardcoded | ❌ Prohibited | High leak risk | ### Code Examples ```javascript JavaScript theme={null} // ❌ Dangerous: Hardcoded credentials const clientId = "your_client_id"; const clientSecret = "your_secret"; // ❌ Dangerous: Committed to version control // config.json: { "client_id": "...", "client_secret": "..." } // ✅ Secure: Use environment variables const clientId = process.env.CHAINSTREAM_CLIENT_ID; const clientSecret = process.env.CHAINSTREAM_CLIENT_SECRET; // ✅ Secure: Use secret management service const credentials = await secretsManager.getSecret('chainstream-credentials'); ``` ```python Python theme={null} import os # ❌ Dangerous: Hardcoded client_id = "your_client_id" client_secret = "your_secret" # ✅ Secure: Use environment variables client_id = os.environ.get('CHAINSTREAM_CLIENT_ID') client_secret = os.environ.get('CHAINSTREAM_CLIENT_SECRET') # ✅ Secure: Use secret management service (AWS Secrets Manager example) import boto3 client = boto3.client('secretsmanager') credentials = client.get_secret_value(SecretId='chainstream-credentials')['SecretString'] ``` ```go Go theme={null} // ❌ Dangerous: Hardcoded clientID := "your_client_id" clientSecret := "your_secret" // ✅ Secure: Use environment variables clientID := os.Getenv("CHAINSTREAM_CLIENT_ID") clientSecret := os.Getenv("CHAINSTREAM_CLIENT_SECRET") ``` ### Multi-App Management We recommend creating separate Apps for different environments and services: | Purpose | Suggested App Name | Description | | :--------- | :----------------- | :---------------------- | | Production | `prod-main` | Production workloads | | Testing | `test-dev` | Development and testing | | CI/CD | `ci-pipeline` | Automated testing | | Monitoring | `monitoring` | Monitoring and alerting | *** ## Transport Security ### TLS Requirements | Item | Requirement | | :--------------------- | :---------------- | | Minimum Version | TLS 1.2 | | Recommended Version | TLS 1.3 | | Certificate Validation | Must be enabled | | Not Supported | HTTP, TLS 1.0/1.1 | ### Certificate Validation Never skip certificate validation in production environments. This exposes your application to man-in-the-middle attack risks. ```javascript JavaScript theme={null} // ❌ Dangerous: Skip certificate validation process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; // ✅ Secure: Normal certificate validation (default behavior) const response = await fetch('https://api.chainstream.io/v1/...'); ``` ```python Python theme={null} import requests # ❌ Dangerous: Skip certificate validation requests.get(url, verify=False) # ✅ Secure: Normal certificate validation (default behavior) requests.get(url) ``` ```bash cURL theme={null} # ❌ Dangerous: Skip certificate validation curl -k https://api.chainstream.io/v1/... # ✅ Secure: Normal certificate validation (default behavior) curl https://api.chainstream.io/v1/... ``` *** ## Webhook Security Webhook messages use a signature mechanism to ensure message source reliability. ### Signature Verification When you receive a Webhook message, you need to verify the signature using your Webhook Secret to confirm the message is from ChainStream and has not been tampered with. | Item | Description | | :--------------- | :--------------------------------------- | | Algorithm | HMAC-SHA256 | | Key | Webhook Secret (configured in Dashboard) | | Signature Header | `X-Webhook-Signature` | ### Verification Example ```javascript JavaScript theme={null} const crypto = require('crypto'); function verifyWebhookSignature(payload, signature, secret) { const expectedSignature = crypto .createHmac('sha256', secret) .update(JSON.stringify(payload)) .digest('hex'); return crypto.timingSafeEqual( Buffer.from(signature), Buffer.from(expectedSignature) ); } // Express middleware example app.post('/webhook', (req, res) => { const signature = req.headers['x-webhook-signature']; const isValid = verifyWebhookSignature( req.body, signature, process.env.WEBHOOK_SECRET ); if (!isValid) { return res.status(401).send('Invalid signature'); } // Process webhook message console.log('Received webhook:', req.body); res.status(200).send('OK'); }); ``` ```python Python theme={null} import hmac import hashlib import json def verify_webhook_signature(payload, signature, secret): expected_signature = hmac.new( secret.encode(), json.dumps(payload).encode(), hashlib.sha256 ).hexdigest() return hmac.compare_digest(signature, expected_signature) # Flask example @app.route('/webhook', methods=['POST']) def webhook(): signature = request.headers.get('X-Webhook-Signature') is_valid = verify_webhook_signature( request.json, signature, os.environ['WEBHOOK_SECRET'] ) if not is_valid: return 'Invalid signature', 401 # Process webhook message print('Received webhook:', request.json) return 'OK', 200 ``` ### Webhook Secret Rotation To rotate your Webhook Secret: Dashboard → Webhooks → Select Endpoint → Rotate Secret Update to the new Webhook Secret in your application Confirm the new Secret correctly verifies signatures *** ## Usage Monitoring ### Metrics Dashboard In the Dashboard's Metrics panel, you can view API and WebSocket call statistics: | Metric | Description | | :------------- | :----------------------------------- | | Request IP | Source IP address | | User Agent | Client identifier | | Status Code | HTTP status code | | Latency | Request response time | | Units Consumed | Usage units consumed by this request | | Total Usage | Cumulative usage consumed | ### Chart Data The Metrics panel provides charts at multiple time dimensions: * **Hourly** — View call trends for the last 24 hours * **Daily** — View call trends for the last 30 days * **Monthly** — View historical monthly statistics **View Path:** Dashboard → Metrics *** ## Security Monitoring 🚧 **Coming Soon** — Security monitoring features are under development and will be available soon. Once available, it will support: * **Anomaly Detection** — Auto-detect auth failure spikes, unusual geography, etc. * **Alert Notifications** — Email and Webhook alerts * **Auto Protection** — Temporary bans, rate limiting, etc. *** ## IP Whitelist 🚧 **Coming Soon** — IP whitelist feature is under development and will be available soon. Once available, it will support: * Single IP configuration (e.g., `203.0.113.50`) * IP range configuration (e.g., `203.0.113.0/24`) * Multiple IPs (comma-separated) *** ## Common Attack Protection ### Man-in-the-Middle Attack **Attack Method:** Attacker intercepts communication between client and server. **Protection Measures:** | Measure | Description | | :--------------------- | :----------------------------------- | | Enforce HTTPS | Only TLS 1.2+ supported | | Certificate Validation | Must enable certificate verification | | HSTS | Force HTTPS connections | ### Injection Attack **Attack Method:** Attacker attempts unauthorized operations through malicious input data. **Protection Measures:** | Measure | Description | | :-------------------- | :----------------------------- | | Input Validation | Strict parameter type checking | | Parameterized Queries | Prevent SQL/NoSQL injection | | Output Encoding | Prevent XSS | ### Credential Leak Response If you suspect your Client Secret has been leaked, immediately execute the following steps: Dashboard → Apps → Select App → Delete Dashboard → Apps → Create New App Update to new Client ID and Secret in all applications using the old credential Dashboard → Metrics → Check for abnormal calls Investigate leak cause and improve security measures *** ## Security Error Codes ### Authentication Related | Error Code | HTTP Status | Description | | :-------------------- | :---------- | :---------------------------- | | `UNAUTHORIZED` | 401 | No authentication provided | | `EXPIRED_TOKEN` | 401 | Access Token expired | | `INVALID_TOKEN` | 401 | Access Token invalid | | `INVALID_CREDENTIALS` | 401 | Client ID or Secret incorrect | ### Access Control Related | Error Code | HTTP Status | Description | | :------------------- | :---------- | :------------------------------- | | `FORBIDDEN` | 403 | No permission or quota exhausted | | `RATE_LIMITED` | 429 | Request rate exceeded | | `INSUFFICIENT_SCOPE` | 403 | Token permission insufficient | ### Webhook Related | Error Code | Description | | :------------------ | :------------------------------------ | | `INVALID_SIGNATURE` | Webhook signature verification failed | | `MISSING_SIGNATURE` | Missing signature header | ### Error Response Example ```json theme={null} { "error": { "code": "EXPIRED_TOKEN", "message": "Access token has expired", "details": { "expired_at": "2024-01-15T10:30:00Z" } } } ``` *** ## Security Configuration Checklist ### Basic Configuration (Required) * [ ] Use HTTPS for API access * [ ] Store Client ID and Client Secret in environment variables or secret management service * [ ] Don't commit credentials to code repository * [ ] Use different Apps for production/test environments * [ ] Properly verify Webhook signatures ### Advanced Configuration (Recommended) * [ ] Integrate secret management service (AWS Secrets Manager / HashiCorp Vault) * [ ] Regularly check Metrics dashboard for call statistics * [ ] Create separate Apps for different services ### Enterprise Configuration (Optional) * [ ] Integrate SIEM system for log analysis * [ ] Establish security incident response process *** ## FAQ Immediately log into Dashboard to delete that App, create a new App, then update all application configurations using that credential. See [Credential Leak Response](#credential-leak-response). Access Tokens are valid for 24 hours. Recommendations: 1. **Cache Token** — Reuse the same Token within validity period 2. **Refresh Early** — Refresh Token about 1 hour before expiration 3. **Error Retry** — Automatically get new Token when receiving 401 error Log into Dashboard → Metrics, where you can view request IP, status codes, latency, Units consumed, and time-dimension charts. Common causes: 1. **Secret mismatch** — Confirm using the correct Webhook Secret 2. **Payload handling error** — Ensure using the original JSON string for signature calculation 3. **Missing signature header** — Confirm request headers include `X-Webhook-Signature` Yes. We recommend creating separate Apps for different environments (production/test) and different services for easier management and troubleshooting. *** ## Related Documentation Authentication and credential management Data privacy policy Complete error code list Webhook configuration and usage # Data Privacy Source: https://docs.chainstream.io/en/docs/platform/security/data-privacy Learn how ChainStream collects, processes, and protects your data ChainStream is committed to protecting user data privacy. This document explains how we collect, process, and protect your data, as well as your privacy rights. **Last Updated:** February 2025 | **Version:** v2.0 *** ## Data Collection Scope ### Data We Collect ChainStream only collects data necessary to provide our services: **Account Data** | Data Type | Collection Purpose | Necessity | | :------------ | :------------------------------------ | :---------------------- | | Email address | Account identification, notifications | Required | | Password hash | Account security | Required | | Company name | Enterprise customer identification | Optional | | Payment info | Billing processing | Required for paid users | **Usage Data** | Data Type | Collection Purpose | Retention Period | | :------------------ | :-------------------------------- | :---------------------------- | | API call records | Billing, performance optimization | 90 days | | Error logs | Troubleshooting | 30 days | | Feature usage stats | Product improvement | Long-term after anonymization | **Technical Data** | Data Type | Collection Purpose | | :----------- | :-------------------------------------- | | IP address | Security protection, geographic routing | | Device info | Compatibility optimization | | Browser type | Interface adaptation | ### Data We Don't Collect ChainStream commits to never collecting the following sensitive information: * **Private keys or seed phrases** — Our service architecture is designed without access to user private keys * **On-chain asset details** — We only provide query capabilities, we don't store asset information * **Real identity information** — No KYC required, no real identity association * **Associated identity of queried addresses** — Query requests are decoupled from identity *** ## Cookies and Tracking Technologies ### Cookie Usage | Cookie Type | Purpose | Can Be Disabled | | :----------------- | :--------------------------- | :-------------- | | Essential Cookies | Session management, security | No | | Functional Cookies | User preference settings | Yes | | Analytics Cookies | Service improvement | Yes | ### Cookie Management Users can manage cookies through browser settings. Disabling essential cookies may prevent the service from functioning properly. *** ## Data Processing Principles ### Minimization Principle We only collect and process the minimum data necessary for business operations. ### Purpose Limitation Data is only used for the following purposes: * Providing and improving services * Billing * Security protection * Customer support ### Transparency Principle * Clear disclosure of data usage * Advance notification of significant changes * Provision of data access channels *** ## Data Storage and Protection ### Storage Locations | Data Type | Storage Location | Backup Location | | :----------- | :--------------- | :-------------- | | Primary data | AWS Singapore | AWS Tokyo | | Log data | AWS Singapore | - | | Backup data | AWS Tokyo | - | ### Encryption Measures **Transmission Encryption** * All API communications use TLS 1.3 * WebSocket connections use WSS protocol * Insecure cipher suites are disabled **Storage Encryption** | Data Type | Encryption Method | | :------------- | :---------------- | | Database | AES-256 | | File storage | AES-256 | | Backups | AES-256 | | Key management | AWS KMS | ### Access Control * Role-Based Access Control (RBAC) * Least privilege principle * Access log auditing * Multi-factor authentication required ### Security Audits * Regular security assessments * Third-party penetration testing * Vulnerability response mechanism * Security incident notification *** ## Data Retention Periods | Data Type | Retention Period | Deletion Method | | :-------------- | :-------------------------- | :------------------- | | Account data | Account lifetime + 30 days | Automatic deletion | | API call logs | 90 days | Automatic deletion | | Error logs | 30 days | Automatic deletion | | Billing records | 7 years (legal requirement) | Deletion upon expiry | | Security logs | 1 year | Automatic deletion | After account deletion, we will clear all identifiable personal data within 30 days, except for data required to be retained by law. *** ## Third-Party Data Sharing ### Data Sharing Principles * **No data selling:** We never sell user data to third parties * **Minimal sharing:** Only share the minimum data required for services * **Contractual constraints:** All sub-processors sign data processing agreements ### Sub-processors Enterprise customers can contact [enterprise@chainstream.io](mailto:enterprise@chainstream.io) for the complete sub-processor list. *** ## User Rights ### Rights Overview | Right | Description | How to Exercise | | :--------------------- | :-------------------------------- | :-------------- | | Right of Access | Obtain a copy of your data | Email request | | Right of Rectification | Correct inaccurate data | Email request | | Right of Erasure | Request deletion of your data | Email request | | Right of Portability | Export in machine-readable format | Email request | | Right to Object | Object to certain data processing | Email request | ### Right of Access You have the right to request access to your personal data held by us. **How to request:** Send email to [privacy@chainstream.io](mailto:privacy@chainstream.io) ### Right of Rectification You have the right to request correction of inaccurate personal data. **How to exercise:** Send email to [privacy@chainstream.io](mailto:privacy@chainstream.io) ### Right of Erasure You have the right to request deletion of your personal data. **How to exercise:** * Account deletion: Send email to [privacy@chainstream.io](mailto:privacy@chainstream.io) * Complete deletion: Data will be cleared within 30 days * Retention exceptions: Data required by law to be retained ### Right of Portability You have the right to obtain a copy of your data. * **Supported formats:** JSON, CSV * **Export scope:** Account information, usage records * **How to request:** Send email to [privacy@chainstream.io](mailto:privacy@chainstream.io) * **Processing time:** Within 30 days ### Right to Object You have the right to object to certain data processing activities: * **Marketing communications:** Can unsubscribe at any time * **Data analytics:** Can opt out *** ## Compliance Statement ### GDPR Compliance ChainStream complies with the EU General Data Protection Regulation (GDPR): * Lawful basis for data processing * Data subject rights protection * Data protection impact assessment * Data breach notification mechanism ### CCPA Compliance For California users, we comply with the California Consumer Privacy Act: * Right to know * Right to delete * Right to opt-out * Right to non-discrimination ### Data Processing Agreement Enterprise customers can sign a Data Processing Agreement (DPA): * Standard Contractual Clauses (SCCs) * Data processing scope definition * Security measure commitments * Sub-processor list **How to apply:** Contact [enterprise@chainstream.io](mailto:enterprise@chainstream.io) ### Privacy Policy Updates * 30 days advance notice for significant changes * Update date clearly marked * Historical versions available for review *** ## FAQ **No.** ChainStream's architecture is designed to ensure we cannot access users' private keys or seed phrases. We only provide on-chain data reading services and do not involve any private key operations. API query records are only used for: billing statistics, service performance optimization, and anomaly detection. We do not analyze the specific address content of your queries, nor do we sell query data to third parties. After account deletion, we will clear all identifiable personal data within 30 days. However, billing-related records need to be retained for the legally required period. Primary data is stored in AWS Singapore region, backups are stored in AWS Tokyo region. You can exercise your rights to access, correct, delete, and export data by sending an email to [privacy@chainstream.io](mailto:privacy@chainstream.io). We will respond to your request within 30 days. *** ## Contact Information ### Privacy Inquiries | Matter | Contact | Response Time | | :-------------- | :------------------------------------------------------------ | :-------------- | | Privacy issues | [privacy@chainstream.io](mailto:privacy@chainstream.io) | 5 business days | | Data requests | [privacy@chainstream.io](mailto:privacy@chainstream.io) | Within 30 days | | Security issues | [security@chainstream.io](mailto:security@chainstream.io) | Within 24 hours | | Enterprise DPA | [enterprise@chainstream.io](mailto:enterprise@chainstream.io) | 3 business days | ### Complaints and Suggestions If you have any concerns about our data processing, you can: * Contact our privacy team * File a complaint with your local data protection authority *** ## Related Documentation API security best practices API error code reference # Quickstart Source: https://docs.chainstream.io/en/docs/quickstart Make your first authenticated ChainStream call in under 5 minutes. By the end of this guide you will have: * An API key (or OAuth token) * A working call against the ChainStream REST API * A working call against the ChainStream SDK, CLI and MCP Server * A clear pointer to whichever surface — REST, GraphQL, WebSocket, Kafka, SDK, CLI, MCP — best fits your workload Estimated time: **5 minutes**. ## Prerequisites A ChainStream account. [Sign up here](https://www.chainstream.io/dashboard) if you do not have one yet. ## 1. Get your API key 1. Open the [ChainStream Dashboard](https://www.chainstream.io/dashboard). 2. Go to **Applications**. 3. Click **Create New App**. 4. Copy the generated **API Key** (it starts with `cs_live_…`). An API key is the fastest way to authenticate. For machine-to-machine scenarios use the OAuth 2.0 client-credentials flow described in [API Keys & OAuth](/en/docs/platform/authentication/api-keys-oauth). ## 2. Make your first request This example fetches metadata for Wrapped SOL on Solana. Pick the interface that matches how you will integrate. ```bash theme={null} curl "https://api.chainstream.io/v2/token/solana/So11111111111111111111111111111111111111112/metadata" \ -H "X-API-KEY: your_api_key" ``` ```typescript theme={null} import { ChainStreamClient } from "@chainstream-io/sdk"; const cs = new ChainStreamClient({ apiKey: "your_api_key" }); const token = await cs.token.getToken( "So11111111111111111111111111111111111111112", "solana", ); console.log(token.name, token.symbol, token.decimals); ``` See [all SDKs](/en/sdks/overview) for Python, Go and Rust equivalents. ```bash theme={null} # Runs with no install — npx will fetch the latest CLI. npx @chainstream-io/cli token info \ --chain solana \ --address So11111111111111111111111111111111111111112 ``` On first run the CLI prompts for your key. You can also set it explicitly: ```bash theme={null} npx @chainstream-io/cli config set --key apiKey --value your_api_key ``` ```bash theme={null} CHAINSTREAM_API_KEY=your_api_key npx @chainstream-io/mcp ``` Then ask your agent *"What is the SOL token on Solana?"* — it will call the right tool. For Claude, Cursor and ChatGPT configuration see [MCP Server Setup](/en/docs/ai-agents/mcp-server/setup). For OAuth 2.0 Client Credentials: ```bash theme={null} curl -X POST "https://dex.asia.auth.chainstream.io/oauth/token" \ -H "Content-Type: application/json" \ -d '{ "client_id": "YOUR_CLIENT_ID", "client_secret": "YOUR_CLIENT_SECRET", "audience": "https://api.dex.chainstream.io", "grant_type": "client_credentials" }' curl "https://api.chainstream.io/v2/token/solana/So11111111111111111111111111111111111111112/metadata" \ -H "Authorization: Bearer YOUR_ACCESS_TOKEN" ``` ### Response ```json theme={null} { "chain": "solana", "address": "So11111111111111111111111111111111111111112", "name": "Wrapped SOL", "symbol": "SOL", "decimals": 9, "imageUrl": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/So11111111111111111111111111111111111111112/logo.png", "tokenCreatedAt": 1710417600000 } ``` | Field | Type | Description | | :--------------- | :------ | :-------------------------------- | | `chain` | string | Blockchain identifier, lowercase. | | `address` | string | Token contract address. | | `name` | string | Human-readable token name. | | `symbol` | string | Ticker symbol. | | `decimals` | integer | Token decimals. | | `imageUrl` | string | Canonical logo URL (may be null). | | `tokenCreatedAt` | integer | Creation timestamp (ms). | ## 3. Pick the right access method You just made a single request/response call. Real integrations usually need more than that. On-demand lookups — tokens, wallets, pools, trades, compliance. Flexible analytical queries over the full chain-data cube. Sub-second pushes for live UIs and browser apps. Exactly-once delivery into backends, indexers and trading engines. TypeScript, Python, Go, Rust — typed clients with auth built in. Scripting, CI/CD and pay-per-call access for AI agents. ## Troubleshooting * Confirm `X-API-KEY` or `Authorization: Bearer …` header is present and spelt correctly. * Regenerate a key if yours was rotated. * For OAuth, check the token hasn't expired (default TTL is 1 hour). You hit your plan's rate limit. Free plans start at 10 req/s; upgrade or back off exponentially. See [Plans & Units](/en/docs/platform/billing-payments/plans-and-units). Use the chain identifier in the URL: `solana`, `ethereum`, `bsc`, `base`, `polygon`, `arbitrum`, `optimism`, `avalanche`, `zksync`, `tron`. Full list in [Supported Chains](/en/docs/supported-chains). ## Next steps Every dataset we publish, with coverage and refresh rates. Subscribe to live trades, prices, transfers and pool events. KYT and KYA on transfers, withdrawals and counterparties. Connect Claude, Cursor or ChatGPT via MCP + Agent Skills. # DeFi Monitoring Overview Source: https://docs.chainstream.io/en/docs/recipes/defi-monitoring Key metrics and risk identification for DeFi protocol monitoring ChainStream currently supports **Solana** (`sol`), **Ethereum** (`eth`), and **BSC** (`bsc`). Supported DEXes are Jupiter, Raydium, PumpFun, Moonshot, Candy (Solana), and KyberSwap (Ethereum/BSC). Some examples below reference additional protocols for conceptual illustration — check [Supported Chains](/en/docs/supported-chains) for the current coverage. **Coming Soon** - This feature is currently under development. Stay tuned! This document introduces how to use ChainStream to monitor DeFi protocol activities, including liquidity changes, large trades, yield tracking, and risk alerts. *** ## Supported DeFi Protocols ### DEX (Decentralized Exchanges) | Protocol | Chains | Supported Features | | ------------- | ------------- | ----------------------- | | **Jupiter** | Solana | Aggregated trading | | **Raydium** | Solana | Trading, LP, Pool data | | **PumpFun** | Solana | Launch/bonding, trading | | **Moonshot** | Solana | Trading | | **Candy** | Solana | Trading | | **KyberSwap** | Ethereum, BSC | Trading, quotes | ### Other DeFi verticals Lending, yield aggregators, and liquid staking are common monitoring targets in DeFi generally. ChainStream’s indexed swap and DEX analytics focus on the protocols above on **Solana**, **Ethereum**, and **BSC**. Before building lending- or vault-specific alerts, confirm what your deployment exposes in the API reference and [Supported Chains](/en/docs/supported-chains). *** ## Monitoring Dimensions ### 1. Liquidity Monitoring #### Monitored Events | Event | Description | Importance | | ------------------ | ---------------------- | -------------------------- | | `pool_created` | New pool creation | Discover new opportunities | | `liquidity_add` | Add liquidity | Confidence indicator | | `liquidity_remove` | Remove liquidity | ⚠️ Rug pull warning | | `pool_update` | Pool parameter changes | Protocol governance | #### Key Metrics | Metric | Description | Healthy Standard | | --------------- | -------------------------------- | ----------------------- | | TVL | Total Value Locked | Stable or growing | | TVL Change Rate | 24h/7d TVL change | > -10%/day | | LP Holder Count | LP Token holder distribution | Dispersed is better | | Liquidity Depth | Liquidity within ±2% price range | Greater depth is better | #### Rug Pull Risk Signals * Single withdrawal > 30% of pool * 24h cumulative withdrawal > 50% * LP concentrated in few addresses (\< 5) * Single withdrawal > 10% of pool * LP lock expiring soon * Project team addresses start withdrawing * LP widely distributed * LP lock period > 6 months * TVL stable growth *** ### 2. Trading Monitoring #### Real-time Trading Flow Subscribe to real-time trades via WebSocket: | Event Type | Description | Data Fields | | ------------- | ----------------- | ------------------------------------ | | `swap` | DEX trade | token\_in, token\_out, amount, price | | `large_trade` | Large trade | threshold, trade\_details | | `arbitrage` | Arbitrage trade | profit, path | | `mev` | MEV-related trade | type, extracted\_value | ```typescript theme={null} // Subscribe to DEX trading flow ws.subscribe('defi_trades', { protocol: 'kyberswap', chain: 'eth', min_amount_usd: 10000 }, (trade) => { console.log(`${trade.type}: ${trade.token_in} → ${trade.token_out}`); }); ``` #### Trading Analysis Dimensions | Analysis Dimension | Metric | Significance | | ------------------ | ---------------------------- | ---------------- | | Buy/Sell Pressure | Buy volume/Sell volume ratio | > 1 bullish | | Volume Trend | Volume moving average | Activity level | | Whale Behavior | Large trade percentage | Market impact | | Pair Popularity | Trading frequency ranking | Market attention | *** ### 3. Yield Tracking #### Tracked Content | Yield Type | Description | Calculation Method | | -------------------- | ------------------------------------- | --------------------------- | | **LP Mining** | Trading fees from providing liquidity | Fees × Share percentage | | **Lending Interest** | Deposit/borrow interest | Principal × APY | | **Staking Rewards** | Protocol token rewards | Staked amount × Reward rate | | **Airdrop Yields** | Protocol airdrops | Snapshot holdings | #### Yield Metrics | Metric | Description | Notes | | -------------------- | -------------------------------------------- | ---------------------- | | **APY** | Annual Percentage Yield (with compounding) | Actual yield reference | | **APR** | Annual Percentage Rate (without compounding) | Base yield | | **Impermanent Loss** | LP loss relative to holding | Important risk factor | | **Net Yield** | Yield - Gas - Impermanent Loss | Final yield | #### Impermanent Loss Estimation **Impermanent Loss Formula** ``` Impermanent Loss = 2 × √(Price Ratio) / (1 + Price Ratio) - 1 ``` | Price Change | Impermanent Loss | | ------------ | ---------------- | | ±10% | -0.11% | | ±25% | -0.64% | | ±50% | -2.02% | | ±100% | -5.72% | | ±200% | -13.4% | *** ### 4. Risk Alerts #### Protocol-Level Risks | Risk Type | Description | Alert Trigger | | --------------------- | ------------------------------- | ------------------- | | **Large Withdrawal** | Significant liquidity reduction | Single > 5% of pool | | **TVL Plunge** | Rapid protocol TVL decline | > 20% decline in 1h | | **Flash Loan Attack** | Flash loan pattern detected | Auto-detection | | **Governance Attack** | Abnormal proposals or votes | Auto-detection | | **Oracle Anomaly** | Abnormal price data | Deviation > 5% | #### Position-Level Risks | Risk Type | Description | Alert Trigger | | -------------------- | --------------------------------- | -------------------- | | **Liquidation Risk** | Lending position near liquidation | Health factor \< 1.2 | | **Impermanent Loss** | LP impermanent loss expanding | Loss > 5% | | **Yield Decline** | Significant APY drop | Decline > 50% | #### Alert Configuration Example ```json theme={null} { "alert_type": "liquidity_remove", "protocol": "kyberswap", "pool": "0x...", "threshold": { "type": "percentage", "value": 10 }, "notification": { "webhook": "https://your-server.com/webhook", "email": "alert@example.com" } } ``` *** ## Monitoring Scenarios ### Scenario 1: New Pool Discovery **Goal**: Discover newly created trading pools as early as possible ```mermaid theme={null} flowchart TD A[Subscribe
pool_created] --> B[Filter
Liquidity > $10k] B --> C[Risk Check
Token Safety] C --> D{Score > 60?} D -->|Yes| E[Send Alert] D -->|No| F[Ignore] ``` ```typescript theme={null} ws.subscribe('pool_created', { chain: 'sol', min_liquidity_usd: 10000 }, async (pool) => { // Check token safety const risk = await checkTokenRisk(pool.token_address); if (risk.score > 60) { notify(`New pool found: ${pool.pair_name}, Liquidity: $${pool.liquidity_usd}`); } }); ``` ### Scenario 2: Rug Pull Warning **Goal**: Monitor rug pull risk for held pools Add target pool to monitoring list Set withdrawal threshold (e.g., single > 10%) Receive real-time alerts Adjust position promptly ```typescript theme={null} ws.subscribe('liquidity_remove', { pool: '0x...', threshold_percentage: 10 }, (event) => { alert(`⚠️ Rug pull warning: ${event.percentage}% liquidity removed`); }); ``` ### Scenario 3: Arbitrage Opportunity Discovery **Goal**: Discover cross-DEX price differences Subscribe to price feeds from multiple DEXs Calculate spread percentage Consider Gas and slippage costs Alert when net profit > threshold ```typescript theme={null} // Listen to prices from multiple DEXs const prices = {}; ws.subscribe('token_price', { token: 'SOL', dex: ['jupiter', 'raydium', 'pumpfun'] }, (data) => { prices[data.dex] = data.price; checkArbitrage(prices); }); function checkArbitrage(prices) { const maxPrice = Math.max(...Object.values(prices)); const minPrice = Math.min(...Object.values(prices)); const spread = (maxPrice - minPrice) / minPrice; if (spread > 0.005) { // 0.5% spread notify(`Arbitrage opportunity: ${spread * 100}% spread`); } } ``` ### Scenario 4: Liquidation Monitoring **Goal**: Monitor lending position health Get lending position for target address Calculate real-time health factor Warn when health factor \< 1.5 Urgent alert when health factor \< 1.2 ```typescript theme={null} async function monitorLiquidationRisk(address: string) { // Wire to lending APIs your deployment exposes (not DEX-specific) const position = await getLendingPosition(address); if (position.health_factor < 1.2) { urgentAlert(`🚨 Liquidation risk! Health factor: ${position.health_factor}`); } else if (position.health_factor < 1.5) { warnAlert(`⚠️ Low health factor: ${position.health_factor}`); } } ``` *** ## Data Latency | Data Type | Latency | Description | | ---------------- | ------- | ------------------------------- | | Real-time Trades | \< 3s | Pushed after block confirmation | | TVL Data | \< 1min | Minute-level updates | | APY Data | \< 5min | Calculated from recent trades | | Holder Data | \< 1h | Hourly snapshots | *** ## API Endpoints | Function | Endpoint | | ------------------ | --------------------------------------------- | | Get Protocol TVL | `GET /v1/defi/{protocol}/tvl` | | Get Pool Info | `GET /v1/defi/{protocol}/pools/{pool_id}` | | Get User Positions | `GET /v1/defi/{protocol}/positions/{address}` | | Get Yield Data | `GET /v1/defi/{protocol}/yields` | *** ## Related Documentation Build an arbitrage scanning tool Build a price alert system # Pump.fun Source: https://docs.chainstream.io/en/docs/recipes/pump-fun Complete guide to analyzing Pump.fun tokens on Solana — discovery, pricing, trades, holders, and token creation Pump.fun is the leading memecoin launchpad on Solana. ChainStream provides full data coverage for Pump.fun tokens through REST API, GraphQL, WebSocket, and MCP Tools. **Supported operations**: Token discovery, price tracking, trade analysis, holder analytics, token creation (via `pumpfun_create`), and graduation/migration tracking. *** ## How do I discover new Pump.fun tokens? Use the ranking endpoints to find newly created tokens on the Pump.fun launchpad. ```bash theme={null} curl "https://api.chainstream.io/v2/ranking/sol/newTokens" \ -H "X-API-KEY: your_api_key" ``` See [Ranking - New Tokens](/en/api-reference/endpoint/data/ranking/v2/ranking-chain-newtokens-get) for full parameter reference. Query `TokenSupplyUpdates` on Solana and filter by Pump.fun tokens: ```graphql theme={null} query { TokenSupplyUpdates( network: sol limit: {count: 20} orderBy: Block_Time_DESC ) { Block { Time } TokenSupplyUpdate { Currency { MintAddress Decimals } PostBalance MarketCapInUSD PriceInUSD TotalSupply } } } ``` [Open in GraphQL IDE](https://ide.chainstream.io) to run this query interactively. ``` ranking_get_new_tokens({ chain: "solana" }) ``` See [MCP Tools Catalog](/en/docs/ai-agents/mcp-server/tools) for full tool reference. *** ## How do I get the price of a Pump.fun token? ```bash theme={null} curl "https://api.chainstream.io/v2/token/sol/TOKEN_ADDRESS/price" \ -H "X-API-KEY: your_api_key" ``` See [Token - Price](/en/api-reference/endpoint/data/token/v2/token-chain-tokenaddress-price-get) for full reference. ```graphql theme={null} query { DEXTrades( network: sol limit: {count: 1} tokenAddress: {is: "TOKEN_ADDRESS"} where: {IsSuspect: {eq: false}} orderBy: Block_Time_DESC ) { Trade { Buy { PriceInUSD PriceInNative } } Block { Time } } } ``` ``` token_get_price({ chain: "solana", tokenAddress: "TOKEN_ADDRESS" }) ``` Replace `TOKEN_ADDRESS` with the actual Pump.fun token mint address. *** ## How do I get trades for a Pump.fun token? ```bash theme={null} curl "https://api.chainstream.io/v2/trade/sol?tokenAddress=TOKEN_ADDRESS&limit=20" \ -H "X-API-KEY: your_api_key" ``` See [Trade - List](/en/api-reference/endpoint/data/trade/v2/trade-chain-get) for full reference. ```graphql theme={null} query { DEXTrades( network: sol limit: {count: 20} tokenAddress: {is: "TOKEN_ADDRESS"} orderBy: Block_Time_DESC ) { Block { Time Slot } Transaction { Hash } Trade { Buy { Currency { MintAddress } Amount PriceInUSD Account { Owner } } Sell { Currency { MintAddress } Amount Account { Owner } } Dex { ProtocolName } } Pool { Address } } } ``` ``` trade_get({ chain: "solana", tokenAddress: "TOKEN_ADDRESS", limit: 20 }) ``` *** ## How do I get top holders of a Pump.fun token? ```bash theme={null} curl "https://api.chainstream.io/v2/token/sol/TOKEN_ADDRESS/topHolders" \ -H "X-API-KEY: your_api_key" ``` See [Token - Top Holders](/en/api-reference/endpoint/data/token/v2/token-chain-tokenaddress-topholders-get) for full reference. ```graphql theme={null} query { TokenHolders( network: sol limit: {count: 100} tokenAddress: {is: "TOKEN_ADDRESS"} ) { Token { Address } Holder { Address } LatestBalance LatestBalanceUSD FirstSeen LastSeen } } ``` ``` token_get_top_holders({ chain: "solana", tokenAddress: "TOKEN_ADDRESS" }) ``` *** ## How do I get OHLCV (K-line) data for a Pump.fun token? ```bash theme={null} curl "https://api.chainstream.io/v2/token/sol/TOKEN_ADDRESS/candles?resolution=1m&limit=60" \ -H "X-API-KEY: your_api_key" ``` See [Token - Candles](/en/api-reference/endpoint/data/token/v2/token-chain-tokenaddress-candles-get) for full reference. ```graphql theme={null} query { OHLC( network: sol limit: {count: 60} tokenAddress: {is: "TOKEN_ADDRESS"} ) { TimeMinute Token { Address } Price { OpenState HighState LowState CloseState } VolumeUSDState TradeCountState } } ``` ``` token_get_candles({ chain: "solana", tokenAddress: "TOKEN_ADDRESS", resolution: "1m" }) ``` *** ## How do I track Pump.fun tokens about to graduate? Tokens in the "final stretch" are close to meeting the bonding curve graduation threshold and migrating to Raydium. ```bash theme={null} curl "https://api.chainstream.io/v2/ranking/sol/finalStretch" \ -H "X-API-KEY: your_api_key" ``` See [Ranking - Final Stretch](/en/api-reference/endpoint/data/ranking/v2/ranking-chain-finalstretch-get) for full reference. ``` ranking_get_final_stretch({ chain: "solana" }) ``` *** ## How do I find tokens that graduated from Pump.fun? Graduated tokens have completed the bonding curve and migrated to a Raydium liquidity pool. ```bash theme={null} curl "https://api.chainstream.io/v2/ranking/sol/migrated" \ -H "X-API-KEY: your_api_key" ``` See [Ranking - Migrated](/en/api-reference/endpoint/data/ranking/v2/ranking-chain-migrated-get) for full reference. ``` ranking_get_migrated({ chain: "solana" }) ``` *** ## How do I get the top traders for a Pump.fun token? ```bash theme={null} curl "https://api.chainstream.io/v2/trade/sol/top-traders?tokenAddress=TOKEN_ADDRESS" \ -H "X-API-KEY: your_api_key" ``` See [Trade - Top Traders](/en/api-reference/endpoint/data/trade/v2/trade-chain-top-traders-get) for full reference. ```graphql theme={null} query { DEXTrades( network: sol limit: {count: 100} tokenAddress: {is: "TOKEN_ADDRESS"} where: {IsSuspect: {eq: false}} ) { Trade { Buy { Account { Owner } Amount PriceInUSD } } count sum(of: Trade_Buy_Amount) } } ``` ``` trade_get_top_traders({ chain: "solana", tokenAddress: "TOKEN_ADDRESS" }) ``` *** ## How do I check a Pump.fun token's security? ```bash theme={null} curl "https://api.chainstream.io/v2/token/sol/TOKEN_ADDRESS/security" \ -H "X-API-KEY: your_api_key" ``` See [Token - Security](/en/api-reference/endpoint/data/token/v2/token-chain-tokenaddress-security-get) for full reference. ``` token_get_security({ chain: "solana", tokenAddress: "TOKEN_ADDRESS" }) ``` *** ## How do I create a token on Pump.fun? ChainStream supports creating tokens on Pump.fun directly via API. ```bash theme={null} curl -X POST "https://api.chainstream.io/v2/dex/sol/create" \ -H "X-API-KEY: your_api_key" \ -H "Content-Type: application/json" \ -d '{ "launchpad": "pumpfun", "name": "My Token", "symbol": "MYTKN", "description": "A test token", "privateKey": "YOUR_PRIVATE_KEY" }' ``` See [DEX - Create](/en/api-reference/endpoint/defi/dex/v2/dex-chain-create-post) for full reference. ``` pumpfun_create({ name: "My Token", symbol: "MYTKN", description: "A test token" }) ``` Token creation requires a funded Solana wallet. The private key is used to sign the creation transaction. *** ## How do I get the developer's other tokens? Find all tokens created by a specific developer address on Solana. ```bash theme={null} curl "https://api.chainstream.io/v2/token/sol/dev/DEV_ADDRESS/tokens" \ -H "X-API-KEY: your_api_key" ``` See [Token - Dev Tokens](/en/api-reference/endpoint/data/token/v2/token-chain-dev-devaddress-tokens-get) for full reference. ``` token_dev_get_tokens({ chain: "solana", devAddress: "DEV_ADDRESS" }) ``` *** ## FAQ When a Pump.fun token's bonding curve reaches 100%, it "graduates" — the liquidity is migrated to a Raydium pool and the token begins trading on the open market. Use the `ranking/sol/finalStretch` endpoint to track tokens approaching graduation, and `ranking/sol/migrated` for tokens that have already graduated. The GraphQL `DEXTrades` Cube has a default filter `IsSuspect = false` that automatically excludes suspected bot and MEV trades. For REST API, check the trade response for the `isSuspect` field. Yes. Use WebSocket subscriptions for real-time price updates and trade streams. See [Real-time Streaming](/en/docs/access-methods/websocket) for setup instructions. Pump.fun is a Solana-only launchpad. Use `chain: sol` (REST) or `network: sol` (GraphQL) for all Pump.fun queries. *** ## Related Documentation More GraphQL query examples for DEX trade analysis. Comprehensive token evaluation methodology. Full list of 50+ MCP tools for AI agent integration. Raydium DEX trading and liquidity analysis. # Raydium Source: https://docs.chainstream.io/en/docs/recipes/raydium Complete guide to analyzing Raydium DEX on Solana — trades, liquidity pools, token launches, and price data Raydium is the largest AMM and liquidity provider on Solana. ChainStream provides full data coverage for Raydium trades and pools through REST API, GraphQL, WebSocket, and MCP Tools. **Supported operations**: Trade analysis, liquidity pool monitoring, token price tracking, OHLCV data, holder analytics, and token creation via Raydium launchpad. *** ## How do I get recent trades on Raydium? ```bash theme={null} curl "https://api.chainstream.io/v2/trade/sol?limit=20" \ -H "X-API-KEY: your_api_key" ``` See [Trade - List](/en/api-reference/endpoint/data/trade/v2/trade-chain-get) for full parameter reference. Query `DEXTrades` and filter by Raydium's protocol name: ```graphql theme={null} query { DEXTrades( network: sol limit: {count: 20} dexProgram: {is: "RAYDIUM_PROGRAM_ADDRESS"} orderBy: Block_Time_DESC ) { Block { Time Slot } Transaction { Hash } Trade { Buy { Currency { MintAddress } Amount PriceInUSD Account { Owner } } Sell { Currency { MintAddress } Amount } Dex { ProgramAddress ProtocolName } } Pool { Address } } } ``` ``` trade_get({ chain: "solana", limit: 20 }) ``` *** ## How do I get the price of a token on Raydium? ```bash theme={null} curl "https://api.chainstream.io/v2/token/sol/TOKEN_ADDRESS/price" \ -H "X-API-KEY: your_api_key" ``` See [Token - Price](/en/api-reference/endpoint/data/token/v2/token-chain-tokenaddress-price-get) for full reference. ```graphql theme={null} query { DEXTrades( network: sol limit: {count: 1} tokenAddress: {is: "TOKEN_ADDRESS"} where: {IsSuspect: {eq: false}} orderBy: Block_Time_DESC ) { Trade { Buy { PriceInUSD PriceInNative } } Block { Time } } } ``` ``` token_get_price({ chain: "solana", tokenAddress: "TOKEN_ADDRESS" }) ``` *** ## How do I get liquidity pools for a token on Raydium? ```bash theme={null} curl "https://api.chainstream.io/v2/token/sol/TOKEN_ADDRESS/pools" \ -H "X-API-KEY: your_api_key" ``` See [Token - Pools](/en/api-reference/endpoint/data/token/v2/token-chain-tokenaddress-pools-get) for full reference. ```graphql theme={null} query { DEXPools( network: sol limit: {count: 10} tokenAddress: {is: "TOKEN_ADDRESS"} orderBy: Block_Time_DESC ) { Pool { Address Dex { ProgramAddress } Base { Address PostAmount } Quote { Address PostAmount } LiquidityInUSD } Block { Time } } } ``` ``` token_get_pools({ chain: "solana", tokenAddress: "TOKEN_ADDRESS" }) ``` *** ## How do I get pool details by address? ```bash theme={null} curl "https://api.chainstream.io/v2/dexpools/sol/POOL_ADDRESS" \ -H "X-API-KEY: your_api_key" ``` See [DexPool - Get](/en/api-reference/endpoint/data/dexpool/v2/dexpools-chain-pooladdress-get) for full reference. ```graphql theme={null} query { DEXPools( network: sol limit: {count: 1} poolAddress: {is: "POOL_ADDRESS"} orderBy: Block_Time_DESC ) { Pool { Address Base { Address PostAmount } Quote { Address PostAmount } LiquidityInUSD } Block { Time } } } ``` ``` dexpool_get({ chain: "solana", poolAddress: "POOL_ADDRESS" }) ``` *** ## How do I get OHLCV (K-line) data for a Raydium token? ```bash theme={null} curl "https://api.chainstream.io/v2/token/sol/TOKEN_ADDRESS/candles?resolution=1m&limit=60" \ -H "X-API-KEY: your_api_key" ``` ```graphql theme={null} query { OHLC( network: sol limit: {count: 60} tokenAddress: {is: "TOKEN_ADDRESS"} ) { TimeMinute Token { Address } Price { OpenState HighState LowState CloseState } VolumeUSDState TradeCountState } } ``` ``` token_get_candles({ chain: "solana", tokenAddress: "TOKEN_ADDRESS", resolution: "1m" }) ``` *** ## How do I get token holders on Raydium? ```bash theme={null} curl "https://api.chainstream.io/v2/token/sol/TOKEN_ADDRESS/topHolders" \ -H "X-API-KEY: your_api_key" ``` ```graphql theme={null} query { TokenHolders( network: sol limit: {count: 100} tokenAddress: {is: "TOKEN_ADDRESS"} ) { Token { Address } Holder { Address } LatestBalance LatestBalanceUSD FirstSeen LastSeen } } ``` ``` token_get_top_holders({ chain: "solana", tokenAddress: "TOKEN_ADDRESS" }) ``` *** ## How do I get top traders for a Raydium token? ```bash theme={null} curl "https://api.chainstream.io/v2/trade/sol/top-traders?tokenAddress=TOKEN_ADDRESS" \ -H "X-API-KEY: your_api_key" ``` ```graphql theme={null} query { DEXTrades( network: sol limit: {count: 100} tokenAddress: {is: "TOKEN_ADDRESS"} where: {IsSuspect: {eq: false}} ) { Trade { Buy { Account { Owner } Amount PriceInUSD } } count sum(of: Trade_Buy_Amount) } } ``` ``` trade_get_top_traders({ chain: "solana", tokenAddress: "TOKEN_ADDRESS" }) ``` *** ## How do I get pool liquidity snapshots? ```bash theme={null} curl "https://api.chainstream.io/v2/dexpools/sol/POOL_ADDRESS/snapshots" \ -H "X-API-KEY: your_api_key" ``` See [DexPool - Snapshots](/en/api-reference/endpoint/data/dexpool/v2/dexpools-chain-pooladdress-snapshots-get) for full reference. ```graphql theme={null} query { PoolLiquiditySnapshots( network: sol limit: {count: 20} tokenAddress: {is: "TOKEN_ADDRESS"} ) { Pool { Address ProgramAddress } TokenA { Address } TokenB { Address } LiquidityUSDState EventCountState LastSeenState } } ``` ``` dexpool_get_snapshots({ chain: "solana", poolAddress: "POOL_ADDRESS" }) ``` *** ## How do I create a token on Raydium? ChainStream supports creating tokens on Raydium launchpad directly via API. ```bash theme={null} curl -X POST "https://api.chainstream.io/v2/dex/sol/create" \ -H "X-API-KEY: your_api_key" \ -H "Content-Type: application/json" \ -d '{ "launchpad": "raydium", "name": "My Token", "symbol": "MYTKN", "description": "A test token", "privateKey": "YOUR_PRIVATE_KEY" }' ``` See [DEX - Create](/en/api-reference/endpoint/defi/dex/v2/dex-chain-create-post) for full reference. Token creation is only available on Solana. The private key is used to sign the creation transaction. *** ## FAQ Pump.fun tokens trade on a bonding curve until graduation; once they graduate, liquidity is migrated to a Raydium AMM pool. Use `ranking/sol/migrated` to find recently graduated tokens. In GraphQL, use the `dexProgram` selector to filter by Raydium's program address. In REST, trades are returned across all DEXes — check the `dex` field in the response to identify Raydium trades. Yes. Use WebSocket subscriptions for real-time pool and trade updates. See [Real-time Streaming](/en/docs/access-methods/websocket) for setup instructions. *** ## Related Documentation Complete Pump.fun token analysis including graduation tracking. GraphQL query examples for pool and liquidity data. GraphQL query examples for DEX trade analysis. Full list of 50+ MCP tools for AI agent integration. # Token Analysis Framework Source: https://docs.chainstream.io/en/docs/recipes/token-analysis-framework Systematic Token analysis methodology, from fundamentals to on-chain metrics This document introduces a comprehensive Token analysis framework using ChainStream, covering fundamental data, on-chain metrics, holder analysis, and risk assessment. *** ## Framework Overview Name/Symbol, Decimals, Contract Address, Creation Time Price, Market Cap, Liquidity, Volume Holder Count, Top 10/100 Ratio, Creator Holdings Buy/Sell Count, Volume, Price Change *** ## 1. Basic Information ### API Endpoint ```bash theme={null} GET /v2/token/{chain}/{tokenAddress} ``` ### Core Fields | Field | Type | Description | | ---------------- | ------- | ------------------------------------------ | | `chain` | string | Blockchain network identifier, e.g., `sol` | | `name` | string | Token name | | `symbol` | string | Token symbol | | `decimals` | integer | Token decimal places | | `address` | string | Token mint address | | `imageUrl` | string | Token image URL | | `tokenCreatedAt` | integer | Token creation timestamp (milliseconds) | | `description` | string | Token description | | `tokenCreators` | array | Token creator address list | ### Response Example ```json theme={null} { "chain": "sol", "name": "USD Coin", "symbol": "USDC", "decimals": 9, "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", "imageUrl": "https://raw.githubusercontent.com/.../logo.png", "tokenCreatedAt": 1710417600000, "description": "USDC is a stablecoin pegged to the US dollar", "tokenCreators": [ { "address": "...", "share": 100 } ] } ``` *** ## 2. Market Data Market data is included in the `marketData` field of the Token details endpoint. ### Price & Market Cap | Field | Type | Description | | ---------------- | ------ | ---------------------------- | | `priceInUsd` | string | Token price (USD) | | `priceInSol` | string | Token price (SOL) | | `marketCapInUsd` | string | Circulating market cap (USD) | | `marketCapInSol` | string | Circulating market cap (SOL) | | `totalSupply` | string | Total supply | ### Liquidity Metrics | Field | Type | Description | Health Standard | | ----------------- | ------ | -------------------------------- | ----------------------------- | | `maxPoolTvlInUsd` | string | Max pool TVL (USD) | Higher depth = lower slippage | | `totalTvlInUsd` | string | Total TVL across all pools (USD) | > 5% of market cap | | `maxPoolTvlInSol` | string | Max pool TVL (SOL) | - | | `totalTvlInSol` | string | Total TVL across all pools (SOL) | - | ### Holder Overview | Field | Type | Description | Health Standard | | --------------------- | ------ | ---------------------- | ----------------------- | | `holders` | string | Total token holders | More = more distributed | | `top10HoldingsRatio` | string | Top 10 holders ratio | \< 0.5 (50%) | | `top10TotalHoldings` | string | Top 10 total holdings | - | | `top100HoldingsRatio` | string | Top 100 holders ratio | \< 0.7 (70%) | | `top100TotalHoldings` | string | Top 100 total holdings | - | ### Response Example ```json theme={null} { "marketData": { "priceInUsd": "0.00123456", "priceInSol": "0.0000089", "marketCapInUsd": "1234567.89", "totalSupply": "1000000000", "holders": "5432", "top10HoldingsRatio": "0.35", "top100HoldingsRatio": "0.58", "maxPoolTvlInUsd": "50000.00", "totalTvlInUsd": "85000.00" } } ``` *** ## 3. Trading Statistics Trading statistics are included in the `stats` field of the Token details endpoint, or can be fetched via a dedicated endpoint. ### API Endpoint ```bash theme={null} GET /v2/token/{chain}/{tokenAddress}/stats ``` ### Statistics Fields (by Time Period) Supported time periods: `1m`, `5m`, `15m`, `30m`, `1h`, `4h`, `24h` | Field Pattern | Description | Example Fields | | ------------------------------- | ------------------------ | ------------------------------- | | `price{period}` | Price within period | `price1m`, `price5m`, `price1h` | | `buys{period}` | Buy count within period | `buys1m`, `buys5m`, `buys1h` | | `sells{period}` | Sell count within period | `sells1m`, `sells5m`, `sells1h` | | `buyVolumesInUsd{period}` | Buy volume (USD) | `buyVolumesInUsd1m` | | `sellVolumesInUsd{period}` | Sell volume (USD) | `sellVolumesInUsd1m` | | `volumesInUsd{period}` | Total volume (USD) | `volumesInUsd1m` | | `priceChangeRatioInUsd{period}` | Price change ratio | `priceChangeRatioInUsd1h` | ### Response Example ```json theme={null} { "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", "price1m": "1.234", "buys1m": "150", "sells1m": "120", "buyVolumesInUsd1m": "50000.45", "sellVolumesInUsd1m": "45000.32", "volumesInUsd1m": "95000.77", "buys1h": "2500", "sells1h": "2100", "volumesInUsd1h": "1500000.00", "priceChangeRatioInUsd1h": "0.025" } ``` *** ## 4. Holder Analysis ### API Endpoint ```bash theme={null} GET /v2/token/{chain}/{tokenAddress}/holders ``` ### Query Parameters | Parameter | Type | Required | Description | | ----------- | ------ | -------- | --------------------------------------- | | `cursor` | string | No | Pagination cursor | | `limit` | number | No | Results per page (1-100, default 20) | | `direction` | string | No | Pagination direction (`next` or `prev`) | ### Holder Fields | Field | Type | Description | | --------------- | ------ | ------------------- | | `walletAddress` | string | Wallet address | | `amount` | string | Holding amount | | `amountInUsd` | string | Holding value (USD) | | `percentage` | string | Holding percentage | ### Response Example ```json theme={null} { "hasNext": true, "hasPrev": false, "startCursor": "abc123", "endCursor": "xyz789", "data": [ { "walletAddress": "HN7cABqLq46Es1jh92dQQisAq662SmxELLLsHHe4YWrH", "amount": "1000000000000000000", "amountInUsd": "12345.67", "percentage": "10.5" } ] } ``` ### Holder Distribution Assessment **Characteristics**: * Top 10 ratio \< 50% * Top 100 ratio \< 70% * High holder count * Even distribution, decentralized **Risk Level**: 🟢 Low Risk **Characteristics**: * Top 10 ratio > 80% * Few addresses control most supply * Low holder count * Highly concentrated, manipulation risk **Risk Level**: 🔴 High Risk ### Holder Type Identification | Type | Identification | Significance | | ---------------- | ------------------------------------------------ | --------------------- | | **Team/Project** | Contract deployer, addresses in `tokenCreators` | Unlock risk | | **Whales** | Holdings > 1% | Market influence | | **Smart Money** | High win-rate traders (requires wallet analysis) | Information advantage | | **CEX** | Exchange hot wallets | Liquidity source | *** ## 5. Risk Assessment ### Risk Assessment Dimensions | Dimension | Weight | Metrics | | ---------------------- | ------ | ------------------------------------------- | | **Concentration Risk** | 30% | `top10HoldingsRatio`, `top100HoldingsRatio` | | **Liquidity Risk** | 25% | `totalTvlInUsd`, TVL/Market Cap ratio | | **New Token Risk** | 20% | `tokenCreatedAt` (creation time) | | **Trading Activity** | 15% | `holders`, volume, buy/sell count | | **Creator Holdings** | 10% | Creator address holding ratio | ### Risk Indicators | Indicator | Level | Trigger Conditions | | -------------- | -------- | ------------------------------------------------------------------- | | 🔴 High Risk | Critical | `top10HoldingsRatio` > 0.8, TVL \< 1% of market cap, created \< 24h | | 🟡 Medium Risk | Warning | `top10HoldingsRatio` > 0.5, created \< 7 days | | 🟢 Low Risk | Safe | All metrics healthy | *** ## Analysis Workflow Call `GET /v2/token/{chain}/{tokenAddress}` to get complete token info * Verify contract address * Check creation time `tokenCreatedAt` Review `marketData` field * Current price `priceInUsd` * Market cap `marketCapInUsd` * Liquidity `totalTvlInUsd` Review holder data in `marketData` * Holder count `holders` * Top 10 ratio `top10HoldingsRatio` * Top 100 ratio `top100HoldingsRatio` Review `stats` field * Volume `volumesInUsd1h`, `volumesInUsd24h` * Buy/sell ratio `buys1h` vs `sells1h` Calculate risk level based on above data * High concentration + low liquidity = 🔴 High Risk * Healthy distribution + sufficient liquidity = 🟢 Low Risk *** ## Practical Example ### Example: Analyze Newly Listed Token ```typescript theme={null} import { ChainStreamClient } from '@chainstream-io/sdk'; const client = new ChainStreamClient('YOUR_ACCESS_TOKEN'); async function analyzeToken(chain: string, tokenAddress: string) { // 1. Get complete token info const token = await client.token.getToken(chain, tokenAddress); // 2. Check creation time const ageInDays = (Date.now() - token.tokenCreatedAt) / (1000 * 60 * 60 * 24); if (ageInDays < 7) { console.warn('⚠️ New token risk: Created less than 7 days ago'); } // 3. Analyze holder distribution const top10Ratio = parseFloat(token.marketData.top10HoldingsRatio); if (top10Ratio > 0.5) { console.warn('⚠️ Concentration risk: Top 10 holds > 50%'); } // 4. Check liquidity const tvl = parseFloat(token.marketData.totalTvlInUsd); const marketCap = parseFloat(token.marketData.marketCapInUsd); if (tvl < marketCap * 0.05) { console.warn('⚠️ Liquidity risk: TVL < 5% of market cap'); } // 5. Comprehensive assessment const riskLevel = calculateRiskLevel(token); console.log(`Risk Level: ${riskLevel}`); return { token, ageInDays, top10Ratio, tvlRatio: tvl / marketCap, riskLevel }; } function calculateRiskLevel(token: any): string { const top10Ratio = parseFloat(token.marketData.top10HoldingsRatio); const tvl = parseFloat(token.marketData.totalTvlInUsd); const marketCap = parseFloat(token.marketData.marketCapInUsd); if (top10Ratio > 0.8 || tvl < marketCap * 0.01) { return '🔴 High Risk'; } else if (top10Ratio > 0.5) { return '🟡 Medium Risk'; } return '🟢 Low Risk'; } ``` *** ## API Endpoint Summary | Analysis Need | API Endpoint | | --------------------------------------- | ------------------------------------------------- | | Token Details (with market data, stats) | `GET /v2/token/{chain}/{tokenAddress}` | | Token Metadata | `GET /v2/token/{chain}/{tokenAddress}/metadata` | | Token Stats | `GET /v2/token/{chain}/{tokenAddress}/stats` | | Holder List | `GET /v2/token/{chain}/{tokenAddress}/holders` | | Top Holders | `GET /v2/token/{chain}/{tokenAddress}/topholders` | | Token Pools | `GET /v2/token/{chain}/{tokenAddress}/pools` | | Token Market Data | `GET /v2/token/{chain}/{tokenAddress}/marketdata` | *** ## Related Documentation Learn about Smart Money analysis View complete MCP tools list # Webhook Fundamentals Source: https://docs.chainstream.io/en/docs/recipes/webhook-fundamentals Principles, configuration, and best practices for real-time data delivery **Beta** — This feature is currently in beta. API may be subject to changes. This document introduces the working principles, configuration methods, and best practices for ChainStream Webhooks, helping you implement real-time on-chain event delivery. Webhook functionality is available to all users. *** ## How It Works ### Data Flow ```mermaid theme={null} flowchart TD A[Blockchain Network] --> B[ChainStream Indexing Layer] B --> C[Event Matching Engine] D[Your Subscription Rules] --> C C --> E{Match Success?} E -->|Yes| F[Build Webhook Request] E -->|No| G[Ignore] F --> H[POST to Your Server] H --> I[Your Server Processes Data] ``` ### Core Features | Feature | Description | | -------------------------- | ---------------------------------------------- | | **Real-time Delivery** | Millisecond-level delivery after event trigger | | **Reliable Delivery** | Auto-retry on failure | | **Signature Verification** | HMAC signature anti-forgery | | **Filter Rules** | Support event type filtering | *** ## Supported Event Types Webhook currently supports the following event types (channels): | Channel | Description | Typical Use | | -------------------- | --------------------------------- | ----------------------------------------------------------- | | `sol.token.created` | Solana new token creation | New token discovery, early opportunities | | `sol.token.migrated` | Solana token graduation/migration | Track tokens graduating from Pump.fun and similar platforms | More event types are in development. Stay tuned! *** ## Create Webhook Endpoint ### API Endpoint ```bash theme={null} POST /v1/webhook/endpoint Content-Type: application/json Authorization: Bearer YOUR_ACCESS_TOKEN ``` ### Request Parameters | Parameter | Type | Required | Description | | ------------- | ------- | -------- | ------------------------------------ | | `url` | string | Yes | Webhook callback URL (must be HTTPS) | | `channels` | array | Yes | List of event types to subscribe to | | `description` | string | No | Endpoint description | | `disabled` | boolean | No | Whether disabled, default false | | `filterTypes` | array | No | Filter types | | `metadata` | object | No | Custom metadata | | `rateLimit` | integer | No | Rate limit | ### Request Example ```json theme={null} { "url": "https://your-server.com/webhook", "channels": ["sol.token.created", "sol.token.migrated"], "description": "Monitor new tokens and graduated tokens" } ``` ### Response Example ```json theme={null} { "id": "ep_abc123", "url": "https://your-server.com/webhook", "channels": ["sol.token.created", "sol.token.migrated"], "description": "Monitor new tokens and graduated tokens", "disabled": false } ``` *** ## Webhook Notification Format Webhook notification data structure is consistent with WebSocket push. ### New Token Created (sol.token.created) ```json theme={null} { "channel": "sol.token.created", "timestamp": 1706947200000, "data": { "a": "6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN", "n": "Example Token", "s": "EXT", "dec": 9, "cts": 1706947200000, "lf": { "pa": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P", "pf": "pump_fun", "pn": "Pump.fun" } } } ``` **Field Descriptions**: | Field | Description | | ------- | -------------------------------- | | `a` | Token address | | `n` | Token name | | `s` | Token symbol | | `dec` | Decimals | | `cts` | Created timestamp (milliseconds) | | `lf.pa` | Launch platform program address | | `lf.pf` | Protocol family | | `lf.pn` | Protocol name | ### Token Graduated (sol.token.migrated) ```json theme={null} { "channel": "sol.token.migrated", "timestamp": 1706947200000, "data": { "a": "6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN", "n": "Example Token", "s": "EXT", "cts": 1706947200000, "lf": { "pa": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P", "pf": "pump_fun", "pn": "Pump.fun" }, "mt": { "pa": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", "pf": "raydium", "pn": "Raydium" } } } ``` **Additional Fields**: | Field | Description | | ------- | ----------------------------------------- | | `mt.pa` | Migration target platform program address | | `mt.pf` | Migration target protocol family | | `mt.pn` | Migration target protocol name | *** ## Webhook URL Requirements | Requirement | Description | | --------------------- | ------------------------------------------- | | ✅ HTTPS | Must use HTTPS protocol | | ✅ Publicly Accessible | URL must be accessible from public internet | | ✅ 2xx Response | Must return 2xx status code for success | | ✅ Response Time | Should respond within 5 seconds | | ✅ Idempotent Handling | Must handle duplicate requests | *** ## Security Verification ### Get Webhook Secret After creating an endpoint, get the secret via this API: ```bash theme={null} GET /v1/webhook/endpoint/{id}/secret ``` **Response**: ```json theme={null} { "secret": "whsec_abcdXXX" } ``` ### Signature Verification Each Webhook request includes signature headers for verifying request origin: ``` X-Webhook-Signature: X-Webhook-Timestamp: ``` ### Verification Flow ```mermaid theme={null} flowchart TD A[Get Signature Headers] --> B[Build Signature String] B --> C[Calculate HMAC-SHA256] C --> D{Signature Match?} D -->|Yes| E[Process Request] D -->|No| F[Reject Request] ``` ### Code Examples ```javascript theme={null} const crypto = require('crypto'); function verifyWebhook(req, secret) { const signature = req.headers['x-webhook-signature']; const timestamp = req.headers['x-webhook-timestamp']; const body = JSON.stringify(req.body); // Check timestamp (5-minute window) const now = Date.now(); if (Math.abs(now - parseInt(timestamp)) > 300000) { return false; } // Calculate signature const message = `${timestamp}.${body}`; const expectedSignature = crypto .createHmac('sha256', secret) .update(message) .digest('hex'); // Safe comparison return crypto.timingSafeEqual( Buffer.from(signature), Buffer.from(expectedSignature) ); } ``` ```python theme={null} import hmac import hashlib import time def verify_webhook(request, secret): signature = request.headers.get('X-Webhook-Signature') timestamp = request.headers.get('X-Webhook-Timestamp') body = request.get_data(as_text=True) # Check timestamp (5-minute window) now = int(time.time() * 1000) if abs(now - int(timestamp)) > 300000: return False # Calculate signature message = f"{timestamp}.{body}" expected_signature = hmac.new( secret.encode(), message.encode(), hashlib.sha256 ).hexdigest() # Safe comparison return hmac.compare_digest(signature, expected_signature) ``` ```go theme={null} import ( "crypto/hmac" "crypto/sha256" "encoding/hex" "strconv" "time" ) func verifyWebhook(signature, timestamp, body, secret string) bool { // Check timestamp ts, _ := strconv.ParseInt(timestamp, 10, 64) now := time.Now().UnixMilli() if abs(now-ts) > 300000 { return false } // Calculate signature message := timestamp + "." + body mac := hmac.New(sha256.New, []byte(secret)) mac.Write([]byte(message)) expected := hex.EncodeToString(mac.Sum(nil)) return hmac.Equal([]byte(signature), []byte(expected)) } ``` *** ## Manage Webhook Endpoints ### List Endpoints ```bash theme={null} GET /v1/webhook/endpoint ``` **Query Parameters**: | Parameter | Type | Description | | ---------- | ------- | ----------------------------------- | | `limit` | integer | Items per page (1-100, default 100) | | `iterator` | string | Pagination iterator | | `order` | string | Sort order (ascending/descending) | ### Get Endpoint Details ```bash theme={null} GET /v1/webhook/endpoint/{id} ``` ### Update Endpoint ```bash theme={null} PATCH /v1/webhook/endpoint ``` ```json theme={null} { "endpointId": "ep_abc123", "channels": ["sol.token.created"], "description": "Monitor new tokens only" } ``` ### Delete Endpoint ```bash theme={null} DELETE /v1/webhook/endpoint/{id} ``` ### Rotate Secret ```bash theme={null} POST /v1/webhook/endpoint/{id}/secret/rotate ``` *** ## Best Practices ### ✅ Fast Response ```python theme={null} # Recommended: Respond first, process later @app.route('/webhook', methods=['POST']) def webhook(): # Verify signature if not verify_webhook(request, SECRET): return "Invalid signature", 401 # Put in queue for async processing queue.put(request.json) # Return 200 immediately return "OK", 200 ``` ### ✅ Idempotency Handling Each event contains a unique identifier. Record processed events on your server: ```python theme={null} # Use Redis to record processed events def process_webhook(event): event_id = f"{event['channel']}:{event['data']['a']}:{event['timestamp']}" # Check if already processed if redis.exists(f"processed:{event_id}"): return {"status": "already_processed"} # Process event handle_event(event) # Mark as processed (TTL 24 hours) redis.setex(f"processed:{event_id}", 86400, "1") return {"status": "ok"} ``` ### ✅ Security Verify signature for every request Ensure transport security Recommended every 90 days Don't log sensitive data ### ✅ Reliability Handle duplicate requests Use queues for async processing Avoid long blocking Log key information for troubleshooting *** ## FAQ **Troubleshooting steps**: 1. **Confirm URL is accessible** — Test if URL is reachable from public internet 2. **Check HTTPS** — Must use a valid SSL certificate 3. **Check endpoint status** — Confirm `disabled` is not `true` 4. **Check channels** — Confirm subscribed to correct event types This may be caused by retry mechanism. Implement idempotency handling: 1. Use unique event identifier (channel + token address + timestamp) 2. Check if already processed when receiving requests 3. Use cache with TTL (like Redis) for storage 1. Use ngrok to expose local service 2. Create Webhook endpoint pointing to ngrok URL 3. Wait for real events to trigger, or use test environment 4. Check local service logs *** ## API Endpoint Summary | Function | Endpoint | | -------------------- | ---------------------------------------------- | | List Endpoints | `GET /v1/webhook/endpoint` | | Create Endpoint | `POST /v1/webhook/endpoint` | | Update Endpoint | `PATCH /v1/webhook/endpoint` | | Get Endpoint Details | `GET /v1/webhook/endpoint/{id}` | | Delete Endpoint | `DELETE /v1/webhook/endpoint/{id}` | | Get Secret | `GET /v1/webhook/endpoint/{id}/secret` | | Rotate Secret | `POST /v1/webhook/endpoint/{id}/secret/rotate` | *** ## Related Documentation Real-time data subscription Complete API documentation # Error Codes Reference Source: https://docs.chainstream.io/en/docs/reference/error-codes Complete list of ChainStream API error codes ## Error Response Format All API errors follow a unified response format: ```json theme={null} { "code": 40001, "timestamp": "2026-02-05T10:30:00.000Z", "message": "Human readable error message", "details": { // Optional additional information } } ``` ## HTTP Status Codes | Status | Description | Error Code Range | | ------ | --------------------- | ---------------- | | 400 | Bad Request | 400, 40001-40040 | | 401 | Unauthorized | 401 | | 403 | Forbidden | 403, 40301 | | 404 | Not Found | 404, 40401-40406 | | 429 | Too Many Requests | 429, 42901-42902 | | 500 | Internal Server Error | 500, 50001-50036 | | 510 | Red Packet Error | 51000-51004 | | 520 | Webhook Error | 52000-52001 | *** ## Client Errors (400) ### Parameter Validation Errors | Code | Name | Description | Solution | | ----- | ----------------------- | -------------------------------------------- | ------------------------------------------- | | 400 | `BAD_REQUEST` | Bad request | Check request format | | 40001 | `VALIDATION_ERROR` | Request parameters are abnormal or incorrect | Check parameter format and values | | 40002 | `INVALID_PARAMETER` | Invalid parameter | Check if parameter value meets requirements | | 40003 | `INVALID_TOKEN` | Invalid access token | Check token format | | 40004 | `MISSING_PARAMETER` | Missing required parameter | Add missing required parameters | | 40005 | `INVALID_ADDRESS` | Invalid wallet address format | Check address format | | 40027 | `INVALID_CURSOR` | Invalid cursor | Use valid pagination cursor | | 40031 | `INVALID_TIMESTAMP` | Invalid timestamp format | Use ISO 8601 format | | 40032 | `INVALID_RESOLUTION` | Invalid resolution parameter | Use supported K-line periods | | 40033 | `INVALID_NUMBER_FORMAT` | Invalid number format | Use correct number format | ```json theme={null} { "code": 40002, "timestamp": "2026-02-05T10:30:00.000Z", "message": "Invalid parameter", "details": { "parameter": "resolution", "value": "2h", "allowed_values": ["1s", "1m", "5m", "15m", "1h", "4h", "1d"] } } ``` ### Token Related Errors | Code | Name | Description | Solution | | ----- | -------------------------------- | ------------------------------ | ---------------------------- | | 40009 | `INVALID_TOKEN_ADDRESS` | Invalid token address | Check token contract address | | 40028 | `TOKEN_ADDRESSES_LIMIT_EXCEEDED` | Token addresses limit exceeded | Maximum 100 addresses | | 40034 | `TOKEN_ALREADY_CREATED` | Token already created | Check for duplicate creation | ### Wallet Related Errors | Code | Name | Description | Solution | | ----- | --------------------------------- | ------------------------------- | --------------------- | | 40029 | `WALLET_ADDRESSES_LIMIT_EXCEEDED` | Wallet addresses limit exceeded | Maximum 100 addresses | ### Transaction Related Errors | Code | Name | Description | Solution | | ----- | ------------------------------- | ----------------------------- | ------------------------------- | | 40010 | `TRANSACTION_FAILED` | Transaction execution failed | Check parameters and balance | | 40011 | `TRANSACTION_REJECTED` | Transaction rejected | Check signature and permissions | | 40012 | `INVALID_TRANSACTION` | Invalid transaction | Check transaction structure | | 40025 | `TRANSACTION_NOT_SIGNED` | Transaction not signed | Sign before serialization | | 40026 | `TRANSACTION_SIGNATURE_MISSING` | Transaction signature missing | Add transaction signature | | 40039 | `TRANSACTION_SIZE_EXCEEDED` | Transaction size exceeded | Reduce transaction complexity | ### DEX Trading Errors | Code | Name | Description | Solution | | ----- | ------------------------ | -------------------------- | ---------------------------------- | | 40006 | `LIQUIDITY_INSUFFICIENT` | Insufficient liquidity | Reduce trade amount | | 40007 | `PRICE_IMPACT_TOO_HIGH` | Price impact too high | Reduce amount or increase slippage | | 40008 | `SLIPPAGE_TOO_HIGH` | Slippage too high | Adjust slippage settings | | 40014 | `INVALID_AMOUNT` | Invalid amount | Use valid number | | 40015 | `AMOUNT_TOO_SMALL` | Amount too small | Increase trade amount | | 40016 | `AMOUNT_TOO_LARGE` | Amount too large | Amount exceeds safe range | | 40017 | `SAME_TOKEN_SWAP` | Same token swap | Input and output cannot be same | | 40018 | `INVALID_SLIPPAGE` | Invalid slippage value | Use valid slippage value | | 40019 | `SLIPPAGE_TOO_LOW` | Slippage too low | Slippage must be greater than zero | | 40020 | `POOL_NOT_SUPPORTED` | Pool not supported | Use supported pool | | 40021 | `UNSUPPORTED_SWAP_MODE` | Swap mode not supported | Use supported swap mode | | 40022 | `FEE_PARAMETER_ERROR` | Invalid fee parameter | Check fee configuration | | 40023 | `ANTI_MEV_REJECTED` | Anti-MEV validation failed | Check Anti-MEV settings | | 40030 | `POOL_INPUT_MISMATCH` | Pool input mismatch | Input token doesn't match pool | ```json theme={null} { "code": 40006, "timestamp": "2026-02-05T10:30:00.000Z", "message": "Insufficient liquidity", "details": { "requested_amount": "1000000000", "available_liquidity": "500000000" } } ``` ### Order Related Errors | Code | Name | Description | Solution | | ----- | -------------------------- | ------------------------ | ------------------------- | | 40035 | `INVALID_MARKET_PRICES` | Invalid market prices | Check price parameters | | 40036 | `INVALID_ORDER_PARAMETERS` | Invalid order parameters | Check order configuration | ### Other Client Errors | Code | Name | Description | Solution | | ----- | ------------------------ | ------------------------ | ------------------------------ | | 40013 | `PARAMETER_ERROR` | Parameter error | Must set total or fixed amount | | 40024 | `NOT_IMPLEMENTED` | Method not implemented | Use implemented methods | | 40037 | `UNSUPPORTED_VALUE_TYPE` | Value type not supported | Use supported value types | | 40038 | `PARSE_ERROR` | Parse failed | Check data format | | 40040 | `INVALID_MIGRATE_TYPE` | Invalid migration type | Use valid migration type | *** ## Authentication Errors (401) | Code | Name | Description | Solution | | ---- | -------------- | ----------------------------------------- | -------------------------- | | 401 | `UNAUTHORIZED` | Unauthorized. Token is missing or invalid | Check Authorization header | ```json theme={null} { "code": 401, "timestamp": "2026-02-05T10:30:00.000Z", "message": "Unauthorized. Token is missing or invalid" } ``` **Handling Example**: ```javascript theme={null} if (error.code === 401) { // Refresh token const newToken = await getAccessToken(); // Retry request with new token } ``` *** ## Permission Errors (403) | Code | Name | Description | Solution | | ----- | -------------------------- | ------------------------ | --------------------------- | | 403 | `FORBIDDEN` | Forbidden | See details below | | 40301 | `INSUFFICIENT_PERMISSIONS` | Insufficient permissions | Obtain required permissions | 403 errors can be triggered by: * **Quota exhausted**: Monthly API call quota depleted, upgrade plan or wait for next month reset * **Blacklisted**: IP or account has been blacklisted * **Not whitelisted**: Request origin not in allowed whitelist When API quota is exhausted, the gateway returns 403 directly. This differs from 429 (rate limit): * **429**: Short-term rate limiting (requests per second/minute exceeded) * **403**: Account quota limit (monthly usage exhausted) or permission issues ```json theme={null} { "code": 403, "timestamp": "2026-02-05T10:30:00.000Z", "message": "Forbidden" } ``` ```json theme={null} { "code": 40301, "timestamp": "2026-02-05T10:30:00.000Z", "message": "Insufficient permissions", "details": { "required_scope": "kyt.write", "current_scopes": ["kyt.read"] } } ``` *** ## Resource Not Found Errors (404) | Code | Name | Description | Solution | | ----- | ----------------------- | ---------------------------- | ------------------------------ | | 404 | `NOT_FOUND` | Resource not found | Check if resource exists | | 40401 | `POOL_NOT_FOUND` | Liquidity pool not found | Check pool address and chain | | 40402 | `MARKET_INFO_NOT_FOUND` | Market info not found | Check if market exists | | 40403 | `OPEN_ORDER_NOT_FOUND` | Open order account not found | Check order account | | 40404 | `ORDER_NOT_FOUND` | Order not found | Check order ID | | 40405 | `CHAIN_NOT_FOUND` | Chain not found | Use supported chain identifier | | 40406 | `DEX_NOT_FOUND` | DEX not found | Use supported DEX | ```json theme={null} { "code": 40401, "timestamp": "2026-02-05T10:30:00.000Z", "message": "Liquidity pool not found", "details": { "chain": "sol", "pool_address": "INVALID_ADDRESS" } } ``` *** ## Rate Limit Errors (429) | Code | Name | Description | Solution | | ----- | -------------------------- | ------------------------------------- | ------------------------------ | | 429 | `RATE_LIMIT` | Too many requests. Rate limit reached | Wait and retry | | 42901 | `API_USAGE_LIMIT_EXCEEDED` | API usage limit exceeded | Upgrade plan or wait for reset | | 42902 | `KYT_USAGE_LIMIT_EXCEEDED` | KYT API usage limit exceeded | Upgrade KYT plan | ```json theme={null} { "code": 429, "timestamp": "2026-02-05T10:30:00.000Z", "message": "Too Many Requests. Rate limit reached", "details": { "limit": 100, "remaining": 0, "reset_at": 1706745600 } } ``` **Handling Example**: ```javascript theme={null} if (response.status === 429) { const retryAfter = response.headers.get('Retry-After') || 1; await sleep(retryAfter * 1000); // Retry request } ``` *** ## Server Errors (500) ### General Server Errors | Code | Name | Description | Solution | | ----- | ------------------------ | ---------------------------- | --------------- | | 500 | `INTERNAL_SERVER_ERROR` | Internal server error | Retry later | | 50001 | `UNKNOWN_ERROR` | Unknown error | Contact support | | 50005 | `DATABASE_ERROR` | Data operation failed | Retry later | | 50007 | `EXTERNAL_SERVICE_ERROR` | External service call failed | Retry later | | 50029 | `EXTERNAL_API_ERROR` | External API request failed | Retry later | ### Blockchain Related Errors | Code | Name | Description | Solution | | ----- | --------------------------------- | -------------------------------- | ---------------------------- | | 50002 | `CHAIN_CONNECTION_ERROR` | Blockchain connection error | Check network status | | 50003 | `CHAIN_SYNC_ERROR` | Blockchain synchronization error | Wait for sync completion | | 50004 | `TRANSACTION_TIMEOUT` | Transaction timeout | Retry or increase timeout | | 50006 | `TRANSACTION_ERROR` | Transaction error | Check transaction parameters | | 50008 | `CHAIN_NOT_SUPPORTED` | Chain not supported | Use supported chain | | 50017 | `INSUFFICIENT_BALANCE` | Insufficient balance | Check account balance | | 50026 | `TRANSACTION_SEND_FAILED` | Transaction send failed | Check network and parameters | | 50027 | `TRANSACTION_CONFIRMATION_FAILED` | Transaction confirmation failed | Check transaction status | | 50028 | `TRANSACTION_SIGNATURE_EMPTY` | Transaction signature is empty | Add signature | ### DEX Related Errors | Code | Name | Description | Solution | | ----- | --------------------------- | ---------------------------- | -------------------------- | | 50009 | `DEX_NOT_SUPPORTED` | DEX not supported | Use supported DEX | | 50010 | `DEX_ROUTE_BUILD_FAILED` | DEX route build failed | Check token pair liquidity | | 50011 | `DEX_SWAP_BUILD_FAILED` | DEX swap build failed | Check trade parameters | | 50012 | `DEX_SWAP_SIMULATED_FAILED` | DEX swap simulation failed | Adjust trade parameters | | 50019 | `DEX_AGGREGATOR_NOT_FOUND` | DEX aggregator not found | Contact support | | 50020 | `DEX_BUILDER_NOT_FOUND` | DEX builder not found | Contact support | | 50033 | `CURVE_CALCULATION_ERROR` | Curve calculation error | Check parameters | | 50034 | `LOOKUP_TABLE_ERROR` | Address lookup table error | Retry later | | 50035 | `SWAP_ROUTE_ERROR` | Swap route calculation error | Check token pair | ### Jupiter API Errors | Code | Name | Description | Solution | | ----- | -------------------------- | ------------------------ | ---------------- | | 50013 | `JUPITER_API_UNAUTHORIZED` | Jupiter API unauthorized | Check API key | | 50014 | `JUPITER_API_RATE_LIMIT` | Jupiter API rate limit | Retry later | | 50015 | `JUPITER_API_BAD_REQUEST` | Jupiter API bad request | Check parameters | | 50016 | `JUPITER_API_ERROR` | Jupiter API error | Retry later | ### Configuration and Initialization Errors | Code | Name | Description | Solution | | ----- | ---------------------------- | -------------------------- | ------------------- | | 50018 | `PROVIDER_NOT_INITIALIZED` | Provider not initialized | Configure rpcUrl | | 50021 | `ORDER_BUILDER_NOT_FOUND` | Order builder not found | Contact support | | 50022 | `MARKET_EXPIRED` | Market has expired | Use valid market | | 50023 | `CONFIG_NOT_FOUND` | Config not found | Check configuration | | 50030 | `FEE_CONFIGURATION_REQUIRED` | Fee configuration required | Configure fee | | 50036 | `METAFIELD_NOT_FOUND` | Metafield not found | Check metadata | ### File Upload Errors | Code | Name | Description | Solution | | ----- | -------------------- | -------------------------- | ----------- | | 50024 | `IPFS_UPLOAD_FAILED` | IPFS upload failed | Retry later | | 50025 | `SIGNED_URL_FAILED` | Signed URL creation failed | Retry later | ### Bundle Processing Errors | Code | Name | Description | Solution | | ----- | ---------------------------- | -------------------------- | -------------------------- | | 50031 | `BUNDLE_PROCESSING_FAILED` | Bundle processing failed | Check bundle configuration | | 50032 | `TIP_ACCOUNTS_NOT_AVAILABLE` | Tip accounts not available | Retry later | ```json theme={null} { "code": 50010, "timestamp": "2026-02-05T10:30:00.000Z", "message": "DEX route build failed", "details": { "input_token": "So11111111111111111111111111111111111111112", "output_token": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", "reason": "No valid route found" } } ``` *** ## Red Packet Errors (510) | Code | Name | Description | Solution | | ----- | ------------------------------------ | ---------------------------- | --------------------------------- | | 51000 | `RED_PACKET_INVALID_PARAMETER_ERROR` | Red packet parameter error | Provide red packet ID or share ID | | 51001 | `RED_PACKET_NOT_FOUND_ERROR` | Red packet not found | Check red packet ID | | 51002 | `RED_PACKET_WITHDRAWN_ERROR` | Red packet withdrawn | Red packet no longer available | | 51003 | `RED_PACKET_ALREADY_CLAIMED_ERROR` | Already claimed red packet | Each user can claim once | | 51004 | `RED_PACKET_TRANSACTION_ERROR` | Red packet transaction error | Retry later | ```json theme={null} { "code": 51003, "timestamp": "2026-02-05T10:30:00.000Z", "message": "You have already claimed this red packet" } ``` *** ## Webhook Errors (520) | Code | Name | Description | Solution | | ----- | --------------------------------- | ------------------------------ | ----------------------- | | 52000 | `WEBHOOKS_APPLICATION_NOT_FOUND` | Webhook application not found | Check webhook ID | | 52001 | `WEBHOOKS_ENDPOINT_LIMIT_REACHED` | Webhook endpoint limit reached | Delete unused endpoints | ```json theme={null} { "code": 52001, "timestamp": "2026-02-05T10:30:00.000Z", "message": "Webhooks endpoint limit reached", "details": { "current_count": 10, "max_allowed": 10 } } ``` *** ## Error Handling Best Practices ```javascript theme={null} import { ChainStreamClient } from '@chainstream-io/sdk'; const client = new ChainStreamClient(process.env.CHAINSTREAM_ACCESS_TOKEN); async function safeApiCall(apiFunction) { try { return await apiFunction(); } catch (error) { const { code, message, details } = error; // Handle errors by category if (code === 401) { // Authentication error: refresh token await refreshToken(); return safeApiCall(apiFunction); } if (code === 429 || code === 42901 || code === 42902) { // Rate limit: wait and retry const retryAfter = details?.reset_at ? (details.reset_at * 1000 - Date.now()) : 1000; await sleep(retryAfter); return safeApiCall(apiFunction); } if (code >= 40000 && code < 41000) { // Client parameter error: log and throw console.error(`Parameter error: ${message}`, details); throw new ValidationError(message, details); } if (code >= 40400 && code < 40500) { // Resource not found console.warn(`Resource not found: ${message}`); return null; } if (code >= 50000) { // Server error: log and retry console.error(`Server error: ${message}`, details); await sleep(1000); return safeApiCall(apiFunction); } // Unknown error throw error; } } // Usage example const tokenInfo = await safeApiCall(() => client.token.getToken('sol', 'TOKEN_ADDRESS') ); ``` *** ## GraphQL API Errors GraphQL queries return errors in the standard `errors` array. Credit consumption is reported in `extensions.credits`: ```json theme={null} { "data": null, "errors": [ { "message": "Unknown field 'InvalidField' on type 'DEXTradesRecord'", "locations": [{ "line": 3, "column": 5 }] } ], "extensions": { "credits": { "total": 0, "cubes": [] } } } ``` | Scenario | Behavior | | :-------------------------------------- | :--------------------------------------------------------------------------- | | Invalid query (syntax/validation error) | `errors` array populated, `data` is null, no credits charged | | Successful query | `data` populated, `extensions.credits.total` shows CU consumed | | Credit limit exceeded | Query may be rejected depending on billing plan — check `extensions.credits` | See [GraphQL Billing & Credits](/en/graphql/billing/graphql-billing) for the full credit calculation formula. *** ## WebSocket Errors WebSocket connections use the endpoint `wss://realtime-dex.chainstream.io/connection/websocket` with `?token=` authentication. | Scenario | Behavior | | :------------------------------ | :------------------------------------------------------------------- | | Invalid token | Connection rejected on handshake | | Token expired | Connection dropped; reconnect with a fresh token | | Network interruption | Client should implement automatic reconnect with exponential backoff | | Subscription to invalid channel | Error message returned on the WebSocket frame | The TypeScript SDK (`@chainstream-io/sdk`) handles WebSocket reconnection automatically. If using a raw WebSocket client, implement exponential backoff (1s, 2s, 4s, 8s...) on disconnection. See [WebSocket API Reference](/en/api-reference/endpoint/websocket/api) and [Timeouts & Heartbeats](/en/api-reference/endpoint/websocket/timeouts-and-heartbeats) for connection management details. *** ## Getting Help If you encounter unresolvable errors: Email us with error code and timestamp Join community for help When reporting issues, please provide the complete error response (including `code`, `timestamp`, `message`, and `details`) so we can quickly identify the problem. # FAQ Source: https://docs.chainstream.io/en/docs/reference/faq ChainStream frequently asked questions ## Account & Authentication 1. Login to [ChainStream Dashboard](https://www.chainstream.io/dashboard) 2. Go to **Apps** page 3. Click **Create New App** 4. Get your Client ID and Client Secret 5. Use Client ID and Client Secret to request an Access Token (JWT) from the Auth service See [Authentication docs](/en/docs/platform/authentication/api-keys-oauth) for details. *** ## Data Related Currently supported chains: | Chain | Status | Notes | | :------- | :---------- | :------------------------------ | | Ethereum | ✅ Supported | Including mainnet and major L2s | | Solana | ✅ Supported | | | BSC | ✅ Supported | | | Polygon | ✅ Supported | | | Arbitrum | ✅ Supported | | | Optimism | ✅ Supported | | | Base | ✅ Supported | | | Tron | ✅ Supported | | See [Realtime Streaming](/en/docs/access-methods/websocket) for more details. | Data Type | Latency | | :-------------------------- | :----------- | | Real-time price (WebSocket) | \< 2ms (P99) | | REST API queries | \< 100ms | | Historical data queries | \< 500ms | Latency may vary based on network conditions and data complexity. | Data Type | Update Frequency | | :----------------- | :---------------------------------- | | Token price | Real-time (triggered by each trade) | | Wallet holdings | Updated per block | | Smart Money labels | Daily updates | Use WebSocket for the most real-time data push. *** ## Billing Related Free plan limits: * **Quota:** 30K Units/month * **Request rate:** 10 requests/sec * **Data latency:** May have 1-2 second delay * **SLA:** Not guaranteed * **Overage:** Returns 403 error when quota exhausted, resets next month Suitable for development testing and POC, not recommended for production. 1. Login to [Dashboard](https://www.chainstream.io/dashboard) 2. View current month usage, remaining quota, and historical trends on the **Usage** page | Method | Supported Plans | | :----------------------------------- | :------------------ | | Credit Card (Visa, MasterCard, AMEX) | All plans | | Cryptocurrency (USDT, USDC) | Starter and above | | Bank Transfer | Enterprise / Custom | Cryptocurrency payments support ERC-20 and TRC-20 networks. * **Upgrade:** Takes effect immediately, prorated charges apply * **Downgrade:** Takes effect in next billing cycle Manage in Dashboard → Billing → Subscription. No. Monthly quotas reset at month end and do not roll over. Choose a plan based on your actual usage. *** ## Technical Issues * **429 error**: Request rate exceeded * **403 error**: Quota exhausted **Troubleshooting:** 1. **429 - Check if rate limited** * Free plan: 10 requests/minute * Paid plans: See [API Security](/en/docs/platform/security/api-security) 2. **403 - Check if quota exhausted** * View remaining quota in Dashboard → Usage * Paid plans can purchase additional quota to restore service **Solutions:** * 429: Implement request throttling or exponential backoff retry * 403: Purchase additional quota or upgrade plan * Use WebSocket instead of polling to reduce request count ```javascript theme={null} // Error handling example async function handleApiError(error) { if (error.status === 429) { // Rate limited, wait and retry await sleep(1000); return retry(); } else if (error.status === 403) { // Quota exhausted, need to purchase additional quota console.error('Quota exhausted, please purchase additional quota in Dashboard'); } } ``` Implement an auto-reconnect mechanism: ```javascript theme={null} class ChainStreamWebSocket { constructor(baseUrl, accessToken) { this.baseUrl = baseUrl; this.accessToken = accessToken; this.reconnectDelay = 1000; this.maxReconnectDelay = 30000; this.connect(); } connect() { // Pass token via URL parameter const url = `${this.baseUrl}?token=${this.accessToken}`; this.ws = new WebSocket(url); this.ws.onopen = () => { console.log('Connected'); this.reconnectDelay = 1000; // Reset delay }; this.ws.onclose = () => { console.log('Disconnected, reconnecting...'); setTimeout(() => this.connect(), this.reconnectDelay); // Exponential backoff this.reconnectDelay = Math.min( this.reconnectDelay * 2, this.maxReconnectDelay ); }; this.ws.onerror = (error) => { console.error('WebSocket error:', error); }; } } ``` **Reconnection tips:** * Use exponential backoff (1s → 2s → 4s → ... → 30s) * Set maximum reconnect delay (e.g., 30 seconds) * Re-subscribe to data after successful reconnection All APIs return JSON format. **Success response:** ```json theme={null} { "chain": "solana", "address": "So11111111111111111111111111111111111111112", "name": "Wrapped SOL", "symbol": "SOL", "decimals": 9, "price": 95.42 } ``` **Error response:** ```json theme={null} { "error": { "code": "INVALID_TOKEN", "message": "Token not found" } } ``` See [Error Codes](/en/docs/reference/error-codes) for common error codes. **Method 1: Use API Playground** Use the "Try It" feature on [API Reference](/en/api-reference/overview) pages to test without writing code. **Method 2: Use cURL** Add `-v` flag for detailed request info: ```bash theme={null} curl -v "https://api.chainstream.io/v1/token/{chain}/{address}/metadata" \ -H "Authorization: Bearer YOUR_ACCESS_TOKEN" ``` *** ## KYT/KYA Related | Feature | KYA (Address Verification) | KYT Report | | :--------------- | :------------------------------------------------- | :----------------------------------------- | | Purpose | Verify address risk and profile analysis | Transaction-level risk reports | | Input | Wallet address | Transaction hash or address | | Output | Risk level + address type + risk exposures | Transaction-related risk analysis | | Typical use case | Address screening before user registration/deposit | Compliance check for specific transactions | See [Security Compliance docs](/en/docs/compliance/overview). Address verification returns these fields: | Field | Description | Example Values | | :------------- | :-------------------- | :---------------------------------------- | | Risk | Risk level | Low, Medium, High, Severe | | Status | Verification status | COMPLETE, PENDING | | Address Type | Address type | PRIVATE\_WALLET, EXCHANGE, CONTRACT, etc. | | Risk Exposures | Risk exposure details | Risk labels and associated amounts | Address Verification returns these risk levels: | Risk Level | Meaning | Recommended Action | | :--------- | :--------------------------------------------------------------- | :------------------------------------ | | Low | Low risk, no obvious suspicious associations | Process normally | | Medium | Medium risk, some suspicious associations | Manual review recommended | | High | High risk, significant suspicious associations | Reject or enhanced review recommended | | Severe | Severe risk, direct association with sanctioned/illegal entities | Strongly recommend rejection | **Note:** Specific handling policies should be based on your business compliance requirements. Above are reference suggestions only. Risk Exposures shows address associations with various risk entities. Common labels include: **High-risk labels (Severe):** | Label | Description | | :---------------------- | :-------------------------------------- | | sanctioned entity | Associated with sanctioned entity | | sanctioned jurisdiction | Associated with sanctioned jurisdiction | | terrorist financing | Associated with terrorist financing | **Neutral/low-risk labels:** | Label | Description | | :--------------------- | :--------------------------------------- | | bridge | Funds transferred via cross-chain bridge | | decentralized exchange | Traded via DEX | | atm | Traded via crypto ATM | **Other risk labels:** | Label | Description | | :------- | :-------------------------------- | | mixer | Via mixing service | | gambling | Associated with gambling platform | | darknet | Associated with darknet market | Each label shows: * **direct / indirect**: Direct or indirect association * **amount**: Associated fund amount * **percentage**: Percentage of total transaction volume | Type | Meaning | Risk Level | | :------- | :------------------------------------------------------- | :--------------- | | direct | Address directly interacted with risk entity | Higher | | indirect | Address indirectly associated via intermediate addresses | Relatively lower | **Examples:** * `sanctioned entity + direct`: Address directly transferred to sanctioned address * `sanctioned entity + indirect`: Associated address of this address previously interacted with sanctioned address Even indirect associations warrant careful handling if involving Severe-level labels (sanctions, terrorist financing). | Address Type | Description | | :----------------- | :--------------------------- | | PRIVATE\_WALLET | Personal wallet address | | EXCHANGE | Centralized exchange address | | CONTRACT | Smart contract address | | MINING\_POOL | Mining pool address | | MERCHANT | Merchant address | | PAYMENT\_PROCESSOR | Payment processor | Address type helps understand fund flow and business context. ```bash theme={null} curl -X POST "https://api.chainstream.io/v1/kya/address/verify" \ -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "address": "So11111111111111111111111111111111111111112", "chain": "sol" }' ``` **Response example:** ```json theme={null} { "address": "So11111111111111111111111111111111111111112", "risk": "Low", "status": "COMPLETE", "address_type": "PRIVATE_WALLET", "risk_exposures": [ { "label": "sanctioned entity", "severity": "Severe", "type": "indirect", "amount": 372262.76, "percentage": 0.6 }, { "label": "bridge", "severity": "Info", "type": "indirect", "amount": 816082.22, "percentage": 1.3 } ] } ``` | Operation | Response Time | | :---------------------------------- | :-------------------- | | New address first verification | Usually 1-5 seconds | | Cached address query | \< 500ms | | Complex address (many transactions) | May take 5-10 seconds | Status `PENDING` indicates analysis in progress; retry later for complete results. KYT/KYA APIs **do not consume plan Units**. They are charged from a separate KYT account balance (in USD). | Operation | Cost | | :------------------------- | :---------- | | Deposit Risk Assessment | \$0.25/call | | Withdrawal Risk Assessment | \$0.25/call | | Register Address | \$1.25/call | Please top up at Dashboard → KYT Service. *** ## AI/MCP Related MCP (Model Context Protocol) is a protocol proposed by Anthropic that enables AI models to call external tools. ChainStream provides an MCP Server that lets Claude and other AIs directly query on-chain data. See [MCP Server docs](/en/docs/ai-agents/mcp-server/introduction). 1. Install ChainStream MCP Server 2. Configure Claude Desktop's MCP settings 3. Restart Claude Desktop 4. Start chatting - Claude can automatically call ChainStream to query data See [Claude Integration guide](/en/docs/ai-agents/mcp-server/setup) for detailed setup. **Not currently supported.** ChainStream MCP Server only provides read operations: * Query token prices and information * Query wallet holdings and transaction history * Execute KYT/KYA risk assessments Does not support automatic transaction execution, transfers, or other write operations for security reasons. MCP calls are billed the same as direct API calls, consuming Units based on the actual API type called. *** ## Contact Support | Channel | Use Case | Response Time | | :------------------------------------------------------------ | :------------------------------------- | :-------------- | | Email [support@chainstream.io](mailto:support@chainstream.io) | General questions | Within 24 hours | | Discord community | Technical discussions, usage questions | Community help | | Dedicated account manager | Enterprise / Custom customers | Within 4 hours | **When contacting, please provide:** * Client ID * Error messages and reproduction steps * **GitHub Issues:** Submit documentation issues * **Email:** [docs@chainstream.io](mailto:docs@chainstream.io) Thanks for helping us improve the documentation! *** ## Didn't find an answer? If the above FAQ didn't answer your question, please contact our technical support team. # Glossary Source: https://docs.chainstream.io/en/docs/reference/glossary Common terminology and concepts in ChainStream documentation This glossary collects professional terms and abbreviations commonly used in ChainStream documentation to help developers quickly understand concepts in Web3 data and blockchain. *** ## Blockchain Terms Basic blockchain concepts and general terminology. ### A A unique identifier on the blockchain used to send and receive assets. Ethereum addresses start with `0x` and are 42 characters long. Example: `0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045` The interface definition of a smart contract, describing functions and data structures for interacting with the contract. ### B The basic unit storing transaction data in a blockchain. Each block contains a set of transactions, timestamp, and the hash of the previous block. | Field | Description | | ------------ | --------------------- | | Block Number | Block height | | Block Hash | Block hash | | Timestamp | Block time | | Transactions | Included transactions | The number of subsequent blocks produced after a transaction is included in a block. More confirmations mean the transaction is more irreversible. | Chain | Recommended Confirmations | | -------- | ------------------------- | | Ethereum | 12-32 | | BSC | 15 | | Solana | 32 | A protocol that allows assets and data to transfer between different blockchains. Common bridges include LayerZero, Wormhole, etc. ### C A blockchain network. ChainStream supports multiple chains including Ethereum, BSC, Polygon, Arbitrum, Solana, etc. Chain identifier examples: * `ethereum` - Ethereum Mainnet * `bsc` - BNB Chain * `arbitrum` - Arbitrum One * `solana` - Solana The unique address where a smart contract is deployed on the blockchain. Unlike regular addresses (EOA), contract addresses are controlled by code. ### E An account controlled by a private key, as opposed to a smart contract address. Ethereum token standard. Defines basic token function interfaces like `transfer`, `approve`, `balanceOf`, etc. Ethereum NFT standard. Defines the interface specification for non-fungible tokens. The runtime environment for executing smart contract code. Polygon, Arbitrum, Base are all EVM-compatible chains. ### G The fee unit required to execute blockchain transactions. Gas Fee = Gas Used × Gas Price. | Term | Description | | --------- | --------------------------------------- | | Gas Limit | Maximum gas consumption for transaction | | Gas Used | Actual gas consumed | | Gas Price | Price per gas unit | | Gwei | Gas Price unit, 1 Gwei = 10⁻⁹ ETH | ### H A cryptographic function that converts arbitrary length data to a fixed-length string. Commonly used for transaction hashes, block hashes in blockchain. Example: `0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef` ### L First layer blockchain. Independent main chains like Ethereum, Solana, Bitcoin. Second layer scaling solutions. Scaling solutions built on top of L1, like Arbitrum, Optimism, Base, zkSync. ### M Staging area for pending transactions. Transactions wait in the mempool before being included in a block. ### N Unique digital assets, commonly used for digital art, gaming items, etc. A computer running blockchain software, participating in network validation and data storage. Transaction sequence number. An incrementing counter for each address sending transactions, preventing replay attacks. ### R Protocol for interacting with blockchain nodes, used to send transactions, query data, etc. ### S Program code that automatically executes on the blockchain. Once deployed, code logic cannot be changed (unless upgrade mechanism is designed). ### T Digital assets on the blockchain. Includes native tokens (like ETH) and contract tokens (like USDC). State change operations on the blockchain, such as transfers, contract calls, etc. | Field | Description | | ---------- | ----------------------------------- | | TxHash | Transaction hash, unique identifier | | From | Sender address | | To | Receiver address | | Value | Transfer amount | | Input Data | Contract call data | The unique identifier of a transaction. Can be used to query transaction details on block explorers. ### W A tool for storing and managing crypto assets. Can be software (like MetaMask) or hardware (like Ledger). *** ## DeFi Terms Decentralized finance related concepts. ### A Algorithm mechanism for providing liquidity and pricing in DEXes, like Uniswap's constant product formula `x * y = k`. Annual interest rate without considering compounding. Annual yield percentage considering compounding. Formula: `APY = (1 + APR/n)^n - 1`, where n is the number of compounding periods. The highest price a token or asset has ever reached. The lowest price a token or asset has ever reached. ### C Cryptocurrency trading platforms operated by centralized institutions. Examples: Binance, Coinbase, OKX, Bybit Assets used to secure loans in lending protocols. Collateral ratio typically needs to exceed 100%. ### D Trading platforms that don't require centralized institutions, automatically executing trades through smart contracts. Examples: Uniswap, SushiSwap, Raydium, Jupiter Applications running on the blockchain. Blockchain-based financial services and applications, including trading, lending, derivatives, etc. ### F The practice of earning token rewards by providing liquidity to DeFi protocols. Total market value assuming all tokens are issued. Formula: `FDV = Token Price × Total Supply` Instant uncollateralized loans that must be repaid within the same block/transaction. Commonly used for arbitrage, liquidation, etc. ### H A metric measuring position safety in lending protocols. Position may be liquidated when health factor \< 1. ### I Loss incurred by liquidity providers relative to simply holding assets due to price volatility. | Price Change | Impermanent Loss | | ------------ | ---------------- | | ±25% | -0.6% | | ±50% | -2.0% | | ±100% | -5.7% | ### L The process where protocols automatically sell collateral to repay debt when lending position collateral ratio falls below threshold. The amount of assets available for trading in a market. High liquidity means large trades won't significantly affect price. Smart contracts in DEXes that store trading pair assets, providing liquidity for trades. Users who provide assets to DEX pools and earn trading fees as rewards. Tokens representing a user's share in a liquidity pool, can be used to redeem assets or stake for mining. ### M Total market value of a token. Formula: `Market Cap = Token Price × Circulating Supply` Extra value miners or validators extract through transaction ordering, insertion, or censorship. Common MEV types: * Sandwich Attack * Front-running * Back-running * Liquidation ### O Services providing off-chain data to smart contracts, like Chainlink, Pyth. Commonly used for price data. ### S The difference between expected trade price and actual execution price. Can be larger in pools with lower liquidity. Locking tokens in protocols to earn rewards or participate in governance. Token exchange operations on DEXes. ### T Total value of assets locked in DeFi protocols, an important metric for measuring protocol scale. ### W Addresses or investors holding large amounts of crypto assets. Typically refers to addresses holding more than 1% of a token's supply. ### Y Returns from investing in DeFi protocols, including trading fee shares, token rewards, interest, etc. *** ## ChainStream Terms ChainStream product and service related concepts. ### A A JWT (JSON Web Token) used to authenticate API requests. **How to obtain**: 1. Create an App in Dashboard to get Client ID and Client Secret 2. Use Client ID and Client Secret to call the auth service to generate an Access Token 3. Use `Authorization: Bearer ` in API request headers **Auth domain**: `dex.asia.auth.chainstream.io` **Scopes**: | Scope | Description | | --------------- | ---------------------------- | | `webhook.read` | Webhook API read permission | | `webhook.write` | Webhook API write permission | | `kyt.read` | KYT API read permission | | `kyt.write` | KYT API write permission | Security tips: * Don't expose Client Secret in client-side code * Don't commit credentials to version control * Store sensitive information in environment variables * Access Tokens expire, refresh them periodically See [Authentication Documentation](/en/api-reference/authentication/authenticate) ### C Unit for measuring API request complexity in ChainStream. Different endpoints consume different CUs. ### K ChainStream's address risk assessment service, analyzing address historical behavior and associated risks. ChainStream's transaction risk control service, assessing transaction fund sources and risk levels. Risk Levels: | Level | Description | | ------ | ------------------------------------ | | Low | Low risk, can process automatically | | Medium | Medium risk, recommend manual review | | High | High risk, recommend blocking | | Severe | Severe risk, must block | ### R API request frequency limits. ChainStream provides different rate limits based on subscription tier. Response headers: * `X-RateLimit-Limit` - Total limit * `X-RateLimit-Remaining` - Remaining count * `X-RateLimit-Reset` - Reset time ### S Addresses identified by ChainStream that consistently achieve above-market returns. Types: * Top Traders * Early Investors * Institutional Wallets * KOL Wallets See [Smart Money Methodology](/en/docs/data-products/smart-money) ChainStream's comprehensive score for wallet addresses, reflecting trading ability and historical performance. | Score Range | Level | | ----------- | --------------- | | 90-100 | Top Smart Money | | 75-89 | Quality Trader | | 60-74 | Good Trader | | \< 60 | Average Trader | ### W A mechanism for sending notifications to specified URLs when events trigger. **Supported event types**: | Event | Description | | -------------------- | -------------------------------------------------------------- | | `sol.token.created` | New token created on Solana | | `sol.token.migrated` | Token graduated (migrated from Bonding Curve to DEX) on Solana | More event types are under development. **Management endpoints**: * `POST /v1/webhook/endpoint` - Create Webhook * `GET /v1/webhook/endpoint` - List Webhooks * `DELETE /v1/webhook/endpoint/{id}` - Delete Webhook See [Webhook Fundamentals](/en/docs/recipes/webhook-fundamentals) A network protocol supporting real-time bidirectional communication. ChainStream provides real-time data streams via WebSocket. **Endpoint**: `wss://realtime-dex.chainstream.io/connection/websocket` **Connection format**: ``` wss://realtime-dex.chainstream.io/connection/websocket?token=YOUR_ACCESS_TOKEN ``` **Supported subscription types**: * Token candles (`dex-token-candles`) * Token stats (`dex-token-stats`) * Token holders (`token-holders`) * New tokens (`dex-new-token`) * Wallet balance (`wallet-balance`) * Wallet trades (`wallet-trade`) When using SDKs, authentication is handled automatically. See [WebSocket API](/en/api-reference/endpoint/websocket/introduction) *** ## AI Terms AI and MCP related concepts. ### A An AI system capable of autonomously executing tasks. AI Agents can use tools, access external data, and make decisions. Structured instruction packages (`SKILL.md` files) that teach AI coding assistants how to use specific capabilities. ChainStream provides two skills: `chainstream-data` (read-only data queries) and `chainstream-defi` (DeFi execution). Skills include decision trees, workflows, safety rules, and error recovery — everything an AI agent needs to operate autonomously. See [Agent Skills Introduction](/en/docs/ai-agents/agent-skills/introduction) ### C Information the AI model references when generating responses, including conversation history, system prompts, external data, etc. The maximum number of tokens an AI model can process at once. Larger context windows allow processing more information. ### L AI models trained on large amounts of text data, such as Claude, GPT, etc. ### M An open protocol developed by Anthropic that allows AI models to interact with external data sources and tools. ChainStream MCP Server implements this protocol, enabling AI to directly query on-chain data. See [MCP Introduction](/en/docs/ai-agents/mcp-server/introduction) Server implementing MCP protocol, providing tools and data. ChainStream MCP Server provides on-chain data query capabilities. Applications using MCP protocol to call tools, such as Claude Desktop, Cursor. A payment protocol using the Tempo network (chain ID 4217) for USDC.e payments. An alternative to x402 for AI agents that prefer paying on Tempo. Gas is paid in USDC.e directly — no ETH needed. See [x402 Payment](/en/docs/platform/billing-payments/x402-payments) ### P Input text given to AI models to guide the model to generate expected output. ### T The standard file format for Agent Skills. Contains YAML frontmatter (name, description) and structured markdown with decision trees, workflows, safety rules, and references. Used by AI coding assistants like Cursor, Claude Code, and Codex. Computing environment providing hardware-level security protection, ensuring confidentiality and integrity of code and data. ChainStream CLI uses a TEE for wallet key management — private keys never leave the secure enclave. See [CLI Authentication](/en/docs/platform/authentication/api-keys-oauth) The basic unit AI models use to process text. One token is approximately 4 English characters or 1-2 Chinese characters. This Token refers to AI tokens, which is different from blockchain tokens. Functions defined in MCP that can be called by AI. Tools provided by ChainStream include `get_token_balance`, `analyze_wallet`, etc. ### X An open payment protocol built on HTTP 402 (Payment Required) by [Coinbase](https://github.com/coinbase/x402). Enables AI Agents to pay per API call using USDC stablecoins on Base network. ChainStream supports x402 as an authentication scheme — agents without an API key can pay for each tool invocation via signed on-chain authorization (EIP-3009 or Permit2), verified through a Facilitator service. No account registration required. *** ## Quick Reference ### By Letter | Letter | Terms | | ------ | ------------------------------------------------------------------- | | A | Address, ABI, AMM, Access Token, APR, APY, ATH, Agent, Agent Skills | | B | Block, Bridge | | C | CEX, Chain, CU, Context | | D | DEX, DeFi, dApp | | E | EOA, ERC-20, EVM | | F | FDV, Flash Loan, Farming | | G | Gas | | H | Hash, Health Factor | | I | Impermanent Loss | | K | KYA, KYT | | L | L1, L2, Liquidity, LP, LLM | | M | Market Cap, MCP, MEV, Mempool, MPP | | N | NFT, Node, Nonce | | O | Oracle | | P | Prompt | | R | Rate Limit, RPC | | S | SKILL.md, Slippage, Smart Contract, Smart Money, Staking, Swap | | T | Token, TVL, TxHash, TEE, Tool | | W | Wallet, Webhook, WebSocket, Whale | | X | x402 | | Y | Yield | *** ## Related Documentation Learn about ChainStream products API documentation Deep dive into Smart Money Learn about MCP protocol # Supported Chains Source: https://docs.chainstream.io/en/docs/supported-chains Supported blockchains, chain identifiers, and capability coverage ChainStream currently supports **3 blockchains** for data and DeFi operations. ## Chain Overview | Chain | Identifier | Type | Native Token | Data API | DeFi (Swap) | WebSocket | KYT/KYA | | -------- | ---------- | ---- | ------------ | -------- | ----------- | --------- | ------- | | Solana | `sol` | L1 | SOL | Yes | Yes | Yes | Yes | | BSC | `bsc` | L1 | BNB | Yes | Yes | Yes | Yes | | Ethereum | `eth` | L1 | ETH | Yes | Yes | Yes | Yes | Always use **lowercase** chain identifiers: `sol`, `eth`, `bsc`. ## DEX Coverage by Chain | Chain | Supported DEXes | | -------- | ------------------------------------------ | | Solana | Jupiter, Raydium, PumpFun, Moonshot, Candy | | BSC | KyberSwap | | Ethereum | KyberSwap | Token creation is only available on Solana launchpads: PumpFun, Raydium. ## Data Availability ### Real-time Data All three chains provide: * Token metadata, stats, and market data * Wallet balances, PnL, and net worth * Trade history and activity feeds * Token rankings (hot, new, migrated, graduating) * Holder analytics and distribution * Security audit flags ### WebSocket Streaming Real-time subscriptions available on all chains: * Token price and stats updates * OHLCV candlestick feeds * Trade activity streams * Wallet balance changes * New token creation events * Bonding curve progress (Solana) ### DeFi Operations | Operation | Solana | Ethereum | BSC | | -------------------------- | ------ | -------- | --- | | Swap (quote + execute) | Yes | Yes | Yes | | Token creation (launchpad) | Yes | -- | -- | | Transaction broadcast | Yes | Yes | Yes | | Gas estimation | -- | Yes | Yes | ## Chain Identifiers Across Products | Context | Solana | BSC | Ethereum | | ------------- | ------ | ----- | -------- | | REST API | `sol` | `bsc` | `eth` | | CLI `--chain` | `sol` | `bsc` | `eth` | | SDK | `sol` | `bsc` | `eth` | | MCP Tools | `sol` | `bsc` | `eth` | | WebSocket | `sol` | `bsc` | `eth` | ## Next Steps Make your first API call in 5 minutes. Install the TypeScript SDK and start building. Connect your AI agent to on-chain data. # AI Agent with MCP Source: https://docs.chainstream.io/en/docs/tutorials/ai-agent-with-mcp Build an AI trading assistant with Claude that can query on-chain data This tutorial introduces how to use ChainStream MCP Server to build an AI assistant that can query on-chain data, analyze markets, and assist with trading decisions. **Estimated Time**: 30 minutes\ **Difficulty Level**: ⭐⭐ Beginner *** ## Objective Build an AI assistant with on-chain awareness: ```mermaid theme={null} flowchart TD A[User Query] --> B[Claude + MCP] B --> C[ChainStream API] C --> B B --> D[Response] ``` **Capabilities**: * ✅ Query Token prices and balances * ✅ Analyze wallet holdings * ✅ Track Smart Money *** ## Step 1: Configure MCP ### Prerequisites * ChainStream account (to get Client ID and Client Secret) * Claude Desktop or Cursor * Node.js 18+ ### Install MCP Server ```bash theme={null} npm install -g @chainstream/mcp-server ``` ### Configure Claude Desktop Edit the configuration file: ```bash theme={null} # Config file path ~/Library/Application Support/Claude/claude_desktop_config.json ``` ```bash theme={null} # Config file path %APPDATA%\Claude\claude_desktop_config.json ``` Add configuration: ```json theme={null} { "mcpServers": { "chainstream": { "url": "https://mcp.chainstream.io/mcp", "headers": { "Authorization": "Bearer your_access_token" } } } } ``` Restart Claude Desktop. For detailed steps, refer to the [MCP Setup Guide](/en/docs/ai-agents/mcp-server/setup). *** ## Step 2: Conversation Examples ### Example 1: Check ETH Price ``` User: Show me the ETH price Claude: [Calls get_token_price tool] ETH Current Price: - Price: $2,015.32 - 24h Change: +2.5% - 24h Volume: $12.5B - Market Cap: $242B ``` ### Example 2: Analyze Wallet Holdings ``` User: Analyze the holdings of 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 Claude: [Calls get_token_balance and analyze_wallet tools] This address (vitalik.eth) holdings analysis: Holdings Overview | Token | Amount | Value | |-------|--------|-------| | ETH | 1,234 | $2.48M | | USDC | 50,000 | $50K | | ENS | 10,000 | $25K | Wallet Characteristics - Wallet Age: 7+ years - Tags: Core Developer, Long-term Holder - Main Activities: DeFi, NFT, Donations ``` ### Example 3: Track Smart Money ``` User: Which Smart Money addresses have been buying ARB recently? Claude: [Calls get_smart_money_activities tool] Past 24h Smart Money ARB Buy Records: 1. 0xabc...123 (Smart Score: 92) - Bought: 500,000 ARB ($450K) - Time: 2 hours ago - Tags: DeFi Expert, High Win-rate Trader 2. 0xdef...456 (Smart Score: 85) - Bought: 200,000 ARB ($180K) - Time: 5 hours ago - Tags: Institutional Wallet Trend Analysis: Smart Money overall shows net buying stance on ARB ``` *** ## Step 3: Advanced Usage ### Multi-step Analysis ``` User: First check this address's holdings, then analyze its recent trades, and determine its investment style Claude: I'll analyze step by step: Step 1: Holdings Query [Calls get_token_balance] ... Step 2: Transaction History [Calls get_transaction_history] ... Step 3: Comprehensive Analysis [Calls analyze_wallet] Based on the above data, this address's investment style is: - Type: Medium to Long-term Holder - Preference: DeFi Blue Chips + Layer2 - Risk Appetite: Moderate - Characteristic: Good at adding positions during pullbacks ``` ### Comparative Analysis ``` User: Compare the trading strategies of these two addresses Claude: [Calls analyze_wallet x2] | Dimension | Address A | Address B | |-----------|-----------|-----------| | Trading Frequency | High (50/day) | Low (5/day) | | Holding Style | Short-term | Long-term | | Win Rate | 62% | 78% | | Preferred Sector | Meme Coins | DeFi | | Risk Level | High | Medium | ``` *** ## Security Considerations ### Strategy Limitations The AI assistant only provides data queries and analysis, not direct trade execution. ``` User: Buy 100 USDC worth of ETH for me Claude: I can help you query the current ETH price and best trading routes, but cannot execute trades directly. Current ETH price: $2,015 Suggested execution methods: 1. Uniswap V3 - Expected slippage 0.1% 2. 1inch Aggregator - May get better price Please execute the trade manually in your wallet. ``` ### Human Confirmation For important decisions, AI provides analysis but recommends human confirmation: Based on analysis, multiple Smart Money addresses are buying ARB, but please note: * This does not constitute investment advice * Markets are risky, please judge independently * Recommend combining with more information sources *** ## Extension: Custom Agent ### Build with MCP SDK ```javascript theme={null} import Anthropic from '@anthropic-ai/sdk'; import { Client } from '@modelcontextprotocol/sdk/client/index.js'; import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js'; const anthropic = new Anthropic(); // Initialize MCP Client async function createMcpClient() { const transport = new SSEClientTransport( new URL('https://mcp.chainstream.io/sse'), { requestInit: { headers: { 'Authorization': `Bearer ${process.env.CHAINSTREAM_ACCESS_TOKEN}` } } } ); const client = new Client({ name: 'custom-agent', version: '1.0.0' }); await client.connect(transport); return client; } async function chat(userMessage) { const mcp = await createMcpClient(); // Get available tools const { tools } = await mcp.listTools(); // Convert to Anthropic format const anthropicTools = tools.map(tool => ({ name: tool.name, description: tool.description, input_schema: tool.inputSchema })); // Call Claude let response = await anthropic.messages.create({ model: 'claude-sonnet-4-20250514', max_tokens: 1024, tools: anthropicTools, messages: [{ role: 'user', content: userMessage }] }); // Handle tool calls while (response.stop_reason === 'tool_use') { const toolUse = response.content.find(c => c.type === 'tool_use'); // Call MCP tool const toolResult = await mcp.callTool({ name: toolUse.name, arguments: toolUse.input }); // Continue conversation with tool result response = await anthropic.messages.create({ model: 'claude-sonnet-4-20250514', max_tokens: 1024, tools: anthropicTools, messages: [ { role: 'user', content: userMessage }, { role: 'assistant', content: response.content }, { role: 'user', content: [{ type: 'tool_result', tool_use_id: toolUse.id, content: JSON.stringify(toolResult.content) }] } ] }); } await mcp.close(); return response.content.find(c => c.type === 'text')?.text; } // Usage const result = await chat('Check ETH price on Ethereum'); console.log(result); ``` *** ## Available MCP Tools | Tool | Description | | ---------------------------- | --------------------------------- | | `get_token_balance` | Query address token balance | | `get_token_price` | Get real-time token price | | `get_transaction_history` | Query address transaction history | | `get_smart_money_activities` | Get Smart Money activities | | `get_defi_positions` | Query DeFi positions | | `analyze_wallet` | Analyze wallet characteristics | | `get_token_holders` | Get token holder analysis | *** ## FAQ 1. Confirm MCP Server is configured correctly 2. Restart Claude Desktop 3. Check if Client ID and Client Secret are valid 4. Try more explicit prompts like "Use ChainStream to query..." On-chain data queries take time, especially for complex analysis. You can: 1. Ask step by step to reduce single query load 2. Specify a specific chain to reduce query scope The current version only supports data queries, not direct trade execution. This is for security reasons. For automated trading, we recommend executing through a separate trading system based on AI analysis results. *** ## Related Documentation Detailed configuration steps View all available tools # Build Arbitrage Scanner Source: https://docs.chainstream.io/en/docs/tutorials/build-arbitrage-scanner Discover cross-DEX price differences and identify arbitrage opportunities ChainStream currently supports **Solana** (`sol`), **Ethereum** (`eth`), and **BSC** (`bsc`). Supported DEXes are Jupiter, Raydium, PumpFun, Moonshot, Candy (Solana), and KyberSwap (Ethereum/BSC). Some code examples below reference additional DEXes for conceptual illustration — check [Supported Chains](/en/docs/supported-chains) for the current coverage. **Coming Soon** — This feature is under development and not yet available. This tutorial will guide you through building a cross-DEX arbitrage scanner that discovers price differences between exchanges in real-time and identifies potential arbitrage opportunities. **Estimated Time**: 45 minutes\ **Difficulty Level**: ⭐⭐⭐ Intermediate *** ## Objective Discover cross-DEX price difference arbitrage opportunities: ```mermaid theme={null} flowchart TD A[Jupiter Price Data] --> C[Arbitrage Scanner] B[Raydium Price Data] --> C C --> D[Opportunity & Notify] ``` **Feature Checklist**: * ✅ Get multi-DEX trading pair prices * ✅ Calculate spread percentage * ✅ Evaluate feasibility (considering Gas, slippage, depth) * ✅ Risk alerts (MEV, front-running) *** ## Arbitrage Principles ### Cross-DEX Arbitrage The same token may have price differences across different DEXes: ``` Example: SOL/USDC on Solana Jupiter: 1 SOL = $140.00 Raydium: 1 SOL = $140.70 Spread = ($140.70 - $140.00) / $140.00 = 0.5% Arbitrage path: Buy SOL on Jupiter → Sell SOL on Raydium → Profit from difference ``` ### Profit Formula **Net Profit = Spread Revenue - Gas Fees - Slippage Loss** Practical considerations: * Gas fees for two transactions * Buy/sell slippage * Liquidity depth limits * MEV front-running risk *** ## Step 1: Get Trading Pairs ### 1.1 Install Dependencies ```bash theme={null} npm install @chainstream-io/sdk dotenv ``` ### 1.2 Configuration File ```javascript theme={null} // config.js import 'dotenv/config'; export const CHAINSTREAM_ACCESS_TOKEN = process.env.CHAINSTREAM_ACCESS_TOKEN; // DEXes to monitor (Solana: Jupiter, Raydium, PumpFun, Moonshot, Candy; EVM: KyberSwap on eth/bsc) export const DEXES = ['jupiter', 'raydium', 'pumpfun', 'moonshot', 'candy']; // Trading pairs to monitor (multi-DEX spread checks are strongest on Solana in current coverage) export const TRADING_PAIRS = [ { base: 'SOL', quote: 'USDC', chain: 'sol' }, { base: 'SOL', quote: 'USDT', chain: 'sol' }, ]; // Arbitrage thresholds export const MIN_PROFIT_PERCENT = 0.3; // Minimum profit rate export const MIN_LIQUIDITY_USD = 50000; // Minimum liquidity ``` ### 1.3 Get Price Data ```javascript theme={null} // scanner.js import { ChainStreamClient } from '@chainstream-io/sdk'; import { CHAINSTREAM_ACCESS_TOKEN, DEXES } from './config.js'; export class PriceScanner { constructor() { this.client = new ChainStreamClient(CHAINSTREAM_ACCESS_TOKEN); } async getDexPrices(base, quote, chain) { // Get trading pair prices across DEXes const prices = await this.client.dex.getPrices({ base, quote, chain, dexes: DEXES }); return prices; } } ``` *** ## Step 2: Calculate Spread ```javascript theme={null} // evaluator.js import { MIN_PROFIT_PERCENT, MIN_LIQUIDITY_USD } from './config.js'; export class ArbitrageEvaluator { findOpportunity(prices, pair) { // Filter low liquidity const validPrices = prices.filter( p => (p.liquidityUsd || 0) >= MIN_LIQUIDITY_USD ); if (validPrices.length < 2) { return null; } // Find lowest buy price and highest sell price const sortedPrices = [...validPrices].sort((a, b) => a.price - b.price); const buyFrom = sortedPrices[0]; // Lowest price - buy const sellTo = sortedPrices[sortedPrices.length - 1]; // Highest price - sell // Calculate spread const spread = (sellTo.price - buyFrom.price) / buyFrom.price * 100; // Estimate costs const gasCostPercent = 0.1; // ~0.1% const slippagePercent = 0.2; // ~0.2% const totalCost = gasCostPercent + slippagePercent; // Net profit const netProfit = spread - totalCost; if (netProfit < MIN_PROFIT_PERCENT) { return null; } return { pair: `${pair.base}/${pair.quote}`, buyDex: buyFrom.dex, buyPrice: buyFrom.price, sellDex: sellTo.dex, sellPrice: sellTo.price, spreadPercent: Number(spread.toFixed(3)), netProfitPercent: Number(netProfit.toFixed(3)), maxSizeUsd: Math.min(buyFrom.liquidityUsd, sellTo.liquidityUsd) * 0.02 }; } } ``` *** ## Step 3: Evaluate Feasibility ### Risk Assessment ```javascript theme={null} // risk.js export function assessRisk(opportunity) { const risks = []; // MEV risk if (opportunity.netProfitPercent > 1.0) { risks.push('🔴 High profit easily front-run by MEV'); } // Liquidity risk if (opportunity.maxSizeUsd < 5000) { risks.push('🟡 Executable size is small'); } // Timing risk risks.push('⚠️ Price data has latency'); return { risks, executable: risks.filter(r => r.includes('🔴')).length === 0 }; } ``` ### Risk Warning **Important Risk Warnings**: 1. **MEV Front-running**: Arbitrage trades are easily front-run by MEV bots 2. **Price Latency**: Prices may have changed by execution time 3. **Gas Volatility**: Costs can surge significantly during network congestion 4. **Slippage**: Actual slippage may be higher than estimated This tool is only for discovering opportunities and does not constitute investment advice. *** ## Complete Code ```javascript theme={null} // index.js import { PriceScanner } from './scanner.js'; import { ArbitrageEvaluator } from './evaluator.js'; import { TRADING_PAIRS } from './config.js'; async function main() { const scanner = new PriceScanner(); const evaluator = new ArbitrageEvaluator(); console.log('🔍 Arbitrage scanner starting...'); while (true) { for (const pair of TRADING_PAIRS) { const prices = await scanner.getDexPrices( pair.base, pair.quote, pair.chain ); const opp = evaluator.findOpportunity(prices, pair); if (opp) { console.log(` 🎯 Arbitrage opportunity found! Pair: ${opp.pair} Buy: ${opp.buyDex} @ $${opp.buyPrice} Sell: ${opp.sellDex} @ $${opp.sellPrice} Spread: ${opp.spreadPercent}% Net Profit: ${opp.netProfitPercent}% Max Size: $${opp.maxSizeUsd.toLocaleString()} `); } } // Scan every 10 seconds await new Promise(resolve => setTimeout(resolve, 10000)); } } main(); ``` *** ## Extension Suggestions Use flash loans for zero-capital arbitrage Add **eth** / **bsc** KyberSwap quotes alongside Solana venues Integrate wallet for automatic trading (use caution) *** ## Related Documentation Learn about DeFi monitoring dimensions Get started with real-time price monitoring # Build Price Alert Bot Source: https://docs.chainstream.io/en/docs/tutorials/build-price-alert-bot Build a real-time price monitoring bot using WebSocket + Telegram This tutorial will guide you through building a real-time price monitoring bot from scratch that automatically sends Telegram notifications when target token price changes exceed a set threshold. **Estimated Time**: 30 minutes\ **Difficulty Level**: ⭐⭐ Beginner *** ## Objective Build a bot that monitors token prices and sends automatic notifications: ```mermaid theme={null} flowchart TD A[ChainStream WebSocket] --> B[Price Bot] B --> C[Telegram Notification] ``` **Feature Checklist**: * ✅ Subscribe to real-time price stream * ✅ Set price change trigger conditions (> X%) * ✅ Send Telegram notifications * ✅ Support multi-token monitoring *** ## Tech Stack | Component | Technology | Purpose | | -------------- | --------------------- | ------------------------- | | Language | Node.js 18+ | Main development language | | Real-time Data | WebSocket | Subscribe to price stream | | Notification | Telegram Bot API | Send alerts | | Configuration | Environment Variables | Store sensitive info | *** ## Prerequisites * ChainStream account (to get Access Token) * Node.js 18+ * Telegram Account *** ## Step 1: Connect WebSocket ### 1.1 Install Dependencies ```bash theme={null} npm install @chainstream-io/sdk node-telegram-bot-api dotenv ``` ### 1.2 Create Project Structure ``` price-alert-bot/ ├── .env ├── config.js ├── bot.js └── index.js ``` ### 1.3 Configuration Files **.env**: ``` CHAINSTREAM_ACCESS_TOKEN=your_access_token TELEGRAM_BOT_TOKEN=your_bot_token TELEGRAM_CHAT_ID=your_chat_id ``` **config.js**: ```javascript theme={null} import 'dotenv/config'; // ChainStream Config export const CHAINSTREAM_ACCESS_TOKEN = process.env.CHAINSTREAM_ACCESS_TOKEN; // Telegram Config export const TELEGRAM_BOT_TOKEN = process.env.TELEGRAM_BOT_TOKEN; export const TELEGRAM_CHAT_ID = process.env.TELEGRAM_CHAT_ID; // Watch Config export const WATCH_TOKENS = [ { chain: 'sol', address: '6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN', symbol: 'EXAMPLE', thresholdPercent: 3.0 // Trigger at 3% change }, { chain: 'sol', address: 'So11111111111111111111111111111111111111112', symbol: 'SOL', thresholdPercent: 5.0 // Trigger at 5% change } ]; ``` ### 1.4 WebSocket Connection **index.js**: ```javascript theme={null} import { ChainStreamClient } from '@chainstream-io/sdk'; import { CHAINSTREAM_ACCESS_TOKEN, WATCH_TOKENS } from './config.js'; import { sendAlert } from './bot.js'; class PriceMonitor { constructor() { this.client = new ChainStreamClient(CHAINSTREAM_ACCESS_TOKEN); this.lastPrices = new Map(); // Record last prices } async start() { console.log('✅ Starting price monitoring...'); // Subscribe to each token's stats for (const token of WATCH_TOKENS) { this.subscribeToken(token); } } subscribeToken(token) { this.client.stream.subscribeTokenStats({ chain: token.chain, tokenAddress: token.address, callback: (data) => this.handlePriceUpdate(token, data) }); console.log(`📡 Subscribed to ${token.symbol} price stream`); } handlePriceUpdate(token, data) { const currentPrice = data.price || data.p; if (!currentPrice) return; const lastPrice = this.lastPrices.get(token.address); if (lastPrice) { // Calculate change percentage const changePercent = ((currentPrice - lastPrice) / lastPrice) * 100; // Check if alert should be triggered if (Math.abs(changePercent) >= token.thresholdPercent) { this.triggerAlert(token, currentPrice, changePercent); } } // Update price record this.lastPrices.set(token.address, currentPrice); } async triggerAlert(token, price, change) { const direction = change > 0 ? '📈 UP' : '📉 DOWN'; const message = ` ${direction} Price Alert! 🪙 Token: ${token.symbol} 💰 Current Price: $${price.toFixed(6)} 📊 Change: ${change >= 0 ? '+' : ''}${change.toFixed(2)}% ⚡ Threshold: ${token.thresholdPercent}% `.trim(); await sendAlert(message); console.log(`🚨 Alert sent: ${token.symbol} ${change >= 0 ? '+' : ''}${change.toFixed(2)}%`); } } // Start monitoring const monitor = new PriceMonitor(); monitor.start(); ``` *** ## Step 2: Set Trigger Conditions Trigger conditions are configured in `config.js`: ```javascript theme={null} export const WATCH_TOKENS = [ { symbol: 'EXAMPLE', thresholdPercent: 3.0 // Trigger when price change > 3% }, // ... ]; ``` ### Advanced Trigger Conditions Can be extended to more complex conditions: ```javascript theme={null} // Multi-condition triggers const ALERT_CONDITIONS = { priceChange: { enabled: true, thresholdPercent: 5.0 }, priceAbove: { enabled: true, value: 100 // Trigger when price exceeds $100 }, priceBelow: { enabled: true, value: 50 // Trigger when price falls below $50 } }; ``` *** ## Step 3: Send Notifications ### 3.1 Create Telegram Bot Search for `@BotFather` in Telegram, send `/newbot` Follow prompts to create Bot, get Bot Token * Send a message to your Bot * Visit `https://api.telegram.org/bot/getUpdates` * Find `chat.id` ### 3.2 Telegram Notification Module **bot.js**: ```javascript theme={null} import TelegramBot from 'node-telegram-bot-api'; import { TELEGRAM_BOT_TOKEN, TELEGRAM_CHAT_ID } from './config.js'; const bot = new TelegramBot(TELEGRAM_BOT_TOKEN); export async function sendAlert(message) { try { await bot.sendMessage(TELEGRAM_CHAT_ID, message, { parse_mode: 'HTML' }); } catch (error) { console.error(`❌ Telegram send failed: ${error.message}`); } } export async function sendAlertWithRetry(message, maxRetries = 3) { for (let attempt = 0; attempt < maxRetries; attempt++) { try { await sendAlert(message); return true; } catch (error) { if (attempt < maxRetries - 1) { // Exponential backoff await new Promise(resolve => setTimeout(resolve, 2 ** attempt * 1000)); } else { console.error(`❌ Notification failed after ${maxRetries} retries`); return false; } } } } ``` *** ## Verify Installation ### Run Bot ```bash theme={null} node index.js ``` ### Expected Output ``` ✅ Starting price monitoring... 📡 Subscribed to EXAMPLE price stream 📡 Subscribed to SOL price stream ``` ### Trigger Test Temporarily set threshold to 0.01% for quick testing: ```javascript theme={null} thresholdPercent: 0.01 // For testing ``` *** ## Extension Suggestions ```javascript theme={null} // Dynamically fetch watchlist from API async function fetchWatchlist() { const response = await fetch('https://api.chainstream.io/v1/watchlist'); return response.json(); } ``` ```javascript theme={null} import Database from 'better-sqlite3'; const db = new Database('alerts.db'); // Create table db.exec(` CREATE TABLE IF NOT EXISTS alerts ( id INTEGER PRIMARY KEY AUTOINCREMENT, symbol TEXT, price REAL, change REAL, timestamp INTEGER ) `); function saveAlert(alertData) { const stmt = db.prepare(` INSERT INTO alerts (symbol, price, change, timestamp) VALUES (?, ?, ?, ?) `); stmt.run( alertData.symbol, alertData.price, alertData.change, Date.now() ); } ``` ```javascript theme={null} import express from 'express'; const app = express(); app.get('/alerts', (req, res) => { const alerts = getRecentAlerts(); res.json({ alerts }); }); app.post('/config', (req, res) => { // Update monitoring config updateConfig(req.body); res.json({ success: true }); }); app.listen(3000); ``` ```javascript theme={null} async function sendNotification(message, channels) { const tasks = []; if (channels.includes('telegram')) { tasks.push(sendTelegram(message)); } if (channels.includes('discord')) { tasks.push(sendDiscord(message)); } if (channels.includes('email')) { tasks.push(sendEmail(message)); } await Promise.all(tasks); } ``` *** ## FAQ 1. Check if Access Token is correct 2. Confirm network can access ChainStream 3. Check if firewall is blocking WebSocket 1. Confirm Bot Token is correct 2. Confirm Chat ID is correct 3. Make sure you've sent a message to the Bot (activate conversation) Add more configurations to the `WATCH_TOKENS` array in `config.js`. *** ## Related Documentation WebSocket subscription details Use Webhook instead of WebSocket # Integrate Deposit Risk Check Source: https://docs.chainstream.io/en/docs/tutorials/integrate-deposit-check Build an exchange deposit risk detection system using KYT API ## Project Overview This tutorial builds a deposit risk control system that automatically assesses fund source risk when users deposit. **Estimated Time**: 30 minutes\ **Difficulty Level**: ⭐⭐ Beginner **Features**: * Register deposit transactions for KYT analysis * Query transaction risk assessment results * Process deposits based on risk level *** ## How It Works ```mermaid theme={null} flowchart TD A[User Deposits] --> B[Register Transfer with KYT] B --> C[Get Transfer Summary] C --> D{Risk Level?} D -->|Low Risk| E[Approve Deposit] D -->|Medium Risk| F[Manual Review] D -->|High Risk| G[Reject Deposit] ``` *** ## Step 1: Register Deposit Transaction When a deposit is detected, register it with the KYT API for analysis. ```javascript theme={null} import { ChainStreamClient } from '@chainstream-io/sdk'; const client = new ChainStreamClient(process.env.CHAINSTREAM_ACCESS_TOKEN); async function registerDeposit(deposit) { // Register the transfer for KYT analysis const response = await client.kyt.registerTransfer({ network: deposit.network, // 'bitcoin', 'ethereum', 'Solana' asset: deposit.asset, // 'BTC', 'ETH', 'SOL' transferReference: deposit.txHash, // Transaction hash direction: 'received' // Deposit = received }); return response.transferId; } ``` *** ## Step 2: Get Risk Assessment After registration, query the transfer summary to get risk information. ```javascript theme={null} async function getTransferRisk(transferId) { // Get transfer summary with risk assessment const summary = await client.kyt.getTransferSummary(transferId); // Get detailed alerts if any const alerts = await client.kyt.getTransferAlerts(transferId); // Get direct exposure information const exposures = await client.kyt.getTransferDirectExposure(transferId); return { summary, alerts, exposures }; } ``` *** ## Step 3: Process Based on Risk Implement risk-based processing logic. ```javascript theme={null} async function evaluateDeposit(deposit) { // Register the deposit const transferId = await registerDeposit(deposit); // Get risk assessment const { summary, alerts, exposures } = await getTransferRisk(transferId); // Determine risk level based on alerts const hasHighRiskAlert = alerts.some( alert => alert.severity === 'high' || alert.severity === 'critical' ); const hasMediumRiskAlert = alerts.some( alert => alert.severity === 'medium' ); // Process based on risk if (hasHighRiskAlert) { return rejectDeposit(deposit, alerts); } if (hasMediumRiskAlert) { return queueForReview(deposit, alerts); } return approveDeposit(deposit); } function approveDeposit(deposit) { console.log(`✅ Deposit approved: ${deposit.txHash}`); // Credit user account return { status: 'approved', deposit }; } function queueForReview(deposit, alerts) { console.log(`⚠️ Deposit queued for review: ${deposit.txHash}`); // Notify compliance team return { status: 'pending_review', deposit, alerts }; } function rejectDeposit(deposit, alerts) { console.log(`❌ Deposit rejected: ${deposit.txHash}`); // Log and notify return { status: 'rejected', deposit, alerts }; } ``` *** ## Complete Example ```javascript theme={null} import { ChainStreamClient } from '@chainstream-io/sdk'; const client = new ChainStreamClient(process.env.CHAINSTREAM_ACCESS_TOKEN); class DepositRiskChecker { async checkDeposit(deposit) { try { // Step 1: Register transfer const { transferId } = await client.kyt.registerTransfer({ network: deposit.network, asset: deposit.asset, transferReference: deposit.txHash, direction: 'received' }); console.log(`📝 Registered transfer: ${transferId}`); // Step 2: Get risk assessment const summary = await client.kyt.getTransferSummary(transferId); const alerts = await client.kyt.getTransferAlerts(transferId); console.log(`📊 Risk assessment complete`); console.log(` Alerts: ${alerts.length}`); // Step 3: Make decision return this.makeDecision(deposit, summary, alerts); } catch (error) { console.error(`❌ Error checking deposit: ${error.message}`); // On error, queue for manual review return { status: 'pending_review', reason: 'system_error' }; } } makeDecision(deposit, summary, alerts) { const criticalAlerts = alerts.filter(a => a.severity === 'critical'); const highAlerts = alerts.filter(a => a.severity === 'high'); const mediumAlerts = alerts.filter(a => a.severity === 'medium'); if (criticalAlerts.length > 0 || highAlerts.length > 0) { return { status: 'rejected', reason: 'high_risk_detected', alerts: [...criticalAlerts, ...highAlerts] }; } if (mediumAlerts.length > 0) { return { status: 'pending_review', reason: 'medium_risk_detected', alerts: mediumAlerts }; } return { status: 'approved', reason: 'low_risk' }; } } // Usage const checker = new DepositRiskChecker(); const deposit = { network: 'Solana', asset: 'SOL', txHash: '39z5QAprVrzaFzfHu1JHPgBf9dSqYdNYhH31d3PEd4hWiWL1LML7qCct5MHGxaRAgjjj1nC3XUyLwtzGQmYqUk4y:address' }; const result = await checker.checkDeposit(deposit); console.log('Decision:', result); ``` *** ## API Reference | Endpoint | Description | | --------------------------------------------- | ------------------------------------ | | `POST /v1/kyt/transfer` | Register a transfer for KYT analysis | | `GET /v1/kyt/transfers/{id}/summary` | Get transfer summary | | `GET /v1/kyt/transfers/{id}/alerts` | Get transfer alerts | | `GET /v1/kyt/transfers/{id}/exposures/direct` | Get direct exposure info | *** ## Next Steps Learn KYT workings Complete API documentation # Smart Money Tracker Source: https://docs.chainstream.io/en/docs/tutorials/smart-money-tracker Track Smart Money addresses and get trading signals This tutorial introduces how to build a Smart Money tracking system that monitors smart money address trading behavior in real-time to obtain valuable market signals. **Estimated Time**: 45 minutes\ **Difficulty Level**: ⭐⭐⭐ Intermediate *** ## Objective Build a complete Smart Money tracking system: ```mermaid theme={null} flowchart TD A[Get SM List] --> B[Subscribe WebSocket] B --> C[Analyze & Notify] ``` **Feature Checklist**: * ✅ Get Smart Money list * ✅ Subscribe to SM trading stream * ✅ Trade parsing and pattern recognition * ✅ Signal notifications *** ## Methodology Review Before starting, we recommend reading [Smart Money Methodology](/en/docs/data-products/smart-money) to understand: * Definition and types of Smart Money * Scoring model (Smart Score) * Signal strength interpretation * Usage considerations *** ## Step 1: Get SM List ### API to Get Smart Money List ```python theme={null} # sm_client.py import requests from config import CHAINSTREAM_ACCESS_TOKEN, CHAINSTREAM_BASE_URL class SmartMoneyClient: def __init__(self): self.headers = {'Authorization': f'Bearer {CHAINSTREAM_ACCESS_TOKEN}'} def get_smart_money_list(self, chain: str = 'ethereum', limit: int = 100) -> list: """Get Smart Money list""" url = f"{CHAINSTREAM_BASE_URL}/discovery/smart-money" params = { 'chain': chain, 'limit': limit, 'min_score': 70, # Minimum Smart Score 'sort': 'score_desc' } response = requests.get(url, headers=self.headers, params=params) return response.json().get('wallets', []) # Response example: # [ # { # "address": "0xabc...", # "smart_score": 92, # "tags": ["whale", "defi_expert"], # "stats": { # "roi_90d": "45.2%", # "win_rate": "72%" # } # }, # ... # ] def get_wallet_activities(self, address: str, limit: int = 20) -> list: """Get wallet recent transactions""" url = f"{CHAINSTREAM_BASE_URL}/wallets/{address}/activities" params = {'limit': limit} response = requests.get(url, headers=self.headers, params=params) return response.json().get('activities', []) ``` ### Using Preset Lists ```python theme={null} # ChainStream provides preset SM lists PRESET_LISTS = { 'ethereum_top_100': 'eth_top_traders', 'solana_smart_money': 'sol_smart_money', 'base_early_adopters': 'base_early' } def get_preset_list(list_id: str) -> list: url = f"{CHAINSTREAM_BASE_URL}/discovery/lists/{list_id}" response = requests.get(url, headers=headers) return response.json().get('wallets', []) ``` *** ## Step 2: Subscribe to Trades ### WebSocket Subscription The WebSocket examples in this tutorial use simplified pseudo-code to illustrate the concept. For the actual WebSocket subscription format and available channels, see the [WebSocket API Reference](/en/api-reference/endpoint/websocket/api). ```python theme={null} # tracker.py import asyncio import json import websockets from config import CHAINSTREAM_ACCESS_TOKEN class SmartMoneyTracker: def __init__(self, wallets: list): self.wallets = wallets self.ws_url = 'wss://realtime-dex.chainstream.io/connection/websocket' self.ws = None async def connect(self): """Connect to WebSocket""" # Pass token via URL parameter ws_url = f"{self.ws_url}?token={CHAINSTREAM_ACCESS_TOKEN}" self.ws = await websockets.connect(ws_url) print("✅ WebSocket connected") async def subscribe(self): """Subscribe to Smart Money trades""" # Method 1: Subscribe to specific addresses for wallet in self.wallets[:50]: # Limit subscription count msg = { 'type': 'subscribe', 'channel': 'wallet_activity', 'params': { 'address': wallet['address'], 'events': ['swap', 'transfer'] } } await self.ws.send(json.dumps(msg)) # Method 2: Subscribe to Smart Money aggregated channel (recommended) msg = { 'type': 'subscribe', 'channel': 'smart_money', 'params': { 'chains': ['ethereum', 'arbitrum', 'base'], 'min_score': 70, 'min_value_usd': 10000 } } await self.ws.send(json.dumps(msg)) print("📡 Subscribed to Smart Money trading stream") async def listen(self, callback): """Listen to trading events""" async for message in self.ws: data = json.loads(message) if data.get('type') == 'smart_money_activity': await callback(data) async def run(self, callback): """Run tracker""" while True: try: await self.connect() await self.subscribe() await self.listen(callback) except websockets.ConnectionClosed: print("⚠️ Connection closed, reconnecting in 5s...") await asyncio.sleep(5) ``` ### Or Use Webhook ```python theme={null} # Create Webhook to subscribe to Smart Money activities webhook_config = { 'url': 'https://your-server.com/sm-webhook', 'events': ['smartmoney.buy', 'smartmoney.sell', 'smartmoney.new_token'], 'filters': { 'min_score': 70, 'min_value_usd': 10000, 'chains': ['ethereum', 'arbitrum'] } } ``` *** ## Step 3: Analysis and Notification ### Trade Parsing ```python theme={null} # analyzer.py from dataclasses import dataclass from typing import Optional @dataclass class SmartMoneySignal: wallet_address: str wallet_score: int wallet_tags: list action: str # buy, sell token_symbol: str token_address: str amount_usd: float price: float signal_strength: str # strong, medium, weak timestamp: str class SignalAnalyzer: def analyze(self, event: dict) -> Optional[SmartMoneySignal]: """Analyze trading event, generate signal""" wallet = event.get('wallet', {}) transaction = event.get('transaction', {}) # Calculate signal strength strength = self._calc_signal_strength(wallet, transaction) if strength == 'ignore': return None return SmartMoneySignal( wallet_address=wallet['address'], wallet_score=wallet.get('smart_score', 0), wallet_tags=wallet.get('tags', []), action=transaction.get('type', 'unknown'), token_symbol=transaction.get('token', {}).get('symbol', 'Unknown'), token_address=transaction.get('token', {}).get('address', ''), amount_usd=float(transaction.get('value_usd', 0)), price=float(transaction.get('price', 0)), signal_strength=strength, timestamp=event.get('timestamp', '') ) def _calc_signal_strength(self, wallet: dict, tx: dict) -> str: """Calculate signal strength""" score = wallet.get('smart_score', 0) value_usd = float(tx.get('value_usd', 0)) is_new_token = tx.get('is_first_buy', False) # Strong signal conditions if score >= 85 and value_usd >= 100000: return 'strong' if is_new_token and score >= 80: return 'strong' # Medium signal if score >= 70 and value_usd >= 50000: return 'medium' # Weak signal if score >= 60 and value_usd >= 10000: return 'weak' return 'ignore' ``` ### Notification Module ```python theme={null} # notifier.py import aiohttp from config import TELEGRAM_BOT_TOKEN, TELEGRAM_CHAT_ID class Notifier: async def send_signal(self, signal): """Send signal notification""" # Signal strength emoji strength_emoji = { 'strong': '🔴', 'medium': '🟡', 'weak': '🟢' } # Action emoji action_emoji = '📈' if signal.action == 'buy' else '📉' message = f""" {strength_emoji.get(signal.signal_strength, '⚪')} Smart Money Signal {action_emoji} **{signal.action.upper()}** {signal.token_symbol} 👤 Address: `{signal.wallet_address[:10]}...` ⭐ Smart Score: {signal.wallet_score} 🏷️ Tags: {', '.join(signal.wallet_tags)} 💰 Amount: ${signal.amount_usd:,.0f} 💵 Price: ${signal.price:.6f} ⏰ {signal.timestamp} """ await self._send_telegram(message) async def _send_telegram(self, message: str): """Send Telegram message""" url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendMessage" async with aiohttp.ClientSession() as session: await session.post(url, json={ 'chat_id': TELEGRAM_CHAT_ID, 'text': message, 'parse_mode': 'Markdown' }) ``` *** ## Complete Code ```python theme={null} # main.py import asyncio from sm_client import SmartMoneyClient from tracker import SmartMoneyTracker from analyzer import SignalAnalyzer from notifier import Notifier async def main(): # Initialize client = SmartMoneyClient() analyzer = SignalAnalyzer() notifier = Notifier() # Get Smart Money list print("📋 Getting Smart Money list...") wallets = client.get_smart_money_list(chain='ethereum', limit=100) print(f"✅ Got {len(wallets)} Smart Money addresses") # Define callback handler async def on_activity(event): signal = analyzer.analyze(event) if signal: print(f"🎯 {signal.signal_strength.upper()} | {signal.action} {signal.token_symbol} | ${signal.amount_usd:,.0f}") await notifier.send_signal(signal) # Start tracking tracker = SmartMoneyTracker(wallets) print("🚀 Starting Smart Money tracker...") await tracker.run(on_activity) if __name__ == '__main__': asyncio.run(main()) ``` *** ## Use Cases ### Copy-Trading Reference ```python theme={null} # Filter strong signals for reference def filter_strong_signals(signals: list) -> list: return [ s for s in signals if s.signal_strength == 'strong' and s.action == 'buy' ] ``` ### Market Sentiment Indicator ```python theme={null} # Calculate SM buy/sell ratio def calc_sentiment(signals: list, hours: int = 24) -> dict: recent = filter_recent(signals, hours) buys = sum(1 for s in recent if s.action == 'buy') sells = sum(1 for s in recent if s.action == 'sell') ratio = buys / max(sells, 1) return { 'buy_count': buys, 'sell_count': sells, 'ratio': ratio, 'sentiment': 'bullish' if ratio > 1.5 else 'bearish' if ratio < 0.7 else 'neutral' } ``` *** ## Important Notes **Important Reminders**: 1. **Don't blindly copy-trade** — SM signals are for reference only 2. **Mind the delay** — On-chain confirmation + analysis has latency 3. **Diversify attention** — Multiple SM resonance signals are more valuable 4. **Independent research** — Combine with fundamentals for judgment *** ## Related Documentation Understand SM scoring model Use Webhook instead of WebSocket # Authentication Source: https://docs.chainstream.io/en/api-reference/authentication/authenticate How to sign API requests with authentication ## Signing Requests ChainStream uses API keys to authenticate all API calls. The **Base API URL** will be one of the following depending on your workspace environment type: * Mainnet: `https://api.chainstream.io/` Each API request must include the following headers: * `Authorization` - This value should be set to `Bearer `. The access token is a Base64 encoded JSON Web Token (JWT). ## Generating JWT Token You can generate a JWT token using the following code. The `scope` parameter is optional and controls access permissions for specific API modules. ### Available Scopes The following scopes are currently supported: * `webhook.read` - Read access to Webhook API endpoints * `webhook.write` - Write access to Webhook API endpoints * `kyt.read` - Read access to KYT (Know Your Transaction) API endpoints * `kyt.write` - Write access to KYT API endpoints If no scope is specified, the token will have access to all general API endpoints. Scopes are only required when accessing protected Webhook or KYT endpoints. ### JavaScript **Example 1: Without scope (general API access)** ```javascript theme={null} import { AuthenticationClient } from 'auth0'; const auth0Client = new AuthenticationClient({ domain: `dex.asia.auth.chainstream.io`, clientId: 'your client id', clientSecret: 'your client secret' }); const response = await auth0Client.oauth.clientCredentialsGrant({ audience: 'https://api.dex.chainstream.io' }); return response.data.access_token; ``` **Example 2: With Webhook access** ```javascript theme={null} import { AuthenticationClient } from 'auth0'; const auth0Client = new AuthenticationClient({ domain: `dex.asia.auth.chainstream.io`, clientId: 'your client id', clientSecret: 'your client secret' }); const response = await auth0Client.oauth.clientCredentialsGrant({ audience: 'https://api.dex.chainstream.io', scope: 'webhook.read webhook.write' }); return response.data.access_token; ``` **Example 3: With KYT access** ```javascript theme={null} import { AuthenticationClient } from 'auth0'; const auth0Client = new AuthenticationClient({ domain: `dex.asia.auth.chainstream.io`, clientId: 'your client id', clientSecret: 'your client secret' }); const response = await auth0Client.oauth.clientCredentialsGrant({ audience: 'https://api.dex.chainstream.io', scope: 'kyt.read kyt.write' }); return response.data.access_token; ``` **Example 4: With multiple scopes** ```javascript theme={null} import { AuthenticationClient } from 'auth0'; const auth0Client = new AuthenticationClient({ domain: `dex.asia.auth.chainstream.io`, clientId: 'your client id', clientSecret: 'your client secret' }); const response = await auth0Client.oauth.clientCredentialsGrant({ audience: 'https://api.dex.chainstream.io', scope: 'webhook.read webhook.write kyt.read kyt.write' }); return response.data.access_token; ``` ## Using SDKs After generating the JWT token, you can use it to initialize the SDK: ### JavaScript SDK ```javascript theme={null} import { ChainStreamClient } from "@chainstream-io/sdk"; // jwtToken generated from previous step const dex = new ChainStreamClient("your-jwt-token"); ``` Make sure to replace the placeholder values with your actual API credentials. # Blockchain - Latest Block Source: https://docs.chainstream.io/en/api-reference/endpoint/data/blockchain/v2/blockchain-chain-latest_block-get /en/api-reference/openapi-data-en.yaml GET /v2/blockchain/{chain}/latest_block Get the latest block information for a specific blockchain # Blockchain - List Source: https://docs.chainstream.io/en/api-reference/endpoint/data/blockchain/v2/blockchain-get /en/api-reference/openapi-data-en.yaml GET /v2/blockchain Get list of supported blockchains # Dex - List Source: https://docs.chainstream.io/en/api-reference/endpoint/data/dex/v2/dex-get /en/api-reference/openapi-data-en.yaml GET /v2/dex Obtain information about all DEXs on a specified blockchain. # DexPool - Detail Source: https://docs.chainstream.io/en/api-reference/endpoint/data/dexpool/v2/dexpools-chain-pooladdress-get /en/api-reference/openapi-data-en.yaml GET /v2/dexpools/{chain}/{poolAddress} Retrieve detailed information about a specific DEX pool # DexPool - Liquidity Snapshots Source: https://docs.chainstream.io/en/api-reference/endpoint/data/dexpool/v2/dexpools-chain-pooladdress-snapshots-get /en/api-reference/openapi-data-en.yaml GET /v2/dexpools/{chain}/{poolAddress}/snapshots Retrieve historical liquidity snapshots for a specific pool. If a time parameter is provided, returns the nearest snapshot before or at that time. # KYT - Register Address Source: https://docs.chainstream.io/en/api-reference/endpoint/data/kyt/v2/kyt-address-post /en/api-reference/openapi-data-en.yaml POST /v2/kyt/address Register an address for KYT monitoring # KYT - Get Address Risk Source: https://docs.chainstream.io/en/api-reference/endpoint/data/kyt/v2/kyt-addresses-address-risk-get /en/api-reference/openapi-data-en.yaml GET /v2/kyt/addresses/{address}/risk Retrieve risk assessment for a registered address # KYT - Register Transfer Source: https://docs.chainstream.io/en/api-reference/endpoint/data/kyt/v2/kyt-transfer-post /en/api-reference/openapi-data-en.yaml POST /v2/kyt/transfer Register a transfer for KYT (Know Your Transaction) analysis # KYT - Get Transfer Alerts Source: https://docs.chainstream.io/en/api-reference/endpoint/data/kyt/v2/kyt-transfers-transferid-alerts-get /en/api-reference/openapi-data-en.yaml GET /v2/kyt/transfers/{transferId}/alerts Retrieve alerts associated with a transfer # KYT - Get Transfer Direct Exposure Source: https://docs.chainstream.io/en/api-reference/endpoint/data/kyt/v2/kyt-transfers-transferid-exposures-direct-get /en/api-reference/openapi-data-en.yaml GET /v2/kyt/transfers/{transferId}/exposures/direct Get direct exposure information for a transfer # KYT - Get Transfer Network Identifications Source: https://docs.chainstream.io/en/api-reference/endpoint/data/kyt/v2/kyt-transfers-transferid-network-identifications-get /en/api-reference/openapi-data-en.yaml GET /v2/kyt/transfers/{transferId}/network-identifications Get network identifications for a transfer # KYT - Get Transfer Summary Source: https://docs.chainstream.io/en/api-reference/endpoint/data/kyt/v2/kyt-transfers-transferid-summary-get /en/api-reference/openapi-data-en.yaml GET /v2/kyt/transfers/{transferId}/summary Retrieve summary information for a registered transfer # KYT - Register Withdrawal Source: https://docs.chainstream.io/en/api-reference/endpoint/data/kyt/v2/kyt-withdrawal-post /en/api-reference/openapi-data-en.yaml POST /v2/kyt/withdrawal Register a withdrawal for KYT (Know Your Transaction) analysis # KYT - Get Withdrawal Address Identifications Source: https://docs.chainstream.io/en/api-reference/endpoint/data/kyt/v2/kyt-withdrawal-withdrawalid-address-identifications-get /en/api-reference/openapi-data-en.yaml GET /v2/kyt/withdrawal/{withdrawalId}/address-identifications Get address identifications for a withdrawal # KYT - Get Withdrawal Alerts Source: https://docs.chainstream.io/en/api-reference/endpoint/data/kyt/v2/kyt-withdrawal-withdrawalid-alerts-get /en/api-reference/openapi-data-en.yaml GET /v2/kyt/withdrawal/{withdrawalId}/alerts Retrieve alerts associated with a withdrawal # KYT - Get Withdrawal Direct Exposure Source: https://docs.chainstream.io/en/api-reference/endpoint/data/kyt/v2/kyt-withdrawal-withdrawalid-exposures-direct-get /en/api-reference/openapi-data-en.yaml GET /v2/kyt/withdrawal/{withdrawalId}/exposures/direct Get direct exposure information for a withdrawal # KYT - Get Withdrawal Fraud Assessment Source: https://docs.chainstream.io/en/api-reference/endpoint/data/kyt/v2/kyt-withdrawal-withdrawalid-fraud-assessment-get /en/api-reference/openapi-data-en.yaml GET /v2/kyt/withdrawal/{withdrawalId}/fraud-assessment Get fraud assessment results for a withdrawal # KYT - Get Withdrawal Network Identifications Source: https://docs.chainstream.io/en/api-reference/endpoint/data/kyt/v2/kyt-withdrawal-withdrawalid-network-identifications-get /en/api-reference/openapi-data-en.yaml GET /v2/kyt/withdrawal/{withdrawalId}/network-identifications Get network identifications for a withdrawal # KYT - Get Withdrawal Summary Source: https://docs.chainstream.io/en/api-reference/endpoint/data/kyt/v2/kyt-withdrawal-withdrawalid-summary-get /en/api-reference/openapi-data-en.yaml GET /v2/kyt/withdrawal/{withdrawalId}/summary Retrieve summary information for a registered withdrawal # Ranking - FinalStretch Tokens Source: https://docs.chainstream.io/en/api-reference/endpoint/data/ranking/v2/ranking-chain-finalstretch-get /en/api-reference/openapi-data-en.yaml GET /v2/ranking/{chain}/finalStretch Return the finalStretch tokens # Ranking - Hot Tokens Source: https://docs.chainstream.io/en/api-reference/endpoint/data/ranking/v2/ranking-chain-hottokens-duration-get /en/api-reference/openapi-data-en.yaml GET /v2/ranking/{chain}/hotTokens/{duration} Retrieve a list of trending tokens Get trending/hot tokens ranked by trading activity over a specified duration. Available durations vary by chain. **Related**: MCP: `ranking_get_hot_tokens` # Ranking - Migrated Tokens Source: https://docs.chainstream.io/en/api-reference/endpoint/data/ranking/v2/ranking-chain-migrated-get /en/api-reference/openapi-data-en.yaml GET /v2/ranking/{chain}/migrated Return the migrated tokens # Ranking - New Tokens Source: https://docs.chainstream.io/en/api-reference/endpoint/data/ranking/v2/ranking-chain-newtokens-get /en/api-reference/openapi-data-en.yaml GET /v2/ranking/{chain}/newTokens Return the latest 100 tokens Get newly created tokens on a chain, sorted by creation time. Covers tokens from all supported launchpads including PumpFun and Raydium. **Related**: [Pump.fun Protocol Guide](/en/docs/recipes/pump-fun) | MCP: `ranking_get_new_tokens` # Ranking - Stocks Tokens Source: https://docs.chainstream.io/en/api-reference/endpoint/data/ranking/v2/ranking-chain-stocks-get /en/api-reference/openapi-data-en.yaml GET /v2/ranking/{chain}/stocks Return the stocks tokens # Token - Get Dev Tokens Source: https://docs.chainstream.io/en/api-reference/endpoint/data/token/v2/token-chain-dev-devaddress-tokens-get /en/api-reference/openapi-data-en.yaml GET /v2/token/{chain}/dev/{devAddress}/tokens Retrieve all tokens created by a specific developer address # Token - List (Filtered) Source: https://docs.chainstream.io/en/api-reference/endpoint/data/token/v2/token-chain-list-get /en/api-reference/openapi-data-en.yaml GET /v2/token/{chain}/list Get filtered token list with range conditions # Token - Market Data (Multi) Source: https://docs.chainstream.io/en/api-reference/endpoint/data/token/v2/token-chain-marketdata-multi-get /en/api-reference/openapi-data-en.yaml GET /v2/token/{chain}/marketData/multi Get market data for multiple tokens # Token - Metadata (Multi) Source: https://docs.chainstream.io/en/api-reference/endpoint/data/token/v2/token-chain-metadata-multi-get /en/api-reference/openapi-data-en.yaml GET /v2/token/{chain}/metadata/multi Get metadata for multiple tokens # Token - Detail (Multi) Source: https://docs.chainstream.io/en/api-reference/endpoint/data/token/v2/token-chain-multi-get /en/api-reference/openapi-data-en.yaml GET /v2/token/{chain}/multi Get detail of tokens # Pair - Candles Source: https://docs.chainstream.io/en/api-reference/endpoint/data/token/v2/token-chain-pair-pair-candles-get /en/api-reference/openapi-data-en.yaml GET /v2/token/{chain}/pair/{pair}/candles Get OHLCV candlestick data for a trading pair (format: TOKEN_A_ADDRESS-TOKEN_B_ADDRESS) # Pool - Candles Source: https://docs.chainstream.io/en/api-reference/endpoint/data/token/v2/token-chain-pool-pooladdress-candles-get /en/api-reference/openapi-data-en.yaml GET /v2/token/{chain}/pool/{poolAddress}/candles Get OHLCV candlestick data for a specific liquidity pool # Token - Stats (Multi) Source: https://docs.chainstream.io/en/api-reference/endpoint/data/token/v2/token-chain-stats-multi-get /en/api-reference/openapi-data-en.yaml GET /v2/token/{chain}/stats/multi Get statistics for multiple tokens # Token - Candles Source: https://docs.chainstream.io/en/api-reference/endpoint/data/token/v2/token-chain-tokenaddress-candles-get /en/api-reference/openapi-data-en.yaml GET /v2/token/{chain}/{tokenAddress}/candles Get token price candles Get OHLCV candlestick data at various resolutions (1m, 5m, 15m, 1h, 4h, 1d). Ideal for charting and technical analysis. **Related**: [GraphQL OHLC](/en/graphql/examples/ohlc-stats) | MCP: `token_get_candles` # Token - Creation Source: https://docs.chainstream.io/en/api-reference/endpoint/data/token/v2/token-chain-tokenaddress-creation-get /en/api-reference/openapi-data-en.yaml GET /v2/token/{chain}/{tokenAddress}/creation Get token creation information # Token - Detail Source: https://docs.chainstream.io/en/api-reference/endpoint/data/token/v2/token-chain-tokenaddress-get /en/api-reference/openapi-data-en.yaml GET /v2/token/{chain}/{tokenAddress} Get detail of token Returns comprehensive token information including metadata, stats, and market data. Use this as your primary token lookup endpoint. **Related**: GraphQL `TokenSearch` Cube | MCP: `token_get` # Token - Holders Source: https://docs.chainstream.io/en/api-reference/endpoint/data/token/v2/token-chain-tokenaddress-holders-get /en/api-reference/openapi-data-en.yaml GET /v2/token/{chain}/{tokenAddress}/holders Get holders of a token Get token holder list with balances. For the top holders only, use the `topHolders` endpoint instead. **Related**: [GraphQL Holders](/en/graphql/examples/balance-holders) | MCP: `token_get_holders` # Token - Holders (Multi) Source: https://docs.chainstream.io/en/api-reference/endpoint/data/token/v2/token-chain-tokenaddress-holders-multi-get /en/api-reference/openapi-data-en.yaml GET /v2/token/{chain}/{tokenAddress}/holders/multi Get holders information for multiple wallet addresses # Token - Liquidity Snapshots Source: https://docs.chainstream.io/en/api-reference/endpoint/data/token/v2/token-chain-tokenaddress-liquiditysnapshots-get /en/api-reference/openapi-data-en.yaml GET /v2/token/{chain}/{tokenAddress}/liquiditySnapshots Retrieve historical liquidity snapshots for a token. If a time parameter is provided, returns the nearest snapshot before or at that time. # Token - Market Cap Source: https://docs.chainstream.io/en/api-reference/endpoint/data/token/v2/token-chain-tokenaddress-marketdata-get /en/api-reference/openapi-data-en.yaml GET /v2/token/{chain}/{tokenAddress}/marketData Get the market cap of a token # Token - Metadata Source: https://docs.chainstream.io/en/api-reference/endpoint/data/token/v2/token-chain-tokenaddress-metadata-get /en/api-reference/openapi-data-en.yaml GET /v2/token/{chain}/{tokenAddress}/metadata Get metadata of token # Token - Mint and Burn Source: https://docs.chainstream.io/en/api-reference/endpoint/data/token/v2/token-chain-tokenaddress-mintandburn-get /en/api-reference/openapi-data-en.yaml GET /v2/token/{chain}/{tokenAddress}/mintAndBurn Get mint and burn information for a token # Token - Pools Source: https://docs.chainstream.io/en/api-reference/endpoint/data/token/v2/token-chain-tokenaddress-pools-get /en/api-reference/openapi-data-en.yaml GET /v2/token/{chain}/{tokenAddress}/pools Get all pools containing this token Get all liquidity pools containing this token across supported DEXes. Returns pool addresses, reserves, and liquidity in USD. **Related**: [GraphQL Pools](/en/graphql/examples/pools-liquidity) | MCP: `token_get_pools` # Token - Price by Time Source: https://docs.chainstream.io/en/api-reference/endpoint/data/token/v2/token-chain-tokenaddress-price-get /en/api-reference/openapi-data-en.yaml GET /v2/token/{chain}/{tokenAddress}/price Get token price at a specific timestamp Get the current price of a token in USD and native currency. For historical prices, use the `/prices` endpoint or GraphQL `DEXTrades` Cube. **Related**: [GraphQL DEX Trades](/en/graphql/examples/dex-trades) | MCP: `token_get_price` # Token - Prices Source: https://docs.chainstream.io/en/api-reference/endpoint/data/token/v2/token-chain-tokenaddress-prices-get /en/api-reference/openapi-data-en.yaml GET /v2/token/{chain}/{tokenAddress}/prices Get historical price data for a token # Token - Security Source: https://docs.chainstream.io/en/api-reference/endpoint/data/token/v2/token-chain-tokenaddress-security-get /en/api-reference/openapi-data-en.yaml GET /v2/token/{chain}/{tokenAddress}/security Get token security information # Token - Stats Source: https://docs.chainstream.io/en/api-reference/endpoint/data/token/v2/token-chain-tokenaddress-stats-get /en/api-reference/openapi-data-en.yaml GET /v2/token/{chain}/{tokenAddress}/stats Get token statistics Get aggregated trading statistics for a token including volume, trade count, unique traders, and price changes over various time windows. **Related**: [GraphQL OHLC & Stats](/en/graphql/examples/ohlc-stats) | MCP: `token_get_stats` # Token - Top Holders Source: https://docs.chainstream.io/en/api-reference/endpoint/data/token/v2/token-chain-tokenaddress-topholders-get /en/api-reference/openapi-data-en.yaml GET /v2/token/{chain}/{tokenAddress}/topHolders Get the top 20 holders for a token Get the top token holders ranked by balance. Useful for concentration analysis and whale tracking. **Related**: [GraphQL Holders](/en/graphql/examples/balance-holders) | MCP: `token_get_top_holders` # Token - Get Token Traders Source: https://docs.chainstream.io/en/api-reference/endpoint/data/token/v2/token-chain-tokenaddress-traders-tag-get /en/api-reference/openapi-data-en.yaml GET /v2/token/{chain}/{tokenAddress}/traders/{tag} Retrieve traders for a token by tag (fresh, sandwish, bundle, sniper, dev, pro, insider) # Token - Transfer Total Source: https://docs.chainstream.io/en/api-reference/endpoint/data/token/v2/token-chain-tokenaddress-transfer-total-get /en/api-reference/openapi-data-en.yaml GET /v2/token/{chain}/{tokenAddress}/transfer-total Get total count of transfers for a specific token with filters # Token - Transfer List Source: https://docs.chainstream.io/en/api-reference/endpoint/data/token/v2/token-chain-tokenaddress-transfers-get /en/api-reference/openapi-data-en.yaml GET /v2/token/{chain}/{tokenAddress}/transfers Get transfer history for a specific token # Token - Search Source: https://docs.chainstream.io/en/api-reference/endpoint/data/token/v2/token-search-get /en/api-reference/openapi-data-en.yaml GET /v2/token/search Search tokens by name, symbol or address Search tokens by name, symbol, or address across all supported chains. Supports fuzzy matching and pagination. **Related**: MCP: `token_search` # Activity - List Source: https://docs.chainstream.io/en/api-reference/endpoint/data/trade/v2/trade-chain-activities-get /en/api-reference/openapi-data-en.yaml GET /v2/trade/{chain}/activities Get token activities including trades, liquidity operations, and other token-related activities # Trade - List Source: https://docs.chainstream.io/en/api-reference/endpoint/data/trade/v2/trade-chain-get /en/api-reference/openapi-data-en.yaml GET /v2/trade/{chain} Retrieve a list of token transactions Get recent DEX trades on a chain. Filter by token address to see trades for a specific token. Returns buy/sell sides, amounts, prices, and DEX info. **Related**: [GraphQL DEX Trades](/en/graphql/examples/dex-trades) | MCP: `trade_get` # Trade - Top Traders Source: https://docs.chainstream.io/en/api-reference/endpoint/data/trade/v2/trade-chain-top-traders-get /en/api-reference/openapi-data-en.yaml GET /v2/trade/{chain}/top-traders Get top traders for a specific token Get top traders ranked by volume for a specific token. Useful for identifying whales and market makers. **Related**: [GraphQL DEX Trades](/en/graphql/examples/dex-trades) | MCP: `trade_get_top_traders` # Trader - Gainers/Losers Source: https://docs.chainstream.io/en/api-reference/endpoint/data/trade/v2/trade-chain-trader-gainers-losers-get /en/api-reference/openapi-data-en.yaml GET /v2/trade/{chain}/trader-gainers-losers Get top gainers or losers ranked by PnL # Wallet - First Tx Funded Source: https://docs.chainstream.io/en/api-reference/endpoint/data/wallet/v2/wallet-chain-first-tx-get /en/api-reference/openapi-data-en.yaml GET /v2/wallet/{chain}/first-tx Get the first funded transaction for one or more wallets # Wallet - Net Worth Summary (Multi) Source: https://docs.chainstream.io/en/api-reference/endpoint/data/wallet/v2/wallet-chain-net-worth-summary-get /en/api-reference/openapi-data-en.yaml GET /v2/wallet/{chain}/net-worth-summary Get current net worth summary for multiple wallets # Wallet - PnL By Wallet Source: https://docs.chainstream.io/en/api-reference/endpoint/data/wallet/v2/wallet-chain-pnl-by-wallet-get /en/api-reference/openapi-data-en.yaml GET /v2/wallet/{chain}/pnl-by-wallet Get PnL for a specific token across multiple wallets # Wallet - Balance Updates Source: https://docs.chainstream.io/en/api-reference/endpoint/data/wallet/v2/wallet-chain-walletaddress-balance-updates-get /en/api-reference/openapi-data-en.yaml GET /v2/wallet/{chain}/{walletAddress}/balance-updates Get wallet balance change history with filtering and pagination # Wallet - Calculate PNL Source: https://docs.chainstream.io/en/api-reference/endpoint/data/wallet/v2/wallet-chain-walletaddress-calculate-pnl-post /en/api-reference/openapi-data-en.yaml POST /v2/wallet/{chain}/{walletAddress}/calculate-pnl Calculate profit and loss for wallet tokens # Wallet - Net Worth Chart Source: https://docs.chainstream.io/en/api-reference/endpoint/data/wallet/v2/wallet-chain-walletaddress-net-worth-chart-get /en/api-reference/openapi-data-en.yaml GET /v2/wallet/{chain}/{walletAddress}/net-worth-chart Get historical net worth chart data for a wallet with hourly snapshots # Wallet - Net Worth Details Source: https://docs.chainstream.io/en/api-reference/endpoint/data/wallet/v2/wallet-chain-walletaddress-net-worth-details-get /en/api-reference/openapi-data-en.yaml GET /v2/wallet/{chain}/{walletAddress}/net-worth-details Get detailed net worth breakdown for a wallet, supporting both real-time and historical snapshots # Wallet - Net Worth Source: https://docs.chainstream.io/en/api-reference/endpoint/data/wallet/v2/wallet-chain-walletaddress-net-worth-get /en/api-reference/openapi-data-en.yaml GET /v2/wallet/{chain}/{walletAddress}/net-worth Get current net worth of a wallet including all token holdings with prices # Wallet - Net Worth By Tokens Source: https://docs.chainstream.io/en/api-reference/endpoint/data/wallet/v2/wallet-chain-walletaddress-net-worth-tokens-get /en/api-reference/openapi-data-en.yaml GET /v2/wallet/{chain}/{walletAddress}/net-worth/tokens Get net worth breakdown by tokens for a wallet # Wallet - PnL By Token Source: https://docs.chainstream.io/en/api-reference/endpoint/data/wallet/v2/wallet-chain-walletaddress-pnl-by-token-get /en/api-reference/openapi-data-en.yaml GET /v2/wallet/{chain}/{walletAddress}/pnl-by-token Get PnL for specific tokens in a wallet # Wallet - PnL Details Source: https://docs.chainstream.io/en/api-reference/endpoint/data/wallet/v2/wallet-chain-walletaddress-pnl-details-get /en/api-reference/openapi-data-en.yaml GET /v2/wallet/{chain}/{walletAddress}/pnl-details Get per-token PnL breakdown for a wallet # Wallet - PnL Summary Source: https://docs.chainstream.io/en/api-reference/endpoint/data/wallet/v2/wallet-chain-walletaddress-pnl-get /en/api-reference/openapi-data-en.yaml GET /v2/wallet/{chain}/{walletAddress}/pnl Get aggregated profit and loss summary for a wallet Get profit and loss summary for a wallet. Shows realized and unrealized PnL across all token positions. **Related**: [GraphQL Wallet PnL](/en/graphql/examples/balance-holders) | MCP: `wallet_get_pnl` # Wallet - Tokens Balance Source: https://docs.chainstream.io/en/api-reference/endpoint/data/wallet/v2/wallet-chain-walletaddress-tokens-balance-get /en/api-reference/openapi-data-en.yaml GET /v2/wallet/{chain}/{walletAddress}/tokens-balance Get token balances for a wallet with current prices Get all token balances for a wallet address. Returns token addresses, amounts, and USD values. **Related**: [GraphQL Balances](/en/graphql/examples/balance-holders) | MCP: `wallet_get_balance` # Wallet - Transfer Total Source: https://docs.chainstream.io/en/api-reference/endpoint/data/wallet/v2/wallet-chain-walletaddress-transfer-total-get /en/api-reference/openapi-data-en.yaml GET /v2/wallet/{chain}/{walletAddress}/transfer-total Get total count of transfers for a wallet with optional token filter # Wallet - Transfer List Source: https://docs.chainstream.io/en/api-reference/endpoint/data/wallet/v2/wallet-chain-walletaddress-transfers-get /en/api-reference/openapi-data-en.yaml GET /v2/wallet/{chain}/{walletAddress}/transfers Get transfer history for a wallet with optional token filter Get token transfer history for a wallet — both incoming and outgoing. Supports pagination and filtering by token. **Related**: [GraphQL Transfers](/en/graphql/examples/transfers) | MCP: `wallet_get_balance_updates` # Watchlist - Add Source: https://docs.chainstream.io/en/api-reference/endpoint/data/watchlist/v2/watchlist-chain-walletaddress-post /en/api-reference/openapi-data-en.yaml POST /v2/watchlist/{chain}/{walletAddress} Add the wallet address to the watchlist. Only the addresses in the watchlist have PNL data # Endpoint - List Source: https://docs.chainstream.io/en/api-reference/endpoint/data/webhook/v2/webhook-endpoint-get /en/api-reference/openapi-data-en.yaml GET /v2/webhook/endpoint Get list of webhook endpoints # Endpoint - Update Source: https://docs.chainstream.io/en/api-reference/endpoint/data/webhook/v2/webhook-endpoint-patch /en/api-reference/openapi-data-en.yaml PATCH /v2/webhook/endpoint Update webhook endpoint configuration # Endpoint - Create Source: https://docs.chainstream.io/en/api-reference/endpoint/data/webhook/v2/webhook-endpoint-post /en/api-reference/openapi-data-en.yaml POST /v2/webhook/endpoint Create a new webhook endpoint # Dex - Create Token Source: https://docs.chainstream.io/en/api-reference/endpoint/defi/dex/v2/dex-chain-create-post /en/api-reference/openapi-defi-en.yaml POST /v2/dex/{chain}/create Create a new token on the specified DEX # Dex - Quote Source: https://docs.chainstream.io/en/api-reference/endpoint/defi/dex/v2/dex-chain-quote-get /en/api-reference/openapi-defi-en.yaml GET /v2/dex/{chain}/quote Get DEX trading quote information # Dex - Route Source: https://docs.chainstream.io/en/api-reference/endpoint/defi/dex/v2/dex-chain-route-post /en/api-reference/openapi-defi-en.yaml POST /v2/dex/{chain}/route Calculate the best route for token swap considering price impact and fees. Returns the optimal path and a prepared transaction. # Dex - Swap Source: https://docs.chainstream.io/en/api-reference/endpoint/defi/dex/v2/dex-chain-swap-post /en/api-reference/openapi-defi-en.yaml POST /v2/dex/{chain}/swap Swap parameters including input token, output token, amount and slippage # Job - Get Source: https://docs.chainstream.io/en/api-reference/endpoint/defi/job/v2/job-id-get /en/api-reference/openapi-defi-en.yaml GET /v2/job/{id} Retrieve the current status and result of a job by its ID # Job - Streaming Source: https://docs.chainstream.io/en/api-reference/endpoint/defi/job/v2/job-id-streaming-get /en/api-reference/openapi-defi-en.yaml GET /v2/job/{id}/streaming Subscribe to real-time job status updates via Server-Sent Events (SSE). The connection will remain open until the job completes or an error occurs # Transaction - Estimate Gas Limit Source: https://docs.chainstream.io/en/api-reference/endpoint/defi/transaction/v2/transaction-chain-estimate-gas-limit-post /en/api-reference/openapi-defi-en.yaml POST /v2/transaction/{chain}/estimate-gas-limit Estimate the gas limit for an EVM transaction # Transaction - Gas Price Source: https://docs.chainstream.io/en/api-reference/endpoint/defi/transaction/v2/transaction-chain-gas-price-get /en/api-reference/openapi-defi-en.yaml GET /v2/transaction/{chain}/gas-price Get the current gas price for an EVM chain # Transaction - Send Source: https://docs.chainstream.io/en/api-reference/endpoint/defi/transaction/v2/transaction-chain-send-post /en/api-reference/openapi-defi-en.yaml POST /v2/transaction/{chain}/send Submit a signed transaction to the blockchain # API Reference Source: https://docs.chainstream.io/en/api-reference/overview Every programmatic surface ChainStream ships — REST, WebSocket, Kafka topics, CLI commands and MCP tools. This section is the authoritative list of endpoints, tools and channels. If you're new here, start with the [Quickstart](/en/docs/quickstart) or the [Access Methods overview](/en/docs/access-methods/overview); come back when you need exact field names, rate limits or schemas. ## Surfaces All data endpoints: tokens, trades, wallets, pools, smart money, search. OpenAPI-generated, with request/response examples per language. DEX aggregator endpoints: quote, route, swap, create token, transaction send. Real-time subscription channels for trades, prices, pools and smart-money flow. Per-chain topic catalog with Protobuf schemas and example consumer snippets. Full `chainstream` CLI reference — every command, flag and exit code. Full list of tools the ChainStream MCP Server exposes to AI agents. ## Authentication All REST and WebSocket requests require an API key, OAuth token, wallet-auth bearer or [x402 / MPP](/en/docs/platform/billing-payments/x402-payments) payment header. See [Authentication](/en/api-reference/authentication/authenticate) for the full matrix. ## Conventions * **Base URLs** — data and DeFi share `https://api.chainstream.io`; see each endpoint for path prefix. * **Rate limits** — per plan and per surface; response headers expose remaining budget. Full table in [Platform / Rate limits](/en/docs/platform/billing-payments/plans-and-units). * **Errors** — consistent JSON error envelope across all surfaces; see [Error handling](/en/docs/reference/error-codes). * **Versioning** — non-breaking changes roll out continuously; breaking changes are announced in the [Changelog](/en/changelog/index) with a deprecation window. ## Next Make your first authenticated call. Typed wrappers for TypeScript, Python, Go and Rust. # CLI Commands Reference Source: https://docs.chainstream.io/en/api-reference/cli-commands/overview Full list of chainstream CLI commands, flags and output formats. The `chainstream` CLI exposes every data product, GraphQL cube and DeFi primitive over a single binary. This page is the authoritative command reference — for narrative usage and installation see [Access Methods → CLI](/en/docs/access-methods/cli). ## Install ```bash theme={null} # Global install (recommended for interactive use) npm install -g @chainstream-io/cli # Zero-install, always-latest (recommended for agents and CI) npx @chainstream-io/cli ``` Either invocation works everywhere below. The short form `chainstream ` is used throughout this reference and is equivalent to `npx @chainstream-io/cli `. ## Global flags | Flag | Purpose | | ----------- | ------------------------------------------------------------------------------ | | `--version` | Print the CLI version and exit | | `--json` | Emit single-line machine-readable JSON (default output is pretty-printed JSON) | | `--help` | Print help for the current command or group | ## Environment variables | Variable | Purpose | Default | | ------------------------- | ---------------------------------------------- | ---------------------------------------- | | `CHAINSTREAM_API_KEY` | API key used in lieu of `config.json` | unset | | `CHAINSTREAM_API_URL` | Override REST base URL | `https://api.chainstream.io` | | `CHAINSTREAM_AUTH_URL` | Override Auth service URL | production default | | `CHAINSTREAM_GRAPHQL_URL` | Override GraphQL endpoint | `https://graphql.chainstream.io/graphql` | | `SOLANA_RPC_URL` | Override Solana RPC for wallet / balance reads | public RPC | | `BASE_RPC_URL` | Override Base RPC | public RPC | Config is persisted to `~/.config/chainstream/config.json`; P-256 wallet keys live in `~/.config/chainstream/keys/`. `chainstream logout` clears the wallet config but preserves the keys. ## Authentication commands (top-level) These commands are registered at the program root (no sub-group). | Command | Purpose | Arguments / Options | | ------------------- | -------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | | `login` | Create a TEE-backed wallet (default) or start an email OTP flow. Auto-grants the **nano trial** (50K CU, 30 days) on first login | `[email]`; `--key`; `--email` | | `verify` | Complete an email OTP login started by `login --email` | `--otp-id`; `--code`; `--email` | | `logout` | Clear the session (keeps keys on disk) | — | | `bind-email` | Bind an email to an existing wallet | `[email]` | | `bind-email-verify` | Finish the email-bind OTP flow (non-interactive) | `--otp-id`; `--code`; `--email` | ## `token` — Token information and analytics | Subcommand | Purpose | Options | | ---------- | ------------------------------------------------------------------ | ------------------------------------------------------------------- | | `search` | Search tokens by keyword | `--keyword` (required); `--chain` (required); `--limit` | | `info` | Get full token detail | `--chain`; `--address` | | `security` | Security report (honeypot, mint authority, freeze authority, etc.) | `--chain`; `--address` | | `holders` | Top token holders | `--chain`; `--address`; `--limit` | | `candles` | OHLCV candlesticks | `--chain`; `--address`; `--resolution`; `--from`; `--to`; `--limit` | | `pools` | Liquidity pools for a token | `--chain`; `--address` | ## `market` — Market data and discovery | Subcommand | Purpose | Options | | ---------- | --------------------------------------------- | ---------------------------------- | | `trending` | Hot / trending tokens by window | `--chain`; `--duration`; `--limit` | | `new` | Newly created tokens | `--chain`; `--limit` | | `trades` | Recent trades, optionally filtered to a token | `--chain`; `--token`; `--limit` | ## `wallet` — Wallet analytics, management, and signing | Subcommand | Purpose | Options | | ---------- | ----------------------------------------------------- | --------------------------------- | | `sign` | Sign a serialized transaction with the on-host wallet | `--chain`; `--tx` | | `profile` | PnL + net worth + top holdings in one call | `--chain`; `--address` | | `pnl` | PnL detail | `--chain`; `--address` | | `holdings` | Token balances | `--chain`; `--address`; `--limit` | | `activity` | Transfer history | `--chain`; `--address`; `--limit` | | `address` | Show current wallet addresses | — | | `balance` | Native + USDC balance (single request) | `--chain` (`sol` \| `base`) | | `set-raw` | Import a raw private key (dev / testing only) | `--chain` (`base` \| `sol`) | | `link` | Link a wallet address to your subscription | `--chain` (`evm` \| `solana`) | | `pricing` | List available x402 plans and prices | — | ## `dex` — DEX route, swap, and token creation All commands return **unsigned** transactions built server-side; signing happens on the host wallet. | Subcommand | Purpose | Options | | ---------- | -------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `route` | Aggregated route + unsigned swap transaction | `--chain`; `--from`; `--input-token`; `--output-token`; `--amount`; `--slippage`; `--dex`; `--recipient`; `--anti-mev`; `--gas-price`; `--gas-limit`; `--max-fee-per-gas`; `--max-priority-fee-per-gas` | | `swap` | Unsigned swap transaction (direct, no aggregation) | `--chain`; `--from`; `--input-token`; `--output-token`; `--amount`; `--slippage`; `--dex` | | `create` | Unsigned launchpad token creation transaction | `--chain`; `--from`; `--name`; `--symbol`; `--dex`; `--uri`; `--image` | ## `tx` — Broadcast and gas | Subcommand | Purpose | Options | | -------------- | ---------------------------------- | ------------------------------------------------------- | | `send` | Broadcast a signed transaction | `--chain`; `--signed-tx`; `--submit-type`; `--anti-mev` | | `gas-price` | Current gas price (EVM only) | `--chain` (`eth` \| `bsc`) | | `estimate-gas` | Estimate gas limit for an EVM call | `--chain`; `--from`; `--to`; `--data`; `--value` | ## `job` — Async job polling | Subcommand | Purpose | Options | | ---------- | -------------------------------------- | ----------------------------- | | `status` | Check the status of a long-running job | `--id`; `--wait`; `--timeout` | ## `graphql` — GraphQL schema and queries See the full usage guide in [Access Methods → CLI → GraphQL subcommand](/en/docs/access-methods/cli#graphql-subcommand) and the Agent Skill at [chainstream-graphql](/en/docs/ai-agents/agent-skills/chainstream-graphql). | Subcommand | Purpose | Options | | ---------- | -------------------------------------- | --------------------------------------------------- | | `schema` | Discover schema (cubes, types, fields) | `--summary`; `--type `; `--full`; `--refresh` | | `query` | Execute a GraphQL query | `--query `; `--file `; `--var ` | ## `plan` — Subscription and x402 auto-pay | Subcommand | Purpose | Options | | ---------- | --------------------------------------------------------------------------------- | ---------------------- | | `status` | Current plan, remaining quota and usage | `--chain`; `--address` | | `purchase` | Purchase a plan via x402 / MPP (auto-saves the returned API key to `config.json`) | `--plan` | ## `config` — Local configuration | Subcommand | Purpose | Options | | ---------- | ---------------------------------- | ----------------------------------------------------------- | | `set` | Set a configuration value | `--key` (`apiKey` \| `baseUrl` \| `walletChain`); `--value` | | `get` | Show current configuration | `--key` (optional) | | `auth` | Show current authentication status | — | ## Exit behaviour * `0` — success (or empty result) * `1` — user-facing error with JSON payload on stdout (unless `--json` is off, in which case a formatted error is printed) * Non-zero exit on auth failure (`401`), payment-required (`402`), or network error On 402 from any data/GraphQL command, the CLI prints a pointer to `wallet pricing` and `plan purchase`. `plan purchase` itself handles x402 auto-pay transparently. ## Next Narrative usage: install, auth, first commands, GraphQL subcommand. How AI agents should drive the CLI. How `plan purchase` and on-the-fly 402 handling work. Endpoint, schema and authentication for the GraphQL surface. # IPFS - Presign Source: https://docs.chainstream.io/en/api-reference/endpoint/data/ipfs/v2/ipfs-presign-post /en/api-reference/openapi-data-en.yaml POST /v2/ipfs/presign Create a Presign URL for IPFS content # RedPacket - Claim Source: https://docs.chainstream.io/en/api-reference/endpoint/data/redpacket/v2/redpacket-chain-claim-post /en/api-reference/openapi-data-en.yaml POST /v2/redpacket/{chain}/claim Claim tokens from an existing red packet # RedPacket - Create Source: https://docs.chainstream.io/en/api-reference/endpoint/data/redpacket/v2/redpacket-chain-create-post /en/api-reference/openapi-data-en.yaml POST /v2/redpacket/{chain}/create Create a new red packet with specified amount and quantity # RedPacket - Send Source: https://docs.chainstream.io/en/api-reference/endpoint/data/redpacket/v2/redpacket-chain-send-post /en/api-reference/openapi-data-en.yaml POST /v2/redpacket/{chain}/send Transactions related to redpacket # RedPacket - GetRedpackets Source: https://docs.chainstream.io/en/api-reference/endpoint/data/redpacket/v2/redpacket-get /en/api-reference/openapi-data-en.yaml GET /v2/redpacket Get the redpackets list # RedPacket - GetClaims Source: https://docs.chainstream.io/en/api-reference/endpoint/data/redpacket/v2/redpacket-id-claims-get /en/api-reference/openapi-data-en.yaml GET /v2/redpacket/{id}/claims Check the record of redpacket collection # RedPacket - Get Source: https://docs.chainstream.io/en/api-reference/endpoint/data/redpacket/v2/redpacket-id-get /en/api-reference/openapi-data-en.yaml GET /v2/redpacket/{id} Query redpacket information # RedPacket - GetClaimsByAddress Source: https://docs.chainstream.io/en/api-reference/endpoint/data/redpacket/v2/redpacket-wallet-address-claims-get /en/api-reference/openapi-data-en.yaml GET /v2/redpacket/wallet/{address}/claims Check the record of redpacket collection by the claimer address # RedPacket - GetRedpacketsByAddress Source: https://docs.chainstream.io/en/api-reference/endpoint/data/redpacket/v2/redpacket-wallet-address-redpackets-get /en/api-reference/openapi-data-en.yaml GET /v2/redpacket/wallet/{address}/redpackets Get the redpackets list by the creator address # Endpoint - Delete Source: https://docs.chainstream.io/en/api-reference/endpoint/data/webhook/v2/webhook-endpoint-id-delete /en/api-reference/openapi-data-en.yaml DELETE /v2/webhook/endpoint/{id} Delete a webhook endpoint # Endpoint - Get Source: https://docs.chainstream.io/en/api-reference/endpoint/data/webhook/v2/webhook-endpoint-id-get /en/api-reference/openapi-data-en.yaml GET /v2/webhook/endpoint/{id} Get webhook endpoint details # Endpoint - Get Secret Source: https://docs.chainstream.io/en/api-reference/endpoint/data/webhook/v2/webhook-endpoint-id-secret-get /en/api-reference/openapi-data-en.yaml GET /v2/webhook/endpoint/{id}/secret Get webhook endpoint secret # Endpoint - Rotate Secret Source: https://docs.chainstream.io/en/api-reference/endpoint/data/webhook/v2/webhook-endpoint-id-secret-rotate-post /en/api-reference/openapi-data-en.yaml POST /v2/webhook/endpoint/{id}/secret/rotate Rotate the secret key for a webhook endpoint # WebSocket API Source: https://docs.chainstream.io/en/api-reference/endpoint/websocket/api WebSocket API Real-time Data Subscription Service ## Overview ChainStream DEX WebSocket API provides real-time data subscription services, supporting the following data types: * Candle Data * Token Series * Wallet Series * Ranking Series * Trade Series * DexPool Series **Base URL** ```bash theme={null} wss://realtime-dex.chainstream.io/connection/websocket ``` ## Quick Start ### 1. Establish Connection First, create a WebSocket connection. WebSocket connections require the `token` query parameter in the URL for authentication. If using the Go or JavaScript SDK, authentication is handled automatically: ```typescript theme={null} import { ChainStreamClient } from '@chainstream-io/sdk'; import { Resolution } from '@chainstream-io/sdk/openapi'; const client = new ChainStreamClient('YOUR_ACCESS_TOKEN'); // Just subscribe directly, SDK handles WebSocket connection and authentication automatically client.stream.subscribeTokenCandles({ chain: 'sol', tokenAddress: '6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN', resolution: Resolution._1m, callback: (data) => { console.log('Received data:', data); } }); ``` When calling `subscribeXXX` methods, SDK automatically checks connection status and establishes connection if not connected. No need to manually call `connect()`. SDK Installation: * **TypeScript/JavaScript**: `npm install @chainstream-io/sdk` ([npm](https://www.npmjs.com/package/@chainstream-io/sdk)) * **Python**: `pip install chainstream-sdk` ([PyPI](https://pypi.org/project/chainstream-sdk)) * **Go**: `go get github.com/chainstream-io/chainstream-go-sdk` ([GitHub](https://github.com/chainstream-io/chainstream-go-sdk)) * **Rust**: Add `chainstream-sdk` to your `Cargo.toml` ([crates.io](https://crates.io/crates/chainstream-sdk)) When using browser native WebSocket or other WebSocket libraries, append the `token` parameter to the URL: ```typescript theme={null} // Works in both browser and Node.js const token = 'YOUR_ACCESS_TOKEN'; const ws = new WebSocket( `wss://realtime-dex.chainstream.io/connection/websocket?token=${token}` ); ws.onopen = () => { console.log('Connection established'); }; ws.onmessage = (event) => { const data = JSON.parse(event.data); console.log('Received data:', data); }; ``` By passing the token via URL parameter, both browser native WebSocket and various third-party libraries can be used without special header handling. Using `wscat` for testing: ```bash theme={null} $ wscat -c "wss://realtime-dex.chainstream.io/connection/websocket?token=YOUR_ACCESS_TOKEN" ``` ### 2. Subscribe to Data Choose the data type you want to subscribe to: ```typescript theme={null} // Example of subscribing to candle data ws.send(JSON.stringify({ type: "subscribe", channel: "dex-candle:sol_6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN_1m" })); ``` ### 3. Handle Data ```typescript theme={null} ws.onmessage = (event) => { const data = JSON.parse(event.data); console.log('Received data:', data); }; ``` ## Data Subscriptions ### Candles #### Candles Data Get real-time price movement data for tokens. **Subscription Format** ```text theme={null} dex-candle:{chain}_{tokenAddress}_{resolution} ``` **Parameters** Blockchain name, e.g., sol Token contract address, e.g., 6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN Candle period, supports: 1m, 5m, 15m, 1h, 4h, 1d Optional filter condition using Google Common Expression Language (CEL) syntax. Example: volume > 1000 **Response Data Format** WebSocket API returns shortened field names to optimize transmission efficiency, while SDK returns full field names to improve code readability. ```typescript theme={null} { "o": number, // Open price "c": number, // Close price "h": number, // High price "l": number, // Low price "v": number, // Volume "r": string, // Resolution "t": number // Timestamp } ``` ```typescript theme={null} { "open": number, // Open price "close": number, // Close price "high": number, // High price "low": number, // Low price "volume": number, // Volume "resolution": string, // Resolution "time": number // Timestamp } ``` ### Token Series #### Token Stats Get real-time market statistics for tokens. **Subscription Format** ```text theme={null} dex-token-stats:{chain}_{tokenAddress} ``` **Parameters** Blockchain name, e.g., sol Token contract address, e.g., 6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN Optional filter condition using Google Common Expression Language (CEL) syntax. Example: price > 0.01 **Response Data Format** WebSocket API returns shortened field names to optimize transmission efficiency, while SDK returns full field names to improve code readability. ```typescript theme={null} { "a": string, // Token address "t": number, // Timestamp "b1m": number, // Buys in 1m "s1m": number, // Sells in 1m "be1m": number, // Buyers in 1m "se1m": number, // Sellers in 1m "bviu1m": number, // Buy volume in USD 1m "sviu1m": number, // Sell volume in USD 1m "p1m": number, // Price 1m "oiu1m": number, // Open price in USD 1m "ciu1m": number, // Close price in USD 1m "b5m": number, // Buys in 5m "s5m": number, // Sells in 5m "be5m": number, // Buyers in 5m "se5m": number, // Sellers in 5m "bviu5m": number, // Buy volume in USD 5m "sviu5m": number, // Sell volume in USD 5m "p5m": number, // Price 5m "oiu5m": number, // Open price in USD 5m "ciu5m": number, // Close price in USD 5m "b15m": number, // Buys in 15m "s15m": number, // Sells in 15m "be15m": number, // Buyers in 15m "se15m": number, // Sellers in 15m "bviu15m": number,// Buy volume in USD 15m "sviu15m": number,// Sell volume in USD 15m "p15m": number, // Price 15m "oiu15m": number, // Open price in USD 15m "ciu15m": number, // Close price in USD 15m "b30m": number, // Buys in 30m "s30m": number, // Sells in 30m "be30m": number, // Buyers in 30m "se30m": number, // Sellers in 30m "bviu30m": number,// Buy volume in USD 30m "sviu30m": number,// Sell volume in USD 30m "p30m": number, // Price 30m "oiu30m": number, // Open price in USD 30m "ciu30m": number, // Close price in USD 30m "b1h": number, // Buys in 1h "s1h": number, // Sells in 1h "be1h": number, // Buyers in 1h "se1h": number, // Sellers in 1h "bviu1h": number, // Buy volume in USD 1h "sviu1h": number, // Sell volume in USD 1h "p1h": number, // Price 1h "oiu1h": number, // Open price in USD 1h "ciu1h": number, // Close price in USD 1h "b4h": number, // Buys in 4h "s4h": number, // Sells in 4h "be4h": number, // Buyers in 4h "se4h": number, // Sellers in 4h "bviu4h": number, // Buy volume in USD 4h "sviu4h": number, // Sell volume in USD 4h "p4h": number, // Price 4h "oiu4h": number, // Open price in USD 4h "ciu4h": number, // Close price in USD 4h "b24h": number, // Buys in 24h "s24h": number, // Sells in 24h "be24h": number, // Buyers in 24h "se24h": number, // Sellers in 24h "bviu24h": number,// Buy volume in USD 24h "sviu24h": number,// Sell volume in USD 24h "p24h": number, // Price 24h "oiu24h": number, // Open price in USD 24h "ciu24h": number, // Close price in USD 24h "p": number // Current price } ``` ```typescript theme={null} { "address": string, // Token address "timestamp": number, // Timestamp "buys1m": number, // Buys in 1m "sells1m": number, // Sells in 1m "buyers1m": number, // Buyers in 1m "sellers1m": number, // Sellers in 1m "buyVolumeInUsd1m": number, // Buy volume in USD 1m "sellVolumeInUsd1m": number,// Sell volume in USD 1m "price1m": number, // Price 1m "openInUsd1m": number, // Open price in USD 1m "closeInUsd1m": number, // Close price in USD 1m "buys5m": number, // Buys in 5m "sells5m": number, // Sells in 5m "buyers5m": number, // Buyers in 5m "sellers5m": number, // Sellers in 5m "buyVolumeInUsd5m": number, // Buy volume in USD 5m "sellVolumeInUsd5m": number,// Sell volume in USD 5m "price5m": number, // Price 5m "openInUsd5m": number, // Open price in USD 5m "closeInUsd5m": number, // Close price in USD 5m "buys15m": number, // Buys in 15m "sells15m": number, // Sells in 15m "buyers15m": number, // Buyers in 15m "sellers15m": number, // Sellers in 15m "buyVolumeInUsd15m": number,// Buy volume in USD 15m "sellVolumeInUsd15m": number,// Sell volume in USD 15m "price15m": number, // Price 15m "openInUsd15m": number, // Open price in USD 15m "closeInUsd15m": number, // Close price in USD 15m "buys30m": number, // Buys in 30m "sells30m": number, // Sells in 30m "buyers30m": number, // Buyers in 30m "sellers30m": number, // Sellers in 30m "buyVolumeInUsd30m": number,// Buy volume in USD 30m "sellVolumeInUsd30m": number,// Sell volume in USD 30m "price30m": number, // Price 30m "openInUsd30m": number, // Open price in USD 30m "closeInUsd30m": number, // Close price in USD 30m "buys1h": number, // Buys in 1h "sells1h": number, // Sells in 1h "buyers1h": number, // Buyers in 1h "sellers1h": number, // Sellers in 1h "buyVolumeInUsd1h": number, // Buy volume in USD 1h "sellVolumeInUsd1h": number,// Sell volume in USD 1h "price1h": number, // Price 1h "openInUsd1h": number, // Open price in USD 1h "closeInUsd1h": number, // Close price in USD 1h "buys4h": number, // Buys in 4h "sells4h": number, // Sells in 4h "buyers4h": number, // Buyers in 4h "sellers4h": number, // Sellers in 4h "buyVolumeInUsd4h": number, // Buy volume in USD 4h "sellVolumeInUsd4h": number,// Sell volume in USD 4h "price4h": number, // Price 4h "openInUsd4h": number, // Open price in USD 4h "closeInUsd4h": number, // Close price in USD 4h "buys24h": number, // Buys in 24h "sells24h": number, // Sells in 24h "buyers24h": number, // Buyers in 24h "sellers24h": number, // Sellers in 24h "buyVolumeInUsd24h": number,// Buy volume in USD 24h "sellVolumeInUsd24h": number,// Sell volume in USD 24h "price24h": number, // Price 24h "openInUsd24h": number, // Open price in USD 24h "closeInUsd24h": number, // Close price in USD 24h "price": number // Current price } ``` #### Token Holders Statistics Get real-time token holder statistics. **Subscription Format** ```text theme={null} dex-token-holding:{chain}_{tokenAddress} ``` **Parameters** Blockchain name, e.g., sol Token contract address, e.g., 6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN Optional filter condition using Google Common Expression Language (CEL) syntax. Example: holders > 200 **Response Data Format** WebSocket API returns shortened field names to optimize transmission efficiency, while SDK returns full field names to improve code readability. ```typescript theme={null} { "a": string, // Token address "h": number, // Number of holders "t100a": number, // Top 100 holders total amount "t10a": number, // Top 10 holders total amount "t100h": number, // Top 100 holders count "t10h": number, // Top 10 holders count "t100r": number, // Top 100 holders ratio "t10r": number, // Top 10 holders ratio "ch": number, // Creators holders count "ca": number, // Creators amount "cr": number, // Creators ratio "ts": number // Timestamp } ``` ```typescript theme={null} { "tokenAddress": string, // Token address "holders": number, // Number of holders "top100Amount": number, // Top 100 holders total amount "top10Amount": number, // Top 10 holders total amount "top100Holders": number, // Top 100 holders count "top10Holders": number, // Top 10 holders count "top100Ratio": number, // Top 100 holders ratio "top10Ratio": number, // Top 10 holders ratio "creatorsHolders": number, // Creators holders count "creatorsAmount": number, // Creators amount "creatorsRatio": number, // Creators ratio "timestamp": number // Timestamp } ``` #### New Token Metadata Get real-time metadata for newly listed tokens. **Subscription Format** ```text theme={null} dex-new-tokens-metadata:{chain} ``` **Parameters** Blockchain name, e.g., sol Optional filter condition using Google Common Expression Language (CEL) syntax. Example: name == "USDC" **Response Data Format** WebSocket API returns shortened field names to optimize transmission efficiency, while SDK returns full field names to improve code readability. ```typescript theme={null} [ { "a": string, // Token address "n": string, // Name "s": string, // Symbol "iu": string, // Image URL "de": string, // Description "sm": { // Social media "tw": string, // Twitter "tg": string, // Telegram "w": string, // Website "tt": string, // TikTok "dc": string, // Discord "fb": string, // Facebook "gh": string, // GitHub "ig": string, // Instagram "li": string, // LinkedIn "md": string, // Medium "rd": string, // Reddit "yt": string, // YouTube "bb": string // BitBucket }, "cts": number // Created timestamp (ms) } ] ``` ```typescript theme={null} [ { "tokenAddress": string, // Token address "name": string, // Name "symbol": string, // Symbol "imageUrl": string, // Image URL "description": string, // Description "socialMedia": { // Social media "twitter": string, // Twitter "telegram": string, // Telegram "website": string, // Website "tiktok": string, // TikTok "discord": string, // Discord "facebook": string, // Facebook "github": string, // GitHub "instagram": string, // Instagram "linkedin": string, // LinkedIn "medium": string, // Medium "reddit": string, // Reddit "youtube": string, // YouTube "bitbucket": string // BitBucket }, "createdAtMs": number // Created timestamp (ms) } ] ``` #### New Token Get information about newly created token. **Subscription Format** ```text theme={null} dex-new-token:{chain} ``` **Parameters** Blockchain name, e.g., sol **Response Data Format** WebSocket API returns shortened field names to optimize transmission efficiency, while SDK returns full field names to improve code readability. ```typescript theme={null} { "a": string, // Token address "n": string, // Name "s": string, // Symbol "dec": number, // Decimals "cts": number, // Created timestamp (ms) "lf": { // Launch from information "pa": string, // Program address "pf": string, // Protocol family "pn": string // Protocol name } } ``` ```typescript theme={null} { "tokenAddress": string, // Token address "name": string, // Name "symbol": string, // Symbol "decimals": number, // Decimals "createdAtMs": number, // Created timestamp (ms) "launchFrom": { // Launch from information "programAddress": string, // Program address "protocolFamily": string, // Protocol family "protocolName": string // Protocol name } } ``` #### Token Supply Get real-time token supply and market cap information. **Subscription Format** ```text theme={null} dex-token-supply:{chain}_{tokenAddress} ``` **Parameters** Blockchain name, e.g., sol Token contract address, e.g., 6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN Optional filter condition using Google Common Expression Language (CEL) syntax. Example: supply > 1000000 **Response Data Format** WebSocket API returns shortened field names to optimize transmission efficiency, while SDK returns full field names for better code readability. ```typescript theme={null} { "a": string, // Token address "s": number, // Supply "mc": number, // Market cap in USD "ts": number // Timestamp } ``` ```typescript theme={null} { "tokenAddress": string, // Token address "supply": number, // Supply "marketCapInUsd": number, // Market cap in USD "timestamp": number // Timestamp } ``` #### Token Liquidity Get real-time token liquidity statistics. **Subscription Format** ```text theme={null} dex-token-general-stat-num:{chain}_{tokenAddress} ``` **Parameters** Blockchain name, e.g., sol Token contract address Optional filter condition using Google Common Expression Language (CEL) syntax. Example: value > 1000000 **Response Data Format** WebSocket API returns shortened field names to optimize transmission efficiency, while SDK returns full field names for better code readability. ```typescript theme={null} { "a": string, // Token address "t": string, // Metric type "v": number, // Value "ts": number // Timestamp } ``` ```typescript theme={null} { "tokenAddress": string, // Token address "metricType": string, // Metric type "value": number, // Value "timestamp": number // Timestamp } ``` #### Token Max Liquidity Get real-time max liquidity info of a token in a single pool. **Subscription Format** ```text theme={null} dex-token-liquidity:{chain}_{tokenAddress} ``` **Parameters** Blockchain name, e.g., sol Token contract address Optional filter condition using Google Common Expression Language (CEL) syntax. Example: liquidityInUsd > 10000 **Response Data Format** WebSocket API returns shortened field names to optimize transmission efficiency, while SDK returns full field names for better code readability. ```typescript theme={null} { "a": string, // Token address "p": string, // Pool address "liu": string, // Liquidity in USD "lin": string, // Liquidity in native token "ts": number // Timestamp } ``` ```typescript theme={null} { "tokenAddress": string, // Token address "poolAddress": string, // Pool address "liquidityInUsd": string, // Liquidity in USD "liquidityInNative": string, // Liquidity in native token "timestamp": number // Timestamp } ``` #### Token Total Liquidity Get real-time total liquidity info of a token across all pools. **Subscription Format** ```text theme={null} dex-token-total-liquidity:{chain}_{tokenAddress} ``` **Parameters** Blockchain name, e.g., sol Token contract address Optional filter condition using Google Common Expression Language (CEL) syntax. Example: liquidityInUsd > 50000 **Response Data Format** WebSocket API returns shortened field names to optimize transmission efficiency, while SDK returns full field names for better code readability. ```typescript theme={null} { "a": string, // Token address "liu": string, // Total liquidity in USD "lin": string, // Total liquidity in native token "pc": number, // Pool count "ts": number // Timestamp } ``` ```typescript theme={null} { "tokenAddress": string, // Token address "liquidityInUsd": string, // Total liquidity in USD "liquidityInNative": string, // Total liquidity in native token "poolCount": number, // Pool count "timestamp": number // Timestamp } ``` ### Ranking Series #### Ranking Token Statistics Get real-time market statistics for ranking tokens. **Subscription Format** ```text theme={null} dex-ranking-token-stats-list:{chain}_{channelType} ``` **Parameters** Blockchain name, e.g., sol Channel type, support:new、trending、us\_stocks、completed、graduated **Response Data Format** WebSocket API returns shortened field names to optimize transmission efficiency, while SDK returns full field names to improve code readability. ```typescript theme={null} [ { "a": string, // Token address "t": number, // Timestamp "b1m": number, // Buys in 1m "s1m": number, // Sells in 1m "be1m": number, // Buyers in 1m "se1m": number, // Sellers in 1m "bviu1m": number, // Buy volume in USD 1m "sviu1m": number, // Sell volume in USD 1m "p1m": number, // Price 1m "oiu1m": number, // Open price in USD 1m "ciu1m": number, // Close price in USD 1m "b5m": number, // Buys in 5m "s5m": number, // Sells in 5m "be5m": number, // Buyers in 5m "se5m": number, // Sellers in 5m "bviu5m": number, // Buy volume in USD 5m "sviu5m": number, // Sell volume in USD 5m "p5m": number, // Price 5m "oiu5m": number, // Open price in USD 5m "ciu5m": number, // Close price in USD 5m "b15m": number, // Buys in 15m "s15m": number, // Sells in 15m "be15m": number, // Buyers in 15m "se15m": number, // Sellers in 15m "bviu15m": number,// Buy volume in USD 15m "sviu15m": number,// Sell volume in USD 15m "p15m": number, // Price 15m "oiu15m": number, // Open price in USD 15m "ciu15m": number, // Close price in USD 15m "b30m": number, // Buys in 30m "s30m": number, // Sells in 30m "be30m": number, // Buyers in 30m "se30m": number, // Sellers in 30m "bviu30m": number,// Buy volume in USD 30m "sviu30m": number,// Sell volume in USD 30m "p30m": number, // Price 30m "oiu30m": number, // Open price in USD 30m "ciu30m": number, // Close price in USD 30m "b1h": number, // Buys in 1h "s1h": number, // Sells in 1h "be1h": number, // Buyers in 1h "se1h": number, // Sellers in 1h "bviu1h": number, // Buy volume in USD 1h "sviu1h": number, // Sell volume in USD 1h "p1h": number, // Price 1h "oiu1h": number, // Open price in USD 1h "ciu1h": number, // Close price in USD 1h "b4h": number, // Buys in 4h "s4h": number, // Sells in 4h "be4h": number, // Buyers in 4h "se4h": number, // Sellers in 4h "bviu4h": number, // Buy volume in USD 4h "sviu4h": number, // Sell volume in USD 4h "p4h": number, // Price 4h "oiu4h": number, // Open price in USD 4h "ciu4h": number, // Close price in USD 4h "b24h": number, // Buys in 24h "s24h": number, // Sells in 24h "be24h": number, // Buyers in 24h "se24h": number, // Sellers in 24h "bviu24h": number,// Buy volume in USD 24h "sviu24h": number,// Sell volume in USD 24h "p24h": number, // Price 24h "oiu24h": number, // Open price in USD 24h "ciu24h": number, // Close price in USD 24h "p": number // Current price } ] ``` ```typescript theme={null} [ { "address": string, // Token address "timestamp": number, // Timestamp "buys1m": number, // Buys in 1m "sells1m": number, // Sells in 1m "buyers1m": number, // Buyers in 1m "sellers1m": number, // Sellers in 1m "buyVolumeInUsd1m": number, // Buy volume in USD 1m "sellVolumeInUsd1m": number,// Sell volume in USD 1m "price1m": number, // Price 1m "openInUsd1m": number, // Open price in USD 1m "closeInUsd1m": number, // Close price in USD 1m "buys5m": number, // Buys in 5m "sells5m": number, // Sells in 5m "buyers5m": number, // Buyers in 5m "sellers5m": number, // Sellers in 5m "buyVolumeInUsd5m": number, // Buy volume in USD 5m "sellVolumeInUsd5m": number,// Sell volume in USD 5m "price5m": number, // Price 5m "openInUsd5m": number, // Open price in USD 5m "closeInUsd5m": number, // Close price in USD 5m "buys15m": number, // Buys in 15m "sells15m": number, // Sells in 15m "buyers15m": number, // Buyers in 15m "sellers15m": number, // Sellers in 15m "buyVolumeInUsd15m": number,// Buy volume in USD 15m "sellVolumeInUsd15m": number,// Sell volume in USD 15m "price15m": number, // Price 15m "openInUsd15m": number, // Open price in USD 15m "closeInUsd15m": number, // Close price in USD 15m "buys30m": number, // Buys in 30m "sells30m": number, // Sells in 30m "buyers30m": number, // Buyers in 30m "sellers30m": number, // Sellers in 30m "buyVolumeInUsd30m": number,// Buy volume in USD 30m "sellVolumeInUsd30m": number,// Sell volume in USD 30m "price30m": number, // Price 30m "openInUsd30m": number, // Open price in USD 30m "closeInUsd30m": number, // Close price in USD 30m "buys1h": number, // Buys in 1h "sells1h": number, // Sells in 1h "buyers1h": number, // Buyers in 1h "sellers1h": number, // Sellers in 1h "buyVolumeInUsd1h": number, // Buy volume in USD 1h "sellVolumeInUsd1h": number,// Sell volume in USD 1h "price1h": number, // Price 1h "openInUsd1h": number, // Open price in USD 1h "closeInUsd1h": number, // Close price in USD 1h "buys4h": number, // Buys in 4h "sells4h": number, // Sells in 4h "buyers4h": number, // Buyers in 4h "sellers4h": number, // Sellers in 4h "buyVolumeInUsd4h": number, // Buy volume in USD 4h "sellVolumeInUsd4h": number,// Sell volume in USD 4h "price4h": number, // Price 4h "openInUsd4h": number, // Open price in USD 4h "closeInUsd4h": number, // Close price in USD 4h "buys24h": number, // Buys in 24h "sells24h": number, // Sells in 24h "buyers24h": number, // Buyers in 24h "sellers24h": number, // Sellers in 24h "buyVolumeInUsd24h": number,// Buy volume in USD 24h "sellVolumeInUsd24h": number,// Sell volume in USD 24h "price24h": number, // Price 24h "openInUsd24h": number, // Open price in USD 24h "closeInUsd24h": number, // Close price in USD 24h "price": number // Current price } ] ``` #### Ranking Token Holders Statistics Get real-time token holder statistics for ranking tokens. **Subscription Format** ```text theme={null} dex-ranking-token-holding-list:{chain}_{channelType} ``` **Parameters** Blockchain name, e.g., sol Channel type, support:new、trending、us\_stocks、completed、graduated **Response Data Format** WebSocket API returns shortened field names to optimize transmission efficiency, while SDK returns full field names to improve code readability. ```typescript theme={null} [ { "a": string, // Token address "h": number, // Number of holders "t100a": number, // Top 100 holders total amount "t10a": number, // Top 10 holders total amount "t100h": number, // Top 100 holders count "t10h": number, // Top 10 holders count "t100r": number, // Top 100 holders ratio "t10r": number, // Top 10 holders ratio "ts": number // Timestamp } ] ``` ```typescript theme={null} [ { "tokenAddress": string, // Token address "holders": number, // Number of holders "top100Amount": number, // Top 100 holders total amount "top10Amount": number, // Top 10 holders total amount "top100Holders": number, // Top 100 holders count "top10Holders": number, // Top 10 holders count "top100Ratio": number, // Top 100 holders ratio "top10Ratio": number, // Top 10 holders ratio "timestamp": number // Timestamp } ] ``` #### Ranking Token Supply Data Get real-time supply and market cap information for ranking tokens. **Subscription Format** ```text theme={null} dex-ranking-token-supply-list:{chain}_{channelType} ``` **Parameters** Blockchain name, e.g., sol Channel type, support:new、trending、us\_stocks、completed、graduated **Response Data Format** WebSocket API returns shortened field names to optimize transmission efficiency, while SDK returns full field names to improve code readability. ```typescript theme={null} [ { "a": string, // Token address "s": number, // Supply "mc": number, // Market cap in USD "ts": number // Timestamp } ] ``` ```typescript theme={null} [ { "tokenAddress": string, // Token address "supply": number, // Supply "marketCapInUsd": number, // Market cap in USD "timestamp": number // Timestamp } ] ``` #### Ranking Token Liquidity Data Get real-time liquidity statistics for ranking tokens. **Subscription Format** ```text theme={null} dex-ranking-token-general_stat_num-list:{chain}_{channelType} ``` **Parameters** Blockchain name, e.g., sol Channel type, support:new、trending、us\_stocks、completed、graduated **Response Data Format** WebSocket API returns shortened field names to optimize transmission efficiency, while SDK returns full field names to improve code readability. ```typescript theme={null} [ { "a": string, // Token address "t": string, // Metric type "v": number, // Value "ts": number // Timestamp } ] ``` ```typescript theme={null} [ { "tokenAddress": string, // Token address "metricType": string, // Metric type "value": number, // Value "timestamp": number // Timestamp } ] ``` #### Ranking Token List Get real-time complete information list for ranking tokens, including metadata, holder statistics, supply and market data. **Subscription Format** ```text theme={null} dex-ranking-list:{chain}_{ranking_type} # Or specify DEX dex-ranking-list:{chain}_{ranking_type}_{dex} ``` **Parameters** Blockchain name, e.g., sol Ranking type, support:new、trending、us\_stocks、completed、graduated Optional DEX platform, support:pump\_fun、raydium\_launchpad、meteora\_dynamic\_bounding\_curve、bonk\_fun、boop\_fun、moonit\_fun **Response Data Format** WebSocket API returns shortened field names to optimize transmission efficiency, while SDK returns full field names to improve code readability. ```typescript theme={null} [ { // TokenMetadata (t) "t": { "a": string, // Token address "n": string, // Name "s": string, // Symbol "iu": string, // Image URL "de": string, // Description "dec": number, // Decimals "cts": number, // Created timestamp (ms) "lf": { // Launch from information "pa": string, // Program address "pf": string, // Protocol family "pn": string // Protocol name }, "mt": { // Migrated to information "pa": string, // Program address "pf": string, // Protocol family "pn": string // Protocol name }, "sm": { // Social media "tw": string, // Twitter "tg": string, // Telegram "w": string, // Website "tt": string, // TikTok "dc": string, // Discord "fb": string, // Facebook "gh": string, // GitHub "ig": string, // Instagram "li": string, // LinkedIn "md": string, // Medium "rd": string, // Reddit "yt": string, // YouTube "bb": string // BitBucket } }, // TokenBondingCurve (bc) "bc": { "pr": number // Progress ratio }, // TokenHolder (h) "h": { "a": string, // Token address "h": number, // Number of holders "t100a": number, // Top 100 holders total amount "t10a": number, // Top 10 holders total amount "t100h": number, // Top 100 holders count "t10h": number, // Top 10 holders count "t100r": number, // Top 100 holders ratio "t10r": number, // Top 10 holders ratio "ts": number // Timestamp }, // TokenSupply (s) "s": { "a": string, // Token address "s": number, // Supply "mc": number, // Market cap in USD "ts": number // Timestamp }, // TokenStat (ts) "ts": { "a": string, // Token address "t": number, // Timestamp "b1m": number, // Buys in 1m "s1m": number, // Sells in 1m "be1m": number, // Buyers in 1m "se1m": number, // Sellers in 1m "bviu1m": number, // Buy volume in USD 1m "sviu1m": number, // Sell volume in USD 1m "p1m": number, // Price 1m "oiu1m": number, // Open price in USD 1m "ciu1m": number, // Close price in USD 1m "b5m": number, // Buys in 5m "s5m": number, // Sells in 5m "be5m": number, // Buyers in 5m "se5m": number, // Sellers in 5m "bviu5m": number, // Buy volume in USD 5m "sviu5m": number, // Sell volume in USD 5m "p5m": number, // Price 5m "oiu5m": number, // Open price in USD 5m "ciu5m": number, // Close price in USD 5m "b15m": number, // Buys in 15m "s15m": number, // Sells in 15m "be15m": number, // Buyers in 15m "se15m": number, // Sellers in 15m "bviu15m": number,// Buy volume in USD 15m "sviu15m": number,// Sell volume in USD 15m "p15m": number, // Price 15m "oiu15m": number, // Open price in USD 15m "ciu15m": number, // Close price in USD 15m "b30m": number, // Buys in 30m "s30m": number, // Sells in 30m "be30m": number, // Buyers in 30m "se30m": number, // Sellers in 30m "bviu30m": number,// Buy volume in USD 30m "sviu30m": number,// Sell volume in USD 30m "p30m": number, // Price 30m "oiu30m": number, // Open price in USD 30m "ciu30m": number, // Close price in USD 30m "b1h": number, // Buys in 1h "s1h": number, // Sells in 1h "be1h": number, // Buyers in 1h "se1h": number, // Sellers in 1h "bviu1h": number, // Buy volume in USD 1h "sviu1h": number, // Sell volume in USD 1h "p1h": number, // Price 1h "oiu1h": number, // Open price in USD 1h "ciu1h": number, // Close price in USD 1h "b4h": number, // Buys in 4h "s4h": number, // Sells in 4h "be4h": number, // Buyers in 4h "se4h": number, // Sellers in 4h "bviu4h": number, // Buy volume in USD 4h "sviu4h": number, // Sell volume in USD 4h "p4h": number, // Price 4h "oiu4h": number, // Open price in USD 4h "ciu4h": number, // Close price in USD 4h "b24h": number, // Buys in 24h "s24h": number, // Sells in 24h "be24h": number, // Buyers in 24h "se24h": number, // Sellers in 24h "bviu24h": number,// Buy volume in USD 24h "sviu24h": number,// Sell volume in USD 24h "p24h": number, // Price 24h "oiu24h": number, // Open price in USD 24h "ciu24h": number, // Close price in USD 24h "p": number // Current price } } ] ``` ```typescript theme={null} [ { // Token metadata "metadata": { "tokenAddress": string, // Token address "name": string, // Name "symbol": string, // Symbol "imageUrl": string, // Image URL "description": string, // Description "decimals": number, // Decimals "createdAtMs": number, // Created timestamp (ms) "launchFrom": { // Launch from information "programAddress": string, // Program address "protocolFamily": string, // Protocol family "protocolName": string // Protocol name }, "migratedTo": { // Migrated to information "programAddress": string, // Program address "protocolFamily": string, // Protocol family "protocolName": string // Protocol name }, "socialMedia": { // Social media "twitter": string, // Twitter "telegram": string, // Telegram "website": string, // Website "tiktok": string, // TikTok "discord": string, // Discord "facebook": string, // Facebook "github": string, // GitHub "instagram": string, // Instagram "linkedin": string, // LinkedIn "medium": string, // Medium "reddit": string, // Reddit "youtube": string, // YouTube "bitbucket": string // BitBucket } }, // Bonding curve information "bondingCurve": { "progressRatio": number // Progress ratio }, // Holder statistics "holder": { "tokenAddress": string, // Token address "timestamp": number, // Timestamp "holders": number, // Number of holders "top100Amount": number, // Top 100 holders total amount "top10Amount": number, // Top 10 holders total amount "top100Holders": number, // Top 100 holders count "top10Holders": number, // Top 10 holders count "top100Ratio": number, // Top 100 holders ratio "top10Ratio": number // Top 10 holders ratio }, // Supply information "supply": { "tokenAddress": string, // Token address "timestamp": number, // Timestamp "supply": number, // Supply "marketCapInUsd": number // Market cap in USD }, // Market statistics "stat": { "address": string, // Token address "timestamp": number, // Timestamp "buys1m": number, // Buys in 1m "sells1m": number, // Sells in 1m "buyers1m": number, // Buyers in 1m "sellers1m": number, // Sellers in 1m "buyVolumeInUsd1m": number, // Buy volume in USD 1m "sellVolumeInUsd1m": number,// Sell volume in USD 1m "price1m": number, // Price 1m "openInUsd1m": number, // Open price in USD 1m "closeInUsd1m": number, // Close price in USD 1m "buys5m": number, // Buys in 5m "sells5m": number, // Sells in 5m "buyers5m": number, // Buyers in 5m "sellers5m": number, // Sellers in 5m "buyVolumeInUsd5m": number, // Buy volume in USD 5m "sellVolumeInUsd5m": number,// Sell volume in USD 5m "price5m": number, // Price 5m "openInUsd5m": number, // Open price in USD 5m "closeInUsd5m": number, // Close price in USD 5m "buys15m": number, // Buys in 15m "sells15m": number, // Sells in 15m "buyers15m": number, // Buyers in 15m "sellers15m": number, // Sellers in 15m "buyVolumeInUsd15m": number,// Buy volume in USD 15m "sellVolumeInUsd15m": number,// Sell volume in USD 15m "price15m": number, // Price 15m "openInUsd15m": number, // Open price in USD 15m "closeInUsd15m": number, // Close price in USD 15m "buys30m": number, // Buys in 30m "sells30m": number, // Sells in 30m "buyers30m": number, // Buyers in 30m "sellers30m": number, // Sellers in 30m "buyVolumeInUsd30m": number,// Buy volume in USD 30m "sellVolumeInUsd30m": number,// Sell volume in USD 30m "price30m": number, // Price 30m "openInUsd30m": number, // Open price in USD 30m "closeInUsd30m": number, // Close price in USD 30m "buys1h": number, // Buys in 1h "sells1h": number, // Sells in 1h "buyers1h": number, // Buyers in 1h "sellers1h": number, // Sellers in 1h "buyVolumeInUsd1h": number, // Buy volume in USD 1h "sellVolumeInUsd1h": number,// Sell volume in USD 1h "price1h": number, // Price 1h "openInUsd1h": number, // Open price in USD 1h "closeInUsd1h": number, // Close price in USD 1h "buys4h": number, // Buys in 4h "sells4h": number, // Sells in 4h "buyers4h": number, // Buyers in 4h "sellers4h": number, // Sellers in 4h "buyVolumeInUsd4h": number, // Buy volume in USD 4h "sellVolumeInUsd4h": number,// Sell volume in USD 4h "price4h": number, // Price 4h "openInUsd4h": number, // Open price in USD 4h "closeInUsd4h": number, // Close price in USD 4h "buys24h": number, // Buys in 24h "sells24h": number, // Sells in 24h "buyers24h": number, // Buyers in 24h "sellers24h": number, // Sellers in 24h "buyVolumeInUsd24h": number,// Buy volume in USD 24h "sellVolumeInUsd24h": number,// Sell volume in USD 24h "price24h": number, // Price 24h "openInUsd24h": number, // Open price in USD 24h "closeInUsd24h": number, // Close price in USD 24h "price": number // Current price } } ] ``` #### Ranking Tokens Bonding Curve Get real-time bonding curve progress for newly listed tokens. **Subscription Format** ```text theme={null} dex-ranking-token-bounding-curve-list:{chain}_new ``` **Parameters** Blockchain name, e.g., sol **Response Data Format** WebSocket API returns shortened field names to optimize transmission efficiency, while SDK returns full field names to improve code readability. ```typescript theme={null} [ { "a": string, // Token address "pr": string // Progress ratio (0-1) } ] ``` ```typescript theme={null} [ { "tokenAddress": string, // Token address "progressRatio": string // Progress ratio (0-1) } ] ``` ### Wallet Series #### Wallet Balance Get real-time wallet balance information. **Subscription Format** ```text theme={null} dex-wallet-balance:{chain}_{walletAddress} ``` **Parameters** Blockchain name, e.g., sol Wallet address, e.g., HN7cABqLq46Es1jh92dQQisAq662SmxELLLsHHe4YWrH Optional filter condition using Google Common Expression Language (CEL) syntax. Example: balance > 1000 **Response Data Format** WebSocket API returns shortened field names to optimize transmission efficiency, while SDK returns full field names to improve code readability. ```typescript theme={null} [ { "a": string, // Wallet address "ta": string, // Token address "tpiu": number, // Token price in USD "b": number, // Balance "t": number // Timestamp } ] ``` ```typescript theme={null} [ { "walletAddress": string, // Wallet address "tokenAddress": string, // Token address "tokenPriceInUsd": number, // Token price in USD "balance": number, // Balance "timestamp": number // Timestamp } ] ``` #### Wallet PnL Data (Token Level) Get real-time wallet profit and loss (PnL) statistics. **Subscription Format** ```text theme={null} dex-wallet-token-pnl:{chain}_{walletAddress} ``` **Parameters** Blockchain name, e.g., sol Wallet address Optional filter condition using Google Common Expression Language (CEL) syntax. Example: buyAmount > 1000 **Response Data Format** WebSocket API returns shortened field names to optimize transmission efficiency, while SDK returns full field names for better code readability. ```typescript theme={null} { "a": string, // Wallet address "ta": string, // Token address "tpiu": number, // Token price in USD "t": number, // Timestamp "ot": number, // Open time "lt": number, // Last time "ct": number, // Close time "ba": number, // Buy amount "baiu": number, // Buy amount in USD "bs": number, // Buy count "bs30d": number, // Buy count 30d "bs7d": number, // Buy count 7d "sa": number, // Sell amount "saiu": number, // Sell amount in USD "ss": number, // Sell count "ss30d": number, // Sell count 30d "ss7d": number, // Sell count 7d "hdts": number, // Held duration timestamp "abpiu": number, // Average buy price in USD "aspiu": number, // Average sell price in USD "upiu": number, // Unrealized profit in USD "upr": number, // Unrealized profit ratio "rpiu": number, // Realized profit in USD "rpr": number, // Realized profit ratio "trpiu": number, // Total realized profit in USD "trr": number // Total realized profit ratio } ``` ```typescript theme={null} { "walletAddress": string, // Wallet address "tokenAddress": string, // Token address "tokenPriceInUsd": number, // Token price in USD "timestamp": number, // Timestamp "opentime": number, // Open time "lasttime": number, // Last time "closetime": number, // Close time "buyAmount": number, // Buy amount "buyAmountInUsd": number, // Buy amount in USD "buyCount": number, // Buy count "buyCount30d": number, // Buy count 30d "buyCount7d": number, // Buy count 7d "sellAmount": number, // Sell amount "sellAmountInUsd": number, // Sell amount in USD "sellCount": number, // Sell count "sellCount30d": number, // Sell count 30d "sellCount7d": number, // Sell count 7d "heldDurationTimestamp": number, // Held duration timestamp "averageBuyPriceInUsd": number, // Average buy price in USD "averageSellPriceInUsd": number, // Average sell price in USD "unrealizedProfitInUsd": number, // Unrealized profit in USD "unrealizedProfitRatio": number, // Unrealized profit ratio "realizedProfitInUsd": number, // Realized profit in USD "realizedProfitRatio": number, // Realized profit ratio "totalRealizedProfitInUsd": number, // Total realized profit in USD "totalRealizedProfitRatio": number // Total realized profit ratio } ``` #### Wallet PnL Data (Wallet Level) Get real-time wallet overall profit and loss statistics. **Subscription Format** ```text theme={null} dex-wallet-pnl-list:{chain}_{walletAddress} ``` **Parameters** Blockchain name, e.g., sol Wallet address **Response Data Format** WebSocket API returns shortened field names to optimize transmission efficiency, while SDK returns full field names for better code readability. ```typescript theme={null} [ { "a": string, // Wallet address "bs": number, // Number of buys "ba": number, // Buy amount "baiu": number, // Buy amount in USD "abpiu": number, // Average buy price in USD "sa": number, // Sell amount "saiu": number, // Sell amount in USD "ss": number, // Number of sells "ws": number, // Number of wins "wr": number, // Win ratio "piu": number, // PnL in USD "apiu": number, // Average PnL in USD "pr": number, // PnL ratio "pd": number, // Profitable days "ld": number, // Losing days "ts": number, // Number of tokens traded "r": string // Resolution } ] ``` ```typescript theme={null} [ { "walletAddress": string, // Wallet address "buys": number, // Number of buys "buyAmount": number, // Buy amount "buyAmountInUsd": number, // Buy amount in USD "averageBuyPriceInUsd": number, // Average buy price in USD "sellAmount": number, // Sell amount "sellAmountInUsd": number, // Sell amount in USD "sells": number, // Number of sells "wins": number, // Number of wins "winRatio": number, // Win ratio "pnlInUsd": number, // PnL in USD "averagePnlInUsd": number, // Average PnL in USD "pnlRatio": number, // PnL ratio "profitableDays": number, // Profitable days "losingDays": number, // Losing days "tokens": number, // Number of tokens traded "resolution": string // Resolution } ] ``` ### Trade Series #### Token Trade Get real-time token trading events. **Subscription Format** ```text theme={null} dex-trade:{chain}_{tokenAddress} ``` **Parameters** Blockchain name, e.g., sol Token contract address, e.g., 6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN Optional filter condition using Google Common Expression Language (CEL) syntax. Example: buyAmount > 100 **Response Data Format** WebSocket API returns shortened field names to optimize transmission efficiency, while SDK returns full field names to improve code readability. ```typescript theme={null} { "a": string, // Token address "t": number, // Timestamp "k": string, // Trade type "ba": number, // Buy amount "baiu": number, // Buy amount in USD "btma": string, // Buy token address "btn": string, // Buy token name "bts": string, // Buy token symbol "bwa": string, // Buy wallet address "sa": number, // Sell amount "saiu": number, // Sell amount in USD "stma": string, // Sell token address "stn": string, // Sell token name "sts": string, // Sell token symbol "swa": string, // Sell wallet address "h": string // Transaction hash } ``` ```typescript theme={null} { "tokenAddress": string, // Token address "timestamp": number, // Timestamp "kind": string, // Trade type "buyAmount": number, // Buy amount "buyAmountInUsd": number, // Buy amount in USD "buyTokenAddress": string, // Buy token address "buyTokenName": string, // Buy token name "buyTokenSymbol": string, // Buy token symbol "buyWalletAddress": string,// Buy wallet address "sellAmount": number, // Sell amount "sellAmountInUsd": number,// Sell amount in USD "sellTokenAddress": string,// Sell token address "sellTokenName": string, // Sell token name "sellTokenSymbol": string,// Sell token symbol "sellWalletAddress": string,// Sell wallet address "txHash": string // Transaction hash } ``` #### Wallet Trade Get real-time wallet trading event. **Subscription Format** ```text theme={null} dex-wallet-trade:{chain}_{walletAddress} ``` **Parameters** Blockchain name, e.g., sol Token contract address, e.g., GDekof7TtgeBKJtoVpkvzPin5mvhxSDyoUY2c1FK1T3i **Response Data Format** WebSocket API returns shortened field names to optimize transmission efficiency, while SDK returns full field names to improve code readability. ```typescript theme={null} { "bwa": string, // Maker address "ba": number, // Base token amount "sa": number, // Quote token amount "swa": string, // Quote token address "bais": number, // USD amount "t": number, // Timestamp "k": string, // Event type "h": string, // Transaction hash "a": string // Token address } ``` ```typescript theme={null} { "maker": string, // Maker address "baseAmount": number, // Base token amount "quoteAmount": number, // Quote token amount "quoteAddress": string, // Quote token address "amountInUsd": number, // USD amount "timestamp": number, // Timestamp "event": string, // Event type "txHash": string, // Transaction hash "tokenAddress": string // Token address } ``` ### DexPool Series #### DEX Pool Balance Get real-time DEX pool balance information. **Subscription Format** ```text theme={null} dex-pool-balance:{chain}_{poolAddress} ``` **Parameters** Blockchain name, e.g., sol Pool address **Response Data Format** WebSocket API returns shortened field names to optimize transmission efficiency, while SDK returns full field names for better code readability. ```typescript theme={null} { "a": string, // Pool address "taa": string, // Token A address "taliu": number, // Token A liquidity in USD "tba": string, // Token B address "tbliu": number // Token B liquidity in USD } ``` ```typescript theme={null} { "poolAddress": string, // Pool address "tokenAAddress": string, // Token A address "tokenALiquidityInUsd": number, // Token A liquidity in USD "tokenBAddress": string, // Token B address "tokenBLiquidityInUsd": number // Token B liquidity in USD } ``` ## Usage Examples ```typescript theme={null} import { ChainStreamClient } from '@chainstream-io/sdk'; import { Resolution } from '@chainstream-io/sdk/openapi'; const client = new ChainStreamClient('YOUR_ACCESS_TOKEN'); // Just subscribe directly, SDK auto-detects connection status and connects if needed client.stream.subscribeTokenCandles({ chain: 'sol', tokenAddress: '6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN', resolution: Resolution._1m, callback: (data) => { console.log('Candle data:', data); } }); // Subscribe to wallet balance client.stream.subscribeWalletBalance({ chain: 'sol', walletAddress: 'YOUR_WALLET_ADDRESS', callback: (data) => { console.log('Wallet balance:', data); } }); ``` ### Reconnection Strategy Recommended to use exponential backoff for reconnection: ```typescript theme={null} function reconnect(attempt) { const delay = Math.min(1000 * Math.pow(2, attempt), 10000); setTimeout(() => { connect(); }, delay); } ``` ## Usage Limits | Limit | Value | Description | | --------------------- | -------------- | -------------------------- | | Maximum Subscriptions | 100/connection | Excess will be rejected | | Message Size | 100KB | Excess will be truncated | | Heartbeat Interval | 30 seconds | Regular heartbeat required | ## Best Practices 1. **Connection Management** * Maintain a single WebSocket connection * Implement automatic reconnection * Send regular heartbeats 2. **Error Handling** * Implement complete error handling * Log detailed error information * Use exponential backoff for reconnection 3. **Performance Optimization** * Control subscription quantity * Implement message queue mechanism * Clean up unused subscriptions ## Complete Example ```typescript theme={null} import { ChainStreamClient } from '@chainstream-io/sdk'; import { Resolution } from '@chainstream-io/sdk/openapi'; const client = new ChainStreamClient('YOUR_ACCESS_TOKEN'); // Just subscribe directly, SDK auto-detects connection status and connects if needed const subscription = client.stream.subscribeTokenCandles({ chain: 'sol', tokenAddress: '6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN', resolution: Resolution._1m, callback: (data) => { console.log('Candle data:', data); } }); // Unsubscribe subscription.unsubscribe(); ``` When using the SDK, authentication, reconnection, heartbeat, etc. are all handled automatically. Recommended for production environments. * **TypeScript/JavaScript SDK**: [@chainstream-io/sdk](https://www.npmjs.com/package/@chainstream-io/sdk) * **Python SDK**: [chainstream-sdk](https://pypi.org/project/chainstream-sdk) * **Go SDK**: [chainstream-go-sdk](https://github.com/chainstream-io/chainstream-go-sdk) * **Rust SDK**: [chainstream-sdk](https://crates.io/crates/chainstream-sdk) ```typescript theme={null} class DexWebSocket { private ws: WebSocket; private reconnectAttempts = 0; private maxReconnectAttempts = 5; private subscriptions = new Set(); constructor( private baseUrl: string, private accessToken: string ) { this.connect(); } private connect() { // Append token parameter to URL for authentication const url = `${this.baseUrl}?token=${this.accessToken}`; this.ws = new WebSocket(url); this.ws.onopen = () => { console.log('WebSocket connection established'); this.reconnectAttempts = 0; // Resubscribe to previous channels this.resubscribe(); }; this.ws.onmessage = (event) => { this.handleMessage(JSON.parse(event.data)); }; this.ws.onclose = () => { console.log('WebSocket connection closed'); this.reconnect(); }; this.ws.onerror = (error) => { console.error('WebSocket error:', error); }; } private reconnect() { if (this.reconnectAttempts < this.maxReconnectAttempts) { const delay = Math.min(1000 * Math.pow(2, this.reconnectAttempts), 10000); this.reconnectAttempts++; console.log(`Attempting reconnection in ${delay}ms...`); setTimeout(() => this.connect(), delay); } } private resubscribe() { this.subscriptions.forEach(channel => { this.send({ type: "subscribe", channel }); }); } private handleMessage(data: any) { // Handle message } private send(data: any) { if (this.ws.readyState === WebSocket.OPEN) { this.ws.send(JSON.stringify(data)); } } public subscribe(channel: string) { this.subscriptions.add(channel); this.send({ type: "subscribe", channel }); } public unsubscribe(channel: string) { this.subscriptions.delete(channel); this.send({ type: "unsubscribe", channel }); } } // Usage example const client = new DexWebSocket( "wss://realtime-dex.chainstream.io/connection/websocket", "YOUR_ACCESS_TOKEN" ); ``` # Introduction Source: https://docs.chainstream.io/en/api-reference/endpoint/websocket/introduction Real-time data streaming via WebSocket API ## Overview WebSocket endpoints are available for real-time data streaming and as an alternative to HTTP request sending on the ChainStream exchange. The WebSocket URLs by network are: * Mainnet: `wss://realtime-dex.chainstream.io/connection/websocket` ## Authentication WebSocket connections require authentication via the `token` query parameter in the URL: ``` wss://realtime-dex.chainstream.io/connection/websocket?token=YOUR_ACCESS_TOKEN ``` If you are using our **Go SDK** or **JavaScript SDK**, authentication is built-in and handled automatically. You only need to manually append the token parameter when using native WebSocket libraries or other third-party libraries. ## Connecting To connect to the WebSocket API, you must establish a WebSocket connection to the respective URL based on your desired network, with the token parameter in the URL. Once connected, you can start sending subscription messages to receive real-time data updates. ### Command Line Example Using `wscat` to test the connection: ```bash theme={null} $ wscat -c "wss://realtime-dex.chainstream.io/connection/websocket?token=YOUR_ACCESS_TOKEN" Connected (press CTRL+C to quit) > { "method": "subscribe", "subscription": { "type": "trades", "coin": "SOL" } } < {"channel":"subscriptionResponse","data":{"method":"subscribe","subscription":{"type":"trades","coin":"SOL"}}} ``` Failing to provide a valid `token` parameter will result in connection rejection or inability to receive data. This documentation uses TypeScript for defining message types. For Python users, you can find equivalent types in our Python SDK. # Timeouts and Heartbeats Source: https://docs.chainstream.io/en/api-reference/endpoint/websocket/timeouts-and-heartbeats Keep WebSocket connections alive ## Overview To maintain an active WebSocket connection, you need to understand how timeouts work and how to use heartbeat messages. ## Connection Timeout The server will automatically close any connection that hasn't received a message in the last 60 seconds. This helps maintain server resources and clean up stale connections. ## Heartbeat Messages If you are subscribed to a channel that doesn't receive regular messages (less than once every 60 seconds), you should send heartbeat messages to keep your connection alive. ### Ping Format Send a ping message in this format: ```json theme={null} { "method": "ping" } ``` ### Pong Response The server will respond with: ```json theme={null} { "channel": "pong" } ``` It's recommended to implement an automatic heartbeat mechanism in your client to send ping messages every 30 seconds if no other messages have been sent. # EVM Kafka Topics Source: https://docs.chainstream.io/en/api-reference/kafka-topics/evm Reference list of EVM-chain Kafka topic names, partition keys and payload schemas. Authoritative list of Kafka topics published for every EVM chain ChainStream indexes. Topic naming uses the `{chain}` prefix — substitute `eth`, `bsc`, `base`, `polygon`, `optimism`, `arbitrum`, `avalanche`, or `zksync` for the network you want to consume. For end-to-end connection details, SASL credentials, and SDK examples see [Access Methods → Kafka Streams → EVM Streams](/en/docs/access-methods/kafka-streams/evm-streams). For the authoritative Protobuf definitions see [github.com/chainstream-io/streaming\_protobuf/evm](https://github.com/chainstream-io/streaming_protobuf/tree/main/evm). ## Partitioning All EVM topics are partitioned by one of: * **Token address** (bytes20) — for token-centric topics (`tokens`, `dex.trades`, `dex.pools`, `candlesticks`, `token-prices`, `token-supplies`, `token-market-caps`, `trade-stats`, `token-holdings`) * **Account address** (bytes20) — for account-centric topics (`balances`, `v1.transfers.proto`) Events for the same address land on the same partition in block order — safe to scale consumers horizontally by partition. ## Topic matrix `{chain}` ∈ `eth` | `bsc` | `base` | `polygon` | `optimism` | `arbitrum` | `avalanche` | `zksync` (see the chain availability matrix in [EVM Streams](/en/docs/access-methods/kafka-streams/evm-streams)). ### DEX trades | Topic | Proto message | Schema file | Description | | ------------------------------ | ------------- | ----------------------- | ----------------------------------------------------------------------- | | `{chain}.dex.trades` | `TradeEvents` | `evm/trade_event.proto` | Raw DEX swaps emitted as they are confirmed | | `{chain}.dex.trades.processed` | `TradeEvents` | `evm/trade_event.proto` | Same events enriched with USD / native price, suspect flags, and dedupe | ### Tokens | Topic | Proto message | Schema file | Description | | -------------------------- | ------------- | ----------------------- | ----------------------------------------------------- | | `{chain}.tokens` | `TokenEvents` | `evm/token_event.proto` | Token lifecycle events (create, update, migrate) | | `{chain}.tokens.created` | `TokenEvents` | `evm/token_event.proto` | Filtered stream of token-creation events only | | `{chain}.tokens.processed` | `TokenEvents` | `evm/token_event.proto` | Tokens enriched with description, image, social links | ### Token-level statistics | Topic | Proto message | Schema file | Description | | ------------------------------------- | --------------------- | ---------------------------------- | ----------------------------------------------- | | `{chain}.token-prices` | `TokenPriceEvent` | `evm/token_price_event.proto` | Aggregated price updates (USD + native) | | `{chain}.token-supplies` | `TokenSupplyEvent` | `evm/token_supply_event.proto` | Circulating + total supply changes | | `{chain}.token-supplies.processed` | `TokenSupplyEvent` | `evm/token_supply_event.proto` | Supplies with decimal normalization + USD value | | `{chain}.token-market-caps.processed` | `TokenMarketCapEvent` | `evm/token_market_cap_event.proto` | Market cap (circulating × price) | | `{chain}.token-holdings` | `TokenHoldingEvent` | `evm/token_holding_event.proto` | Holder count, top-N concentration | | `{chain}.trade-stats` | `TradeStatEvent` | `evm/trade_stat_event.proto` | Trade counts, volume, buyers / sellers | ### Balances | Topic | Proto message | Schema file | Description | | ---------------------------- | --------------- | ------------------------- | ----------------------------------------------- | | `{chain}.balances` | `BalanceEvents` | `evm/balance_event.proto` | Raw balance-change events per account | | `{chain}.balances.processed` | `BalanceEvents` | `evm/balance_event.proto` | Balance events enriched with USD + native value | ### DEX pools | Topic | Proto message | Schema file | Description | | ----------------------------- | --------------- | -------------------------- | ---------------------------------------------------------- | | `{chain}.dex.pools` | `DexPoolEvents` | `evm/dex_pool_event.proto` | Pool create / update / sync events | | `{chain}.dex.pools.processed` | `DexPoolEvents` | `evm/dex_pool_event.proto` | Pool events enriched with liquidity USD + native, fee tier | ### Transfers | Topic | Proto message | Schema file | Description | | -------------------------------------- | ------------------ | ----------------------------- | ------------------------------------------------------------------- | | `{chain}.v1.transfers.proto` | `TransfersMessage` | `evm/transfers_message.proto` | All token + native transfers (ERC-20 / ERC-721 / ERC-1155 / native) | | `{chain}.v1.transfers.processed.proto` | `TransfersMessage` | `evm/transfers_message.proto` | Transfers enriched with price at block-time + USD value | ### Candlesticks | Topic | Proto message | Schema file | Description | | ---------------------- | ------------------- | ------------------- | ----------------------------------------------- | | `{chain}.candlesticks` | `CandlestickEvents` | `candlestick.proto` | Pre-aggregated OHLC across multiple resolutions | ## Example consumer ```python theme={null} from confluent_kafka import Consumer from streaming_protobuf.evm.trade_event_pb2 import TradeEvents consumer = Consumer({ "bootstrap.servers": "kafka.chainstream.io:9093", "security.protocol": "SASL_SSL", "sasl.mechanism": "SCRAM-SHA-512", "sasl.username": "", "sasl.password": "", "group.id": "my-consumer", "auto.offset.reset": "latest", }) consumer.subscribe(["eth.dex.trades.processed"]) while True: msg = consumer.poll(1.0) if msg is None or msg.error(): continue events = TradeEvents.FromString(msg.value()) for trade in events.Trades: print(trade) ``` See the [EVM Streams guide](/en/docs/access-methods/kafka-streams/evm-streams) for JavaScript and Go equivalents. ## Next Topic list for Solana Topic list for Tron Connection, auth, partition model Field definitions and consumer examples # Solana Kafka Topics Source: https://docs.chainstream.io/en/api-reference/kafka-topics/solana Reference list of Solana Kafka topic names, partition keys and payload schemas. Authoritative list of Kafka topics published for Solana. All topics use the `sol.` prefix. For end-to-end connection details, SASL credentials, and SDK examples see [Access Methods → Kafka Streams → Solana Streams](/en/docs/access-methods/kafka-streams/solana-streams). For the authoritative Protobuf definitions see [github.com/chainstream-io/streaming\_protobuf/solana](https://github.com/chainstream-io/streaming_protobuf/tree/main/solana). ## Partitioning * **Mint address** (32-byte pubkey, base58-encoded) — for token-centric topics (`tokens`, `dex.trades`, `dex.pools`, `candlesticks`, `token-prices`, `token-supplies`, `token-market-caps`, `trade-stats`, `token-holdings`) * **Account address** — for account-centric topics (`balances`, `transfers`) Events for the same mint or account land on the same partition in slot order. ## Topic matrix ### DEX trades | Topic | Proto message | Schema file | Description | | -------------------------- | ------------- | -------------------------- | ---------------------------------------------------------------- | | `sol.dex.trades` | `TradeEvents` | `solana/trade_event.proto` | Raw DEX swaps (Raydium, Meteora, Pump.fun, Jupiter routes, etc.) | | `sol.dex.trades.processed` | `TradeEvents` | `solana/trade_event.proto` | Enriched with USD / SOL price, router resolution, suspect flags | ### Tokens | Topic | Proto message | Schema file | Description | | ---------------------- | ------------- | -------------------------- | ---------------------------------------------------------------- | | `sol.tokens` | `TokenEvents` | `solana/token_event.proto` | Token lifecycle events (mint, metadata update, authority change) | | `sol.tokens.created` | `TokenEvents` | `solana/token_event.proto` | Filtered stream of mint-creation events only | | `sol.tokens.processed` | `TokenEvents` | `solana/token_event.proto` | Tokens enriched with metadata JSON, image, socials | ### Token-level statistics | Topic | Proto message | Schema file | Description | | --------------------------------- | --------------------- | ------------------------------------- | --------------------------------------------- | | `sol.token-prices` | `TokenPriceEvent` | `solana/token_price_event.proto` | Aggregated price updates (USD + SOL) | | `sol.token-supplies` | `TokenSupplyEvent` | `solana/token_supply_event.proto` | Mint supply changes (mint/burn) | | `sol.token-supplies.processed` | `TokenSupplyEvent` | `solana/token_supply_event.proto` | Supplies normalized with decimals + USD value | | `sol.token-market-caps.processed` | `TokenMarketCapEvent` | `solana/token_market_cap_event.proto` | Market cap (circulating × price) | | `sol.token-holdings` | `TokenHoldingEvent` | `solana/token_holding_event.proto` | Holder count, top-N concentration | | `sol.trade-stats` | `TradeStatEvent` | `solana/trade_stat_event.proto` | Trade counts, volume, unique buyers / sellers | ### Balances | Topic | Proto message | Schema file | Description | | ------------------------ | --------------- | ---------------------------- | ------------------------------------- | | `sol.balances` | `BalanceEvents` | `solana/balance_event.proto` | Raw balance-change events per account | | `sol.balances.processed` | `BalanceEvents` | `solana/balance_event.proto` | Balance events with USD + SOL value | ### DEX pools | Topic | Proto message | Schema file | Description | | ------------------------- | --------------- | ----------------------------- | ---------------------------------------------------------- | | `sol.dex.pools` | `DexPoolEvents` | `solana/dex_pool_event.proto` | Pool create / update / sync events (including CLMM ticks) | | `sol.dex.pools.processed` | `DexPoolEvents` | `solana/dex_pool_event.proto` | Pool events enriched with liquidity USD + SOL and fee tier | ### Transfers | Topic | Proto message | Schema file | Description | | ------------------------- | ------------------------- | --------------------------------------- | -------------------------------------------------------------- | | `sol.transfers` | `TransferEvents` | `solana/transfer_event.proto` | All SPL + native transfers including program-invoked transfers | | `sol.transfers.processed` | `TransferProcessedEvents` | `solana/transfer_processed_event.proto` | Transfers enriched with price-at-slot + USD value | ### Candlesticks | Topic | Proto message | Schema file | Description | | ------------------ | ------------------- | ------------------- | ----------------------------------------------- | | `sol.candlesticks` | `CandlestickEvents` | `candlestick.proto` | Pre-aggregated OHLC across multiple resolutions | ## Example consumer ```python theme={null} from confluent_kafka import Consumer from streaming_protobuf.solana.trade_event_pb2 import TradeEvents consumer = Consumer({ "bootstrap.servers": "kafka.chainstream.io:9093", "security.protocol": "SASL_SSL", "sasl.mechanism": "SCRAM-SHA-512", "sasl.username": "", "sasl.password": "", "group.id": "my-consumer", "auto.offset.reset": "latest", }) consumer.subscribe(["sol.dex.trades.processed"]) while True: msg = consumer.poll(1.0) if msg is None or msg.error(): continue events = TradeEvents.FromString(msg.value()) for trade in events.Trades: print(trade) ``` See the [Solana Streams guide](/en/docs/access-methods/kafka-streams/solana-streams) for Go and JavaScript equivalents. ## Next Topic list for Ethereum, BSC, Base, Polygon and more Topic list for Tron Connection, auth, partition model Field definitions and consumer examples # Tron Kafka Topics Source: https://docs.chainstream.io/en/api-reference/kafka-topics/tron Reference list of Tron Kafka topic names, partition keys and payload schemas. Authoritative list of Kafka topics published for Tron. All topics use the `tron.` prefix. For end-to-end connection details, SASL credentials, and SDK examples see [Access Methods → Kafka Streams → Tron Streams](/en/docs/access-methods/kafka-streams/tron-streams). For the authoritative Protobuf definitions see [github.com/chainstream-io/streaming\_protobuf/tron](https://github.com/chainstream-io/streaming_protobuf/tree/main/tron). ## Partitioning * **Token address** (base58-encoded TRC-20 contract address) — for token-centric topics (`tokens`, `dex.trades`, `dex.pools`, `candlesticks`, `token-prices`, `token-supplies`) * **Account address** — for account-centric topics (`balances`, `v1.transfers.proto`) Events for the same contract or account land on the same partition in block order. ## Topic matrix ### DEX trades | Topic | Proto message | Schema file | Description | | --------------------------- | ------------- | ------------------------ | -------------------------------------------- | | `tron.dex.trades` | `TradeEvents` | `tron/trade_event.proto` | Raw DEX swaps (SunSwap, JustSwap, etc.) | | `tron.dex.trades.processed` | `TradeEvents` | `tron/trade_event.proto` | Enriched with USD / TRX price, suspect flags | ### Tokens | Topic | Proto message | Schema file | Description | | ----------------------- | ------------- | ------------------------ | ----------------------------------------------------- | | `tron.tokens` | `TokenEvents` | `tron/token_event.proto` | Token lifecycle events | | `tron.tokens.processed` | `TokenEvents` | `tron/token_event.proto` | Tokens enriched with description, image, social links | ### Token-level statistics | Topic | Proto message | Schema file | Description | | --------------------- | ------------------ | ------------------------------- | ------------------------------------ | | `tron.token-prices` | `TokenPriceEvent` | `tron/token_price_event.proto` | Aggregated price updates (USD + TRX) | | `tron.token-supplies` | `TokenSupplyEvent` | `tron/token_supply_event.proto` | Circulating + total supply changes | ### Balances | Topic | Proto message | Schema file | Description | | --------------- | --------------- | -------------------------- | ------------------------------------- | | `tron.balances` | `BalanceEvents` | `tron/balance_event.proto` | Raw balance-change events per account | ### DEX pools | Topic | Proto message | Schema file | Description | | ---------------- | --------------- | --------------------------- | ---------------------------------- | | `tron.dex.pools` | `DexPoolEvents` | `tron/dex_pool_event.proto` | Pool create / update / sync events | ### Transfers | Topic | Proto message | Schema file | Description | | ----------------------------------- | ------------------ | ------------------------------ | -------------------------------------------------- | | `tron.v1.transfers.proto` | `TransfersMessage` | `tron/transfers_message.proto` | All TRC-10 + TRC-20 + native transfers | | `tron.v1.transfers.processed.proto` | `TransfersMessage` | `tron/transfers_message.proto` | Transfers enriched with price-at-block + USD value | ### Candlesticks | Topic | Proto message | Schema file | Description | | ------------------- | ------------------- | ------------------- | ----------------------------------------------- | | `tron.candlesticks` | `CandlestickEvents` | `candlestick.proto` | Pre-aggregated OHLC across multiple resolutions | ## Example consumer ```python theme={null} from confluent_kafka import Consumer from streaming_protobuf.tron.trade_event_pb2 import TradeEvents consumer = Consumer({ "bootstrap.servers": "kafka.chainstream.io:9093", "security.protocol": "SASL_SSL", "sasl.mechanism": "SCRAM-SHA-512", "sasl.username": "", "sasl.password": "", "group.id": "my-consumer", "auto.offset.reset": "latest", }) consumer.subscribe(["tron.dex.trades.processed"]) while True: msg = consumer.poll(1.0) if msg is None or msg.error(): continue events = TradeEvents.FromString(msg.value()) for trade in events.Trades: print(trade) ``` See the [Tron Streams guide](/en/docs/access-methods/kafka-streams/tron-streams) for additional consumer examples. ## Next Topic list for Ethereum, BSC, Base, Polygon and more Topic list for Solana Connection, auth, partition model Field definitions and consumer examples # MCP Tools Reference Source: https://docs.chainstream.io/en/api-reference/mcp-tools/overview Complete tool catalog exposed by the ChainStream MCP Server. The ChainStream [MCP Server](/en/docs/ai-agents/mcp-server/introduction) exposes the full data catalog and DeFi primitives as Model Context Protocol tools. This page is the authoritative reference — for how to register the server with Claude, Cursor or other clients see [MCP Server Setup](/en/docs/ai-agents/mcp-server/setup). ## Endpoint * **URL**: `https://mcp.chainstream.io/mcp` * **Transport**: Streamable HTTP (horizontal scaling + progress reporting) * **Auth**: Bearer token (`X-API-KEY`) **or** x402 micropayment (USDC on Base / Solana) ## Two tool surfaces ChainStream ships the MCP server in two flavours. Pick the one that matches your agent's workflow. | Surface | Naming | When to use | | -------------------------- | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Outcome-oriented tools** | `tokens_search`, `dex_swap` (underscore) | Agents doing user-facing tasks — each tool orchestrates several REST calls and returns a curated result. This is what the [Agent Skills](/en/docs/ai-agents/agent-skills/introduction) reference. | | **Playground tools** | `getToken`, `createEndpoint` (camelCase) | 1:1 coverage of the REST API for programmatic use — same inputs/outputs as REST, ideal for testing and low-level automation | The 17 outcome-oriented tools below are what you see in the production MCP catalog. Playground tools are the full REST surface re-exposed as MCP tools — listed at the bottom. ## Resources | URI | Content | | ------------------------------------ | ----------------------------------------------- | | `chainstream://chains` | Supported chains and status | | `chainstream://chains/{chain}/dexes` | DEX protocols for a chain | | `chainstream://docs/api_reference` | Full REST API reference (all `/v2/*` endpoints) | | `chainstream://docs/query_examples` | Common query patterns for agents | ## Risk model Each tool is tagged with a risk level. Clients should surface tools with level ≥ L2 behind explicit confirmation UI. | Level | Meaning | | ------ | ---------------------------------------------------------------------------- | | **L0** | Read-only, stateless — safe to call automatically | | **L1** | Read-only, user-scoped (wallet profile, webhook list) — safe but personal | | **L2** | Read-only but computationally expensive (backtest) — may incur cost | | **L3** | **Writes / signs / broadcasts** — always requires explicit user confirmation | ## Outcome-oriented tools (17) ### Token intelligence | Tool | Description | Key params | Risk | | ---------------------- | ------------------------------------------------------------------------- | ------------------------------------------------ | ---- | | `tokens_search` | Search tokens by name, symbol or address across every supported chain | `query`, `chain?` | L0 | | `tokens_analyze` | Comprehensive token analysis: price, volume, holders, security, liquidity | `chain`, `address` | L0 | | `tokens_price_history` | OHLCV candlestick data for charting and technical analysis | `chain`, `address`, `resolution`, `from?`, `to?` | L0 | | `tokens_discover` | Find tokens by on-chain metrics (volume, price change, trade count) | `chain`, filters | L0 | | `tokens_compare` | Side-by-side comparison of up to 5 tokens | `chain`, `addresses[]` | L0 | ### Wallet intelligence | Tool | Description | Key params | Risk | | ------------------ | ----------------------------------------------------------------- | ---------------------------- | ---- | | `wallets_profile` | Complete wallet profile — holdings, PnL and net worth in one call | `chain`, `address` | L1 | | `wallets_activity` | Recent wallet transfers and balance changes | `chain`, `address`, `limit?` | L1 | ### Market discovery | Tool | Description | Key params | Risk | | ----------------- | ------------------------------------------------------------------------------ | -------------------------------------- | ---- | | `market_trending` | Trending tokens by category (`hot`, `new`, `migrated`, `graduating`, `stocks`) | `chain`, `category`, `duration` | L0 | | `trades_recent` | Recent on-chain trades for a token or wallet | `chain`, `token?`, `wallet?`, `limit?` | L0 | ### DEX and trading | Tool | Description | Key params | Risk | | ------------------ | ------------------------------------------------------------------ | ------------------------------------------- | ------ | | `dex_quote` | Swap quote with expected output, price impact and fees (read-only) | `chain`, `from`, `to`, `amount` | L0 | | `dex_swap` | Execute a token swap on a DEX | `chain`, `from`, `to`, `amount`, `slippage` | **L3** | | `dex_create_token` | Create a token on a launchpad | `chain`, `name`, `symbol`, `dex`, `uri` | **L3** | | `trading_backtest` | Backtest a strategy against historical data | strategy spec | L2 | | `trading_execute` | Execute a strategy trade | `chain`, `strategy`, `params` | **L3** | | `transaction_send` | Broadcast a signed transaction | `chain`, `signed_tx` | **L3** | ### Ops | Tool | Description | Key params | Risk | | ----------------- | ----------------------------------------------- | ----------------------- | ---- | | `webhooks_manage` | Manage webhook endpoints (list, create, delete) | `action`, endpoint spec | L1 | | `blockchain_info` | Supported chains and DEX protocols | — | L0 | KYT / compliance is not wrapped as an outcome tool — call the REST API directly under `/v1/kyt/*`. See [KYT concepts](/en/docs/compliance/kyt-concepts). ## Playground tools (REST-parity) The Playground surface mirrors the REST API 1:1 as MCP tools. Every tool accepts the same JSON parameters as the corresponding REST endpoint and returns a `content[0].text` JSON string with the raw response. Use these when you want programmatic parity with REST but routed through MCP. `getBlockchainList`, `getBlockchainLatestBlock` `getToken`, `getTokens`, `searchTokens`, `getTokenMetadata`, `getTokensMetadata`, `getTokenLiquidityPools`, `getTokenStats`, `getTokensStats`, `getTokenHolders`, `getTokenHoldersMulti`, `getTokenCandles`, `getTokenTopHolders`, `getTokenMarketData`, `getTokensMarketData`, `getTokenPrices`, `getTokenPriceByTime`, `getTokenCreation`, `getTokenMintBurn`, `getTokenSecurity`, `getTokenListFiltered`, `getDevTokens`, `getTokenTraders`, `getTokenLiquiditySnapshots`, `getTokenTransfers`, `getTokenTransferTotal`, `getPairCandles`, `getPoolCandles` `getTokensBalance`, `getPnl`, `getPnlDetails`, `getPnlByToken`, `getPnlByWallet`, `calculatePnl`, `getNetWorth`, `getNetWorthDetails`, `getNetWorthChart`, `getNetWorthByTokens`, `getNetWorthSummary`, `getBalanceUpdates`, `getWalletTransfers`, `getWalletTransferTotal`, `getWalletFirstTx` `getTradeList`, `getTradeTopTraders`, `getTradeGainersLosers`, `getTradeActivityList` `getHotTokens`, `getRankingNewTokens`, `getRankingStocksTokens`, `getRankingFinalStretchTokens`, `getRankingMigratedTokens` `getDexpoolDetail`, `getDexpoolSnapshots` `getDexList`, `getQuote`, `getRoute`, `swap`, `createToken` `pumpfunCreateToken`, `moonshotCreateToken` `sendTransaction`, `getGasPrice`, `estimateGasLimit` `registerTransfer`, `getTransferSummary`, `getTransferAlerts`, `getTransferDirectExposure`, `getTransferNetworkIdentifications`, `registerWithdrawal`, `getWithdrawalSummary`, `getWithdrawalAlerts`, `getWithdrawalDirectExposure`, `getWithdrawalFraudAssessment`, `getWithdrawalAddressIdentifications`, `getWithdrawalNetworkIdentifications`, `registerAddress`, `getAddressRisk` `listEndpoints`, `createEndpoint`, `getEndpoint`, `updateEndpoint`, `deleteEndpoint`, `getEndpointSecret`, `rotateEndpointSecret` `getRedpacketCreate`, `getRedpacketClaim`, `getRedpacketGet`, `getRedpacketGetClaims`, `getRedpacketGetList`, `getRedpacketGetClaimsByAddress`, `getRedpacketGetByAddress`, `getRedpacketSend` `watchlistAdd` `presign` For the canonical input/output schema of each Playground tool, see the matching REST endpoint in the [API Reference](/en/api-reference/overview) — the JSON shapes are identical. ## Example client config ```json theme={null} { "mcpServers": { "chainstream": { "url": "https://mcp.chainstream.io/mcp", "headers": { "X-API-KEY": "" } } } } ``` ```json theme={null} { "mcpServers": { "chainstream": { "url": "https://mcp.chainstream.io/mcp", "transport": "streamable-http", "headers": { "X-API-KEY": "" } } } } ``` ## Next What MCP is and how ChainStream exposes it. Wiring the server into Cursor, Claude Desktop and others. Pay-per-call authentication for autonomous agents. Higher-level SKILL.md packages layered on top of MCP and the CLI. # Billing & Credits Source: https://docs.chainstream.io/en/graphql/billing/graphql-billing Understand how GraphQL API queries are billed using the Credit Unit system ## Overview Every GraphQL query consumes **Credit Units (CU)** that are dynamically calculated based on the query's complexity. Credits are deducted from the same billing plan as the REST API — your API Key works across both. The GraphQL API shares the same API Key and billing plan as the REST Data API. Credits consumed by GraphQL queries count toward your overall usage. *** ## Credit Calculation Formula Credits are calculated per Cube using a **5-factor formula**. The final CU depends on what you query, how many rows you request, whether you use aggregation, how many metrics you include, and how many fields you select. ``` CU = ceil(BaseCost × LimitFactor × AggregationFactor × MetricFactor × ComplexityFactor) / 100 ``` | Factor | Calculation | Description | | :-------------------- | :-------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------- | | **BaseCost** | Per-Cube internal value | Reflects the underlying table size and scan cost. Each Cube has a different base cost. | | **LimitFactor** | `ceil(limit / 100)`, minimum 1 | Scales linearly with the number of rows requested. Requesting 1–100 rows costs the same; 101–200 costs 2×, etc. | | **AggregationFactor** | 1.0 (none), 1.5 (GROUP BY), 2.0 (HAVING) | Higher for queries that use aggregation or post-aggregation filters (`selectWhere`). | | **MetricFactor** | `1.0 + (aggregate_count × 0.1)` | Each additional aggregation function (`count`, `sum`, `avg`, etc.) adds 10% to the cost. | | **ComplexityFactor** | `min(1.0 + min(select_count, 250) / 50 × 0.2, 1.5)` | Selecting more fields increases cost, capped at 1.5×. A simple query with \~5 fields has a factor of \~1.02. | **Zero-row queries are free.** If a query returns no rows, no credits are charged regardless of the other factors. ### Calculation Examples ``` BaseCost = 2000 (internal), LimitFactor = ceil(10/100) = 1 AggregationFactor = 1.0, MetricFactor = 1.0 ComplexityFactor = 1.0 + (5/50) × 0.2 = 1.02 Internal = ceil(2000 × 1 × 1.0 × 1.0 × 1.02) = 2040 CU = 2040 / 100 = 20.40 CU ``` ``` BaseCost = 2000, LimitFactor = ceil(500/100) = 5 AggregationFactor = 1.0, MetricFactor = 1.0 ComplexityFactor = 1.02 Internal = ceil(2000 × 5 × 1.0 × 1.0 × 1.02) = 10200 CU = 10200 / 100 = 102.00 CU ``` ``` BaseCost = 2000, LimitFactor = ceil(500/100) = 5 AggregationFactor = 1.5 (GROUP BY) MetricFactor = 1.0 + 2 × 0.1 = 1.2 ComplexityFactor = 1.02 Internal = ceil(2000 × 5 × 1.5 × 1.2 × 1.02) = 18360 CU = 18360 / 100 = 183.60 CU ``` ``` BaseCost = 2000, LimitFactor = 1 AggregationFactor = 1.0, MetricFactor = 1.0 ComplexityFactor = min(1.0 + (250/50) × 0.2, 1.5) = 1.5 (capped) Internal = ceil(2000 × 1 × 1.0 × 1.0 × 1.5) = 3000 CU = 3000 / 100 = 30.00 CU ``` Since CU is dynamically calculated, the best way to know the exact cost of a query is to check the `extensions.credits` field in the response, or monitor the CU indicator in the IDE status bar. *** ## Response: `extensions.credits` Every GraphQL response includes credit consumption details in the `extensions` field: ```json theme={null} { "data": { "Solana": { "DEXTrades": [ ... ] } }, "extensions": { "credits": { "total": 20.4, "unit": "CU", "cubes": [ { "cube": "DEXTrades", "credits": 20.4, "row_count": 10 } ] } } } ``` | Field | Type | Description | | :------------------ | :------- | :-------------------------------------- | | `total` | `Float` | Total CU consumed by the entire query | | `unit` | `String` | Always `"CU"` | | `cubes` | `Array` | Per-Cube breakdown | | `cubes[].cube` | `String` | Cube name as used by the billing engine | | `cubes[].credits` | `Float` | CU charged for this Cube | | `cubes[].row_count` | `Int` | Number of rows returned | The `extensions.credits` field is present when credits are consumed (i.e., `total > 0`). Queries that return zero rows are not charged. *** ## Monitoring Usage in the IDE The [GraphQL IDE](https://ide.chainstream.io) status bar displays credit consumption after each query: * **CU indicator**: Displays the total CU consumed * **Latency**: Request duration in milliseconds * **Response size**: Payload size *** ## Tips for Optimizing Credit Usage Only request the dimensions you need. The ComplexityFactor increases with the number of selected fields. Keep `limit.count` as low as practical. The LimitFactor doubles for every 100 additional rows. For aggregated data, prefer DWM/DWS Cubes (Pairs, Tokens, TokenHolders) over running metrics on DWD Cubes (DEXTrades). *** ## Related Documentation Overview of ChainStream billing plans, unit quotas, and payment methods. Learn how aggregation metrics affect query credits. # Balances & Holders Source: https://docs.chainstream.io/en/graphql/examples/balance-holders Query examples for wallet balances, balance history, and token holders This page covers four Cubes for wallet and holder analytics: * **BalanceUpdates** (DWD) — per-event balance changes for a wallet * **TokenHolders** (DWS) — current holder snapshots for a token * **WalletTokenPnL** (DWS) — per-token profit & loss for a wallet All examples below use `network: sol` (Solana). Replace with `eth`, `bsc`, or `polygon` for other supported chains. *** ## How do I get a wallet's token balances? Get current token balances for a wallet. This query returns the latest balance update event for each token the wallet holds. ```graphql theme={null} query { Solana { BalanceUpdates( limit: {count: 50} ownerAddress: {is: "WALLET_ADDRESS"} ) { BalanceUpdate { Currency { MintAddress } Account { Owner } PostBalance PostBalanceInUSD } Block { Time } } } } ``` [Open in GraphQL IDE](https://ide.chainstream.io) — paste the query above to run it interactively with auto-complete and schema exploration. Replace `WALLET_ADDRESS` with the wallet you want to inspect. The `ownerAddress` selector filters balance update events by wallet owner. | Field | Description | | :----------------------------------- | :------------------------------ | | `BalanceUpdate.Currency.MintAddress` | Token address | | `BalanceUpdate.Account.Owner` | Wallet owner address | | `BalanceUpdate.PostBalance` | Token balance after the update | | `BalanceUpdate.PostBalanceInUSD` | Balance value in USD | | `Block.Time` | Timestamp of the balance update | * **Increase limit**: Set `count: 200` to retrieve more tokens (wallets with many holdings) * **Filter by value**: Add `where: {BalanceUpdate: {PostBalanceInUSD: {gt: 1}}}` to exclude dust balances *** ## How do I get balance change history? Track how a wallet's balance for a specific token changes over time. ```graphql theme={null} query { Solana { BalanceUpdates( limit: {count: 20} ownerAddress: {is: "WALLET_ADDRESS"} tokenAddress: {is: "TOKEN_ADDRESS"} orderBy: {descending: Block_Time} ) { BalanceUpdate { PreBalance PostBalance PostBalanceInUSD } Block { Time } Transaction { Hash } } } } ``` | Field | Description | | :------------------------------- | :--------------------------------- | | `BalanceUpdate.PreBalance` | Balance before the event | | `BalanceUpdate.PostBalance` | Balance after the event | | `BalanceUpdate.PostBalanceInUSD` | Post-balance value in USD | | `Block.Time` | When the balance changed | | `Transaction.Hash` | Transaction that caused the change | * **Detect accumulation**: Compare `PreBalance` and `PostBalance` — when `PostBalance > PreBalance`, the wallet is accumulating * **Time range**: Add `where: {Block: {Time: {since: "2025-03-01T00:00:00Z"}}}` to scope to a specific period * **Larger history**: Increase `count` to up to `10000` for comprehensive balance history The difference between `PostBalance` and `PreBalance` shows the net change per event. A positive delta means tokens flowed in; a negative delta means tokens flowed out. *** ## How do I get a token's top holders? Get the top holders for a token, ranked by balance. ```graphql theme={null} query { Solana { TokenHolders( limit: {count: 100} tokenAddress: {is: "TOKEN_ADDRESS"} ) { Token { Address } Holder { Address } LatestBalance LatestBalanceUSD FirstSeen LastSeen } } } ``` | Field | Description | | :----------------- | :------------------------------------------- | | `Token.Address` | Token address | | `Holder.Address` | Holder wallet address | | `LatestBalance` | Current token balance | | `LatestBalanceUSD` | Current balance in USD | | `FirstSeen` | When this holder first acquired the token | | `LastSeen` | Most recent transaction involving this token | * **Whale threshold**: Add `where: {LatestBalanceUSD: {gt: 10000}}` to only show large holders * **Active holders**: Add `where: {LastSeen: {after: "2025-03-01T00:00:00Z"}}` to filter to recently active holders * **Holder count**: Use `count` metric to get the total number of holders The **TokenHolders** Cube is a DWS (Summary) layer table — it's pre-aggregated and much faster to query than scanning individual balance updates. Use it for holder rankings and distribution analysis. *** ## How do I get wallet profit and loss? Get per-token profit and loss data for a wallet, including buy/sell volumes and trade counts. ```graphql theme={null} query { Solana { WalletTokenPnL( limit: {count: 20} walletAddress: {is: "WALLET_ADDRESS"} ) { Wallet { Address } Token { Address } BuyVolumeUSDState SellVolumeUSDState BuyCountState SellCountState FirstTradeState LastTradeState } } } ``` | Field | Description | | :------------------- | :------------------------------------ | | `Wallet.Address` | Wallet address | | `Token.Address` | Token address | | `BuyVolumeUSDState` | Total USD spent buying this token | | `SellVolumeUSDState` | Total USD received selling this token | | `BuyCountState` | Number of buy trades | | `SellCountState` | Number of sell trades | | `FirstTradeState` | Timestamp of the first trade | | `LastTradeState` | Timestamp of the most recent trade | * **Calculate PnL**: `SellVolumeUSDState - BuyVolumeUSDState` gives the realized PnL for each token * **Active positions**: Filter for tokens where `SellCountState < BuyCountState` to find tokens the wallet is still holding * **High-activity tokens**: Sort by `BuyCountState` or `SellCountState` to find the most frequently traded tokens The **WalletTokenPnL** Cube uses the `walletAddress` selector (not `ownerAddress`). It provides cumulative trading metrics — ideal for portfolio analysis and performance leaderboards. *** ## Multi-Chain Examples ```graphql theme={null} query { Solana { BalanceUpdates( limit: {count: 10} ownerAddress: {is: "WALLET_ADDRESS"} ) { BalanceUpdate { Currency { MintAddress } PostBalance PostBalanceInUSD } } } } ``` ```graphql theme={null} query { EVM(network: eth) { BalanceUpdates( limit: {count: 10} ownerAddress: {is: "WALLET_ADDRESS"} ) { BalanceUpdate { Currency { MintAddress } PostBalance PostBalanceInUSD } } } } ``` ```graphql theme={null} query { EVM(network: bsc) { BalanceUpdates( limit: {count: 10} ownerAddress: {is: "WALLET_ADDRESS"} ) { BalanceUpdate { Currency { MintAddress } PostBalance PostBalanceInUSD } } } } ``` ```graphql theme={null} query { EVM(network: polygon) { BalanceUpdates( limit: {count: 10} ownerAddress: {is: "WALLET_ADDRESS"} ) { BalanceUpdate { Currency { MintAddress } PostBalance PostBalanceInUSD } } } } ``` *** ## Next Steps Query DEX trading data — token trades, wallet activity, and top traders. Track on-chain token transfers between wallets. Explore DEX pool and liquidity data. Fetch candlestick data, trade stats, TokenSupplyUpdates, and token metadata. # Blocks & Transactions Source: https://docs.chainstream.io/en/graphql/examples/blocks-transactions Query examples for Blocks, Transactions, Events, Calls, and other infrastructure Cubes ## Overview This page covers query examples for blockchain infrastructure Cubes — the foundational data about blocks, transactions, smart contract events, and internal traces. *** ## Blocks ### Latest Blocks (Solana) ```graphql theme={null} query { Solana { Blocks(limit: {count: 10}, orderBy: {descending: Block_Time}) { Block { Time Slot Height Hash ParentSlot TxCount } } } } ``` ### Latest Blocks (Ethereum) ```graphql theme={null} query { EVM(network: eth) { Blocks(limit: {count: 10}, orderBy: {descending: Block_Time}) { Block { Time Number Hash GasUsed GasLimit BaseFee TxCount Coinbase } } } } ``` *** ## Transactions ### Recent Transactions by Address (Solana) ```graphql theme={null} query { Solana { Transactions( signer: {is: "WALLET_ADDRESS"} limit: {count: 20} orderBy: {descending: Block_Time} ) { Block { Time Slot } Transaction { Signature Fee FeePayer Result { Success } } } } } ``` ### Recent Transactions by Address (EVM) ```graphql theme={null} query { EVM(network: eth) { Transactions( fromAddress: {is: "0xWALLET_ADDRESS"} limit: {count: 20} orderBy: {descending: Block_Time} ) { Block { Time Number } Transaction { Hash From To Value Gas GasPrice } } } } ``` *** ## Events (EVM Only) ### Filter Events by Contract and Topic ```graphql theme={null} query { EVM(network: eth) { Events( contractAddress: {is: "0xCONTRACT_ADDRESS"} limit: {count: 20} orderBy: {descending: Block_Time} ) { Block { Time Number } Transaction { Hash } Log { SmartContract Index Signature { Name Signature } Data } } } } ``` ### Filter by Event Signature (Topic0) ```graphql theme={null} query { EVM(network: eth) { Events( topic0: {is: "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"} limit: {count: 10} orderBy: {descending: Block_Time} ) { Block { Time } Transaction { Hash } Log { SmartContract Index Data } } } } ``` *** ## Calls / Traces (EVM Only) ### Internal Calls to a Contract ```graphql theme={null} query { EVM(network: eth) { Calls( toAddress: {is: "0xCONTRACT_ADDRESS"} limit: {count: 20} orderBy: {descending: Block_Time} ) { Block { Time Number } Transaction { Hash } Call { From To Opcode Value Gas GasUsed Signature { Name } } } } } ``` *** ## Instructions (Solana Only) ### Recent Instructions for a Program ```graphql theme={null} query { Solana { Instructions( programId: {is: "PROGRAM_ADDRESS"} limit: {count: 20} orderBy: {descending: Block_Time} ) { Block { Time Slot } Transaction { Signature } Instruction { Index Depth Program { Address Name Method } Accounts } } } } ``` *** ## Rewards (Solana Only) ### Staking Rewards for a Validator ```graphql theme={null} query { Solana { Rewards( address: {is: "VALIDATOR_ADDRESS"} limit: {count: 50} orderBy: {descending: Block_Time} ) { Block { Time Slot } Reward { Address Amount AmountInUSD PostBalance RewardType Commission } } } } ``` *** ## Miner Rewards (EVM Only) ### Block Reward Breakdown ```graphql theme={null} query { EVM(network: eth) { MinerRewards( limit: {count: 20} orderBy: {descending: Block_Time} ) { Block { Time Number } Reward { Miner TotalReward TotalRewardInUSD StaticReward DynamicReward TxFees BurntFees } } } } ``` *** ## Related Documentation Detailed field structures for all Cubes including Blocks, Transactions, Events, and Calls. Understand which Cubes are available for EVM vs Solana. # DEX Trades Source: https://docs.chainstream.io/en/graphql/examples/dex-trades Query examples for DEX trading data The **DEXTrades** Cube contains per-trade DEX swap events — the most granular trading data available. Use it to query individual trades, analyze wallet activity, track token prices, and find top traders. All examples below use `network: sol` (Solana). Replace with `eth`, `bsc`, or `polygon` for other supported chains. *** ## How do I get the latest DEX trades? Fetch the 10 most recent DEX trades on Solana, including block info, transaction hash, buy/sell details, and the DEX protocol. ```graphql theme={null} query { Solana { DEXTrades( limit: {count: 10} orderBy: {descending: Block_Time} ) { Block { Time, Slot } Transaction { Hash } Trade { Buy { Currency { MintAddress } Amount PriceInUSD Account { Owner } } Sell { Currency { MintAddress } Amount Account { Owner } } Dex { ProgramAddress, ProtocolName } } Pool { Address } } } } ``` [Open in GraphQL IDE](https://ide.chainstream.io) — paste the query above to run it interactively with auto-complete and schema exploration. | Field | Description | | :------------------------------- | :-------------------------------------------------------------------- | | `Block.Time` | Block timestamp (ISO 8601) | | `Block.Slot` | Solana slot number (Solana-specific) | | `Transaction.Hash` | On-chain transaction hash — use this to look up the tx on an explorer | | `Trade.Buy.Currency.MintAddress` | Token address of the bought asset | | `Trade.Buy.PriceInUSD` | USD price of the bought token at trade time | | `Trade.Buy.Account.Owner` | Buyer wallet address | | `Trade.Dex.ProtocolName` | DEX name (e.g. Raydium, Orca, Jupiter) | | `Pool.Address` | Liquidity pool address where the trade executed | * **Switch chain**: Replace `network: sol` with `network: eth`, `network: bsc`, or `network: polygon` * **Increase results**: Change `count: 10` to up to `10000` * **Add time filter**: Add `where: {Block: {Time: {after: "2025-03-01T00:00:00Z"}}}` to scope to a time range * **Filter by DEX**: Add `where: {Trade: {Dex: {ProtocolName: {is: "Raydium"}}}}` to limit to a specific protocol *** ## How do I get trades for a specific token? Get trades for a specific token by passing its address via the `tokenAddress` selector. ```graphql theme={null} query { Solana { DEXTrades( limit: {count: 10} tokenAddress: {is: "TOKEN_ADDRESS"} orderBy: {descending: Block_Time} ) { Block { Time } Trade { Buy { Amount, PriceInUSD, Account { Owner } } Sell { Currency { MintAddress }, Amount } Dex { ProtocolName } } Pool { Address } } } } ``` Replace `TOKEN_ADDRESS` with the actual token mint address (e.g. `EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v` for USDC on Solana). See [token metadata](/en/graphql/examples/ohlc-stats#how-do-i-look-up-token-information) to look up addresses by name. | Field | Description | | :-------------------------------- | :----------------------------------------------------------- | | `Trade.Buy.Amount` | Quantity of tokens bought | | `Trade.Buy.PriceInUSD` | Price per token at trade time | | `Trade.Buy.Account.Owner` | Wallet that executed the buy | | `Trade.Sell.Currency.MintAddress` | Token address of the sold asset (the other side of the pair) | | `Trade.Dex.ProtocolName` | DEX protocol name | * **Filter by minimum amount**: Add `where: {Trade: {Buy: {Amount: {gt: 1000}}}}` to only see large trades * **Filter by price range**: Add `where: {Trade: {Buy: {PriceInUSD: {gte: 0.001, lte: 1.0}}}}` to scope to a price band * **Exclude suspect trades**: The `IsSuspect = false` filter is applied by default — bot/MEV trades are already excluded *** ## How do I get all trades by a wallet? Get all trades by a specific wallet address. ```graphql theme={null} query { Solana { DEXTrades( limit: {count: 20} walletAddress: {is: "WALLET_ADDRESS"} orderBy: {descending: Block_Time} ) { Block { Time } Trade { Buy { Currency { MintAddress }, Amount, PriceInUSD } Sell { Currency { MintAddress }, Amount } Dex { ProtocolName } } Transaction { Hash, FeeInNative } } } } ``` The `walletAddress` selector matches trades where the given wallet is either the buyer or the seller. | Field | Description | | :-------------------------------- | :-------------------------------------- | | `Trade.Buy.Currency.MintAddress` | Token bought | | `Trade.Sell.Currency.MintAddress` | Token sold | | `Transaction.FeeInNative` | Gas fee in native token (SOL on Solana) | * **Filter to a single token**: Combine with `tokenAddress: {is: "TOKEN_ADDRESS"}` to see only trades for a specific token by this wallet * **Add time window**: Add `where: {Block: {Time: {after: "2025-03-01T00:00:00Z"}}}` to limit to recent trades * **Increase limit**: Set `count: 100` to retrieve more history (max 10,000) *** ## How do I get a token's current price? Get the latest price for a token from its most recent non-suspect trade. ```graphql theme={null} query { Solana { DEXTrades( limit: {count: 1} tokenAddress: {is: "TOKEN_ADDRESS"} where: {IsSuspect: {eq: false}} orderBy: {descending: Block_Time} ) { Trade { Buy { PriceInUSD, PriceInNative } } Block { Time } } } } ``` | Field | Description | | :------------------------ | :------------------------------------------------------------ | | `Trade.Buy.PriceInUSD` | USD price from the most recent trade | | `Trade.Buy.PriceInNative` | Price denominated in the chain's native token (SOL, ETH, BNB) | | `Block.Time` | Timestamp of the trade — indicates how recent the price is | * **Multiple prices**: Increase `count` to get a series of recent prices for averaging * **Cross-chain**: Use `network: eth` to get the same token's price on Ethereum (if it exists on that chain) For reliable token price data over time, consider using the [Pairs](/en/graphql/examples/ohlc-stats#how-do-i-get-k-line-ohlc-candlestick-data) Cube instead — it provides pre-computed candlestick data with open/high/low/close prices per minute. *** ## How do I find the top traders for a token? Find the top traders for a token using aggregation. This query groups trades by buyer wallet and returns the total buy count and volume. ```graphql theme={null} query { Solana { DEXTrades( limit: {count: 100} tokenAddress: {is: "TOKEN_ADDRESS"} where: {IsSuspect: {eq: false}} ) { Trade { Buy { Account { Owner } Amount PriceInUSD } } count sum(of: Trade_Buy_Amount) } } } ``` | Field | Description | | :-------------------------- | :--------------------------------- | | `Trade.Buy.Account.Owner` | Wallet address (grouping key) | | `count` | Number of trades by this wallet | | `sum(of: Trade_Buy_Amount)` | Total tokens bought by this wallet | * **Sort by volume**: The results are grouped by the dimension fields — select fewer dimensions for higher-level aggregation * **Time-scoped leaderboard**: Add `where: {Block: {Time: {after: "2025-03-01T00:00:00Z"}}}` to limit to a specific period * **Exclude small trades**: Add `Trade: {Buy: {Amount: {gt: 100}}}` to the `where` clause When you include metric fields (`count`, `sum`) alongside dimension fields, the API automatically groups results by the selected dimensions. See [Metrics & Aggregation](/en/graphql/schema/metrics-aggregation) for full details. *** ## Multi-Chain Examples The same queries work across all supported chains — just change the `network` parameter. ```graphql theme={null} query { Solana { DEXTrades( limit: {count: 5} orderBy: {descending: Block_Time} ) { Block { Time, Slot } Trade { Buy { Currency { MintAddress }, PriceInUSD } Dex { ProtocolName } } } } } ``` ```graphql theme={null} query { EVM(network: eth) { DEXTrades( limit: {count: 5} orderBy: {descending: Block_Time} ) { Block { Time, Height } Trade { Buy { Currency { MintAddress }, PriceInUSD } Dex { ProtocolName } } } } } ``` ```graphql theme={null} query { EVM(network: bsc) { DEXTrades( limit: {count: 5} orderBy: {descending: Block_Time} ) { Block { Time, Height } Trade { Buy { Currency { MintAddress }, PriceInUSD } Dex { ProtocolName } } } } } ``` *** ## Next Steps Query on-chain token transfer data. Look up wallet balances, balance history, and top holders. Explore DEX pools and liquidity data. Fetch candlestick data, trade stats, market cap, and token metadata. # OHLC & Statistics Source: https://docs.chainstream.io/en/graphql/examples/ohlc-stats Query examples for K-line data (Pairs), per-token trade statistics (Tokens), supply and valuation (TokenSupplyUpdates), and where to find token metadata This page covers aggregated trading and supply data. The **cube names** are **Pairs** and **Tokens** in the **Trading** chain group (cross-chain OHLC and trade stats). Market cap and price snapshots over time come from **TokenSupplyUpdates** under **Solana** or **EVM**. * **Pairs** (Trading, DWM) — per-minute candlestick / K-line data (OHLC, volume, trade count) * **Tokens** (Trading, DWM) — per-minute trade statistics with buy/sell breakdown and unique traders * **TokenSupplyUpdates** (Solana / EVM, DWD) — mint/burn events with supply, price, market cap, and FDV fields * **Token metadata** — there is no separate **TokenSearch** cube; use **Token** (and related) dimensions on **Pairs** / **Tokens**, or other cubes such as **DEXPools**, **TokenHolders**, and **DEXTradeByTokens** for discovery and screening **Trading** has **no** `network` argument. Filter by chain with `where: { Market: { Network: { is: "sol" } } }` (or `eth`, `bsc`, `polygon`). **Solana** and **EVM** groups use their usual wrappers (`Solana { ... }`, `EVM(network: eth) { ... }`). *** ## How do I get K-line (OHLC) candlestick data? Fetch candlestick data for a token — open, high, low, close prices per minute, plus USD volume and trade count. Use the **Pairs** cube inside **Trading**. ```graphql theme={null} query { Trading { Pairs( tokenAddress: { is: "TOKEN_ADDRESS" } where: { Market: { Network: { is: "sol" } } } limit: { count: 24 } orderBy: { descending: Block_Time } ) { Interval { Time { Start } } Token { Address } Market { Network } Price { Ohlc { Open High Low Close } } Volume { Usd } Stats { TradeCount } } } } ``` [Open in GraphQL IDE](https://ide.chainstream.io) — paste the query above to run it interactively with auto-complete and schema exploration. Replace `TOKEN_ADDRESS` with the token mint or contract address. Each row is one minute bucket — use `limit: { count: 60 }` for about one hour, `count: 1440` for about 24 hours. Omit the `Market` filter to query across all chains in one result set. | Field | Description | | :-------------------- | :---------------------------------------- | | `Interval.Time.Start` | Minute-bucket start (same as candle time) | | `Token.Address` | Token address | | `Market.Network` | Chain identifier (`sol`, `eth`, `bsc`, …) | | `Price.Ohlc.Open` | Opening price for the interval | | `Price.Ohlc.High` | Highest price during the interval | | `Price.Ohlc.Low` | Lowest price during the interval | | `Price.Ohlc.Close` | Closing price for the interval | | `Volume.Usd` | Total USD volume in this interval | | `Stats.TradeCount` | Number of trades in this interval | * **Longer timeframes**: Request more rows with `limit`, or aggregate client-side; candles are stored at minute granularity * **Volume filter**: e.g. `where: { Volume: { Usd: { gt: 100 } }, Market: { Network: { is: "sol" } } }` to skip low-volume intervals * **Time range**: e.g. `where: { Block: { Time: { since: "2026-03-27T00:00:00Z" } }, Market: { Network: { is: "sol" } } }` The **Pairs** cube is a **DWM** (aggregated) model — data is pre-computed per minute. It is much faster than scanning raw trades for chart data. *** ## How do I get trade statistics for a token? Get per-minute trade statistics with buy/sell counts, unique buyer/seller counts, and volume. Use the **Tokens** cube inside **Trading**. ```graphql theme={null} query { Trading { Tokens( tokenAddress: { is: "TOKEN_ADDRESS" } where: { Market: { Network: { is: "sol" } } } limit: { count: 24 } orderBy: { descending: Block_Time } ) { Interval { Time { Start } } Token { Address } Market { Network } Stats { TradeCount BuyCount SellCount UniqueBuyers UniqueSellers } Volume { Usd } } } } ``` | Field | Description | | :-------------------- | :---------------------------------------- | | `Interval.Time.Start` | Minute-bucket start (same as candle time) | | `Stats.TradeCount` | Total trades in this interval | | `Stats.BuyCount` | Buy-side trades | | `Stats.SellCount` | Sell-side trades | | `Volume.Usd` | Total USD volume | | `Stats.UniqueBuyers` | Distinct buyer wallets | | `Stats.UniqueSellers` | Distinct seller wallets | * **Buy/sell pressure**: Compare `Stats.BuyCount` vs `Stats.SellCount` * **Unique traders**: `Stats.UniqueBuyers` and `Stats.UniqueSellers` show whether volume is broad or concentrated * **Activity heatmap**: Query a full day (`count: 1440`) and chart by `Interval.Time.Start` (or `Block.Time`) * **Buy/sell volume**: The **Tokens** record also exposes `Volume.BuyVolumeUSD` and `Volume.SellVolumeUSD` when you need USD split Combine **Pairs** and **Tokens** for the same token, chain, and time window to build dashboards — OHLC alongside flow and participant metrics. *** ## How do I get market cap, price, and supply over time? The legacy **TokenMarketCap** summary cube is not used in the current schema. Use **TokenSupplyUpdates** (Solana or EVM): each row reflects a supply-affecting event with **TokenSupplyUpdate** metrics including price, market cap, FDV, and total supply. ### Solana ```graphql theme={null} query { Solana { TokenSupplyUpdates( tokenAddress: { is: "TOKEN_ADDRESS" } limit: { count: 24 } orderBy: { descending: Block_Time } ) { Block { Time } TokenSupplyUpdate { Currency { MintAddress Decimals Symbol Name } PriceInUSD MarketCapInUSD TotalSupply FDVInUSD PostBalance } Transaction { Signature } } } } ``` ### EVM (Ethereum example) ```graphql theme={null} query { EVM(network: eth) { TokenSupplyUpdates( tokenAddress: { is: "TOKEN_ADDRESS" } limit: { count: 24 } orderBy: { descending: Block_Time } ) { Block { Time } TokenSupplyUpdate { Currency { MintAddress Decimals Symbol Name } PriceInUSD MarketCapInUSD TotalSupply FDVInUSD PostBalance } Transaction { Hash } } } } ``` | Field | Description | | :--------------------------------- | :----------------------------------------------------- | | `Block.Time` | Event time | | `TokenSupplyUpdate.Currency.*` | Token identity (mint/contract, decimals, symbol, name) | | `TokenSupplyUpdate.PriceInUSD` | Price in USD at this update | | `TokenSupplyUpdate.MarketCapInUSD` | Market capitalization | | `TokenSupplyUpdate.TotalSupply` | Total supply | | `TokenSupplyUpdate.FDVInUSD` | Fully diluted valuation | | `TokenSupplyUpdate.PostBalance` | Supply-related balance after the event | * **Latest snapshot**: `limit: { count: 1 }` with `orderBy: { descending: Block_Time }` * **Compare chains**: Run the same shape under `Solana` and `EVM(network: bsc)` (or other supported networks) * **More context**: See also [Pools & Liquidity](/en/graphql/examples/pools-liquidity#how-do-i-get-token-supply-and-market-cap) for supply and pool-related examples **TokenSupplyUpdates** is **DWD** (event-level). It is the right place for historical valuation and supply changes tied to mint/burn activity, rather than a single static “market cap” summary row. *** ## Where is token search / metadata? The **TokenSearch** cube is **not** part of the current API. For token context: * **Pairs** and **Tokens** expose **Token** dimensions (e.g. **Token.Address**) alongside OHLC and stats — use them when you already know the address and want aggregated trading data. * For richer metadata, holder counts, pools, or discovery, use cubes such as **DEXPools**, **TokenHolders**, or **DEXTradeByTokens** under **Solana** or **EVM**, depending on your chain. *** ## Multi-Chain Examples ```graphql theme={null} query { Trading { Pairs( tokenAddress: { is: "TOKEN_ADDRESS" } where: { Market: { Network: { is: "sol" } } } limit: { count: 10 } orderBy: { descending: Block_Time } ) { Interval { Time { Start } } Price { Ohlc { Open Close } } Volume { Usd } } } } ``` ```graphql theme={null} query { Trading { Pairs( tokenAddress: { is: "TOKEN_ADDRESS" } where: { Market: { Network: { is: "eth" } } } limit: { count: 10 } orderBy: { descending: Block_Time } ) { Interval { Time { Start } } Price { Ohlc { Open Close } } Volume { Usd } } } } ``` ```graphql theme={null} query { Trading { Pairs( tokenAddress: { is: "TOKEN_ADDRESS" } where: { Market: { Network: { is: "bsc" } } } limit: { count: 10 } orderBy: { descending: Block_Time } ) { Interval { Time { Start } } Price { Ohlc { Open Close } } Volume { Usd } } } } ``` *** ## Next Steps Query DEX trading data — token trades, wallet activity, and top traders. Track on-chain token transfers between wallets. Look up wallet balances, balance history, and top holders. Explore DEX pool and liquidity data. # Pools & Liquidity Source: https://docs.chainstream.io/en/graphql/examples/pools-liquidity Query examples for DEX pools and liquidity data This page covers Cubes for DEX pool and liquidity analysis: * **DEXPoolEvents** (DWD) — liquidity add/remove events with per-event reserves and prices * **DEXPools** (DWS) — pool **snapshots** (current liquidity and prices, refreshed periodically) * **TokenSupplyUpdates** (DWD) — token supply, market cap, and FDV updates Examples use the **Solana** and **EVM** [Chain Groups](/en/graphql/schema/chain-groups): `Solana { ... }` for Solana, `EVM(network: eth | bsc | polygon) { ... }` for EVM chains (including Polygon). *** ## How do I get liquidity pools for a token? Find DEX pools that list a token as **token A** in the snapshot. Pools where the asset appears only as token B need a second query with `tokenB` (or a `where` clause); for **event-level** rows with full pair context, use **DEXPoolEvents**. ```graphql theme={null} query { Solana { DEXPools( limit: {count: 10} tokenA: {is: "TOKEN_ADDRESS"} ) { Pool { Address ProgramAddress TokenAAddress TokenBAddress LiquidityUSD PriceAtoB PriceBtoA LastUpdated } } } } ``` [Open in GraphQL IDE](https://ide.chainstream.io) — paste the query above to run it interactively with auto-complete and schema exploration. Replace `TOKEN_ADDRESS` with the token mint (Solana) or contract address (EVM). Repeat with `tokenB: {is: "TOKEN_ADDRESS"}` to include pools where the token is the quote side. | Field | Description | | :-------------------- | :-------------------------------------- | | `Pool.Address` | Liquidity pool / market address | | `Pool.ProgramAddress` | DEX program or factory address | | `Pool.TokenAAddress` | Base-side token address | | `Pool.TokenBAddress` | Quote-side token address | | `Pool.LiquidityUSD` | Total pool liquidity in USD (snapshot) | | `Pool.LastUpdated` | When this snapshot row was last updated | * **Filter by liquidity**: Add `where: {Pool: {LiquidityUSD: {gt: 10000}}}` for pools above a USD depth threshold * **Specific DEX**: Add `where: {Pool: {ProgramAddress: {is: "DEX_PROGRAM_OR_FACTORY_ADDRESS"}}}` * **More pools**: Increase `count` to discover additional pools for the token * **Per-event reserves**: Use **DEXPoolEvents** with `tokenAddress` / `poolAddress` and `orderBy: {descending: Block_Time}` for add/remove history *** ## How do I get details of a specific pool? Read the **latest snapshot** for one pool by address. **DEXPools** does not expose a block timeline per row — use **DEXPoolEvents** for historical reserve series. ```graphql theme={null} query { Solana { DEXPools( limit: {count: 1} poolAddress: {is: "POOL_ADDRESS"} ) { Pool { Address TokenAAddress TokenBAddress ProgramAddress LiquidityUSD PriceAtoB PriceBtoA LastUpdated } } } } ``` | Field | Description | | :------------------------------------------ | :---------------------------------- | | `Pool.TokenAAddress` / `Pool.TokenBAddress` | Pair token addresses | | `Pool.LiquidityUSD` | Total liquidity in USD (snapshot) | | `Pool.LastUpdated` | Last snapshot refresh for this pool | * **Reserve history**: Query **DEXPoolEvents** with `poolAddress: {is: "POOL_ADDRESS"}` and `orderBy: {descending: Block_Time}` * **Time range on events**: On **DEXPoolEvents**, add `where: {Block: {Time: {since: "2025-03-01T00:00:00Z"}}}` to scope add/removes The `poolAddress` selector filters by `Pool.Address`. It is available on **DEXPools** (snapshot) and **DEXPoolEvents** (events). *** ## How do I rank pools or read snapshot liquidity? **DEXPools** (DWS) stores **current-state** rows (typically refreshed every few minutes). Use it to rank pools by `LiquidityUSD` and compare DEX programs without scanning raw events. ```graphql theme={null} query { Solana { DEXPools( limit: {count: 20} tokenA: {is: "TOKEN_ADDRESS"} ) { Pool { Address ProgramAddress TokenAAddress TokenBAddress LiquidityUSD LastUpdated } } } } ``` | Field | Description | | :------------------------------------------ | :------------------------ | | `Pool.Address` | Pool address | | `Pool.ProgramAddress` | DEX program / factory | | `Pool.TokenAAddress` / `Pool.TokenBAddress` | Pair tokens | | `Pool.LiquidityUSD` | Snapshot liquidity in USD | | `Pool.LastUpdated` | How fresh the snapshot is | * **Rank by liquidity**: Sort client-side by `LiquidityUSD`, or use `orderBy` if your schema exposes a pool snapshot ordering * **Active pools**: Prefer pools with recent `LastUpdated` * **Compare DEXes**: Group or filter by `Pool.ProgramAddress` **DEXPoolEvents** (DWD) is the right Cube for **time series** of reserves and every liquidity event. **DEXPools** (DWS) is optimized for **latest** pool state and discovery. *** ## How do I get token supply and market cap? Use **TokenSupplyUpdates** for supply, market cap, price, and FDV tied to supply events. ```graphql theme={null} query { Solana { TokenSupplyUpdates( limit: {count: 1} tokenAddress: {is: "TOKEN_ADDRESS"} orderBy: {descending: Block_Time} ) { TokenSupplyUpdate { Currency { MintAddress, Decimals } PostBalance MarketCapInUSD PriceInUSD FDVInUSD TotalSupply } Block { Time } } } } ``` | Field | Description | | :--------------------------------------- | :------------------------------------------ | | `TokenSupplyUpdate.Currency.MintAddress` | Token address | | `TokenSupplyUpdate.Currency.Decimals` | Token decimals | | `TokenSupplyUpdate.PostBalance` | Current supply after the event | | `TokenSupplyUpdate.MarketCapInUSD` | Market capitalization in USD | | `TokenSupplyUpdate.PriceInUSD` | Token price at the time of the supply event | | `TokenSupplyUpdate.FDVInUSD` | Fully diluted valuation | | `TokenSupplyUpdate.TotalSupply` | Total token supply | * **Supply history**: Increase `count` to see how supply changed over time (mint/burn events) * **Market cap history**: Query multiple supply updates to chart market cap over time * **Combined with price**: Use `PriceInUSD` alongside `TotalSupply` to verify market cap calculations This page uses **TokenSupplyUpdates** for supply-linked market cap, price, and FDV. For additional token metrics and summaries, see [OHLC & Statistics](/en/graphql/examples/ohlc-stats). *** ## Multi-Chain Examples ```graphql theme={null} query { Solana { DEXPools( limit: {count: 5} tokenA: {is: "TOKEN_ADDRESS"} ) { Pool { Address, LiquidityUSD, LastUpdated } } } } ``` ```graphql theme={null} query { EVM(network: eth) { DEXPools( limit: {count: 5} tokenA: {is: "TOKEN_ADDRESS"} ) { Pool { Address, LiquidityUSD, LastUpdated } } } } ``` ```graphql theme={null} query { EVM(network: bsc) { DEXPools( limit: {count: 5} tokenA: {is: "TOKEN_ADDRESS"} ) { Pool { Address, LiquidityUSD, LastUpdated } } } } ``` ```graphql theme={null} query { EVM(network: polygon) { DEXPools( limit: {count: 5} tokenA: {is: "TOKEN_ADDRESS"} ) { Pool { Address, LiquidityUSD, LastUpdated } } } } ``` *** ## Next Steps Query DEX trading data — token trades, wallet activity, and top traders. Track on-chain token transfers between wallets. Look up wallet balances, balance history, and top holders. Fetch candlestick data, trade stats, market cap, and token metadata. # Prediction Markets Source: https://docs.chainstream.io/en/graphql/examples/prediction-markets Query examples for PredictionTrades, PredictionManagements, and PredictionSettlements Cubes ## Overview ChainStream GraphQL provides three Cubes for prediction market data, primarily available on Polygon. These Cubes cover the full lifecycle of prediction markets — from creation and trading to settlement. Prediction Market Cubes are available in the **EVM** Chain Group. They are primarily used with `network: polygon`. *** ## PredictionTrades ### Recent Prediction Market Trades ```graphql theme={null} query { EVM(network: polygon) { PredictionTrades( limit: {count: 20} orderBy: {descending: Block_Time} ) { Block { Time } Transaction { Hash } Trade { Buyer Seller Amount Price Fee } Prediction { Condition { Id Outcomes } Question { Id } Outcome Marketplace { ProtocolName } } } } } ``` ### Trades for a Specific Condition ```graphql theme={null} query { EVM(network: polygon) { PredictionTrades( conditionId: {is: "CONDITION_ID"} limit: {count: 50} orderBy: {descending: Block_Time} ) { Block { Time } Trade { Buyer Seller Amount Price } Prediction { Outcome OutcomeToken { SmartContract } } } } } ``` ### Trade Volume by Marketplace ```graphql theme={null} query { EVM(network: polygon) { PredictionTrades( marketplace: {is: "Polymarket"} limit: {count: 100} orderBy: {descending: Block_Time} ) { Block { Time } Trade { Amount Price } Prediction { Question { Id } Marketplace { ProtocolName } } count sum(of: Trade_Amount) } } } ``` *** ## PredictionManagements ### Market Creation and Resolution Events ```graphql theme={null} query { EVM(network: polygon) { PredictionManagements( limit: {count: 20} orderBy: {descending: Block_Time} ) { Block { Time } Transaction { Hash } Management { EventType Description Group Prediction { Condition { Id } Question { Id } Marketplace { ProtocolName } } } } } } ``` ### Filter by Event Type ```graphql theme={null} query { EVM(network: polygon) { PredictionManagements( eventType: {is: "ConditionResolution"} limit: {count: 20} orderBy: {descending: Block_Time} ) { Block { Time } Management { EventType Description Prediction { Condition { Id Outcomes } } } } } } ``` *** ## PredictionSettlements ### Recent Settlements ```graphql theme={null} query { EVM(network: polygon) { PredictionSettlements( limit: {count: 20} orderBy: {descending: Block_Time} ) { Block { Time } Transaction { Hash } Settlement { EventType Holder OutcomeTokenIds Amounts Prediction { Condition { Id } CollateralToken { SmartContract Symbol } Marketplace { ProtocolName } } } } } } ``` ### Settlements for a Specific Holder ```graphql theme={null} query { EVM(network: polygon) { PredictionSettlements( holder: {is: "0xHOLDER_ADDRESS"} limit: {count: 50} orderBy: {descending: Block_Time} ) { Block { Time } Settlement { EventType Amounts Prediction { Condition { Id } } } } } } ``` *** ## Related Documentation Detailed field structures for Prediction Market Cubes. Prediction Cubes are EVM-only, primarily on Polygon. # Transfers Source: https://docs.chainstream.io/en/graphql/examples/transfers Query examples for on-chain transfer data The **Transfers** Cube contains on-chain token transfer events — every time tokens move from one wallet to another. Use it to track wallet activity, monitor whale movements, analyze token flows, and detect exchange deposits/withdrawals. All examples below use `network: sol` (Solana). Replace with `eth`, `bsc`, or `polygon` for other supported chains. *** ## How do I get the latest transfers? Fetch the 10 most recent token transfers on Solana, including sender, receiver, amount, and USD value. ```graphql theme={null} query { Solana { Transfers( limit: {count: 10} orderBy: {descending: Block_Time} ) { Block { Time } Transaction { Hash } Transfer { Currency { MintAddress } Sender { Address } Receiver { Address } Amount AmountInUSD } } } } ``` [Open in GraphQL IDE](https://ide.chainstream.io) — paste the query above to run it interactively with auto-complete and schema exploration. | Field | Description | | :------------------------------ | :------------------------------------------------ | | `Block.Time` | Block timestamp (ISO 8601) | | `Transaction.Hash` | On-chain transaction hash | | `Transfer.Currency.MintAddress` | Token address being transferred | | `Transfer.Sender.Address` | Wallet that sent the tokens | | `Transfer.Receiver.Address` | Wallet that received the tokens | | `Transfer.Amount` | Number of tokens transferred | | `Transfer.AmountInUSD` | USD value of the transfer at the time it occurred | * **Filter by token**: Add `tokenAddress: {is: "TOKEN_ADDRESS"}` to see only transfers of a specific token * **Large transfers only**: Add `where: {Transfer: {AmountInUSD: {gt: 10000}}}` to find whale movements * **Time range**: Add `where: {Block: {Time: {after: "2025-03-01T00:00:00Z"}}}` to scope to a period *** ## How do I get outgoing transfers from a wallet? Get outgoing transfers from a specific wallet using the `senderAddress` selector. ```graphql theme={null} query { Solana { Transfers( limit: {count: 20} senderAddress: {is: "WALLET_ADDRESS"} orderBy: {descending: Block_Time} ) { Block { Time } Transfer { Currency { MintAddress } Receiver { Address } Amount AmountInUSD } } } } ``` Replace `WALLET_ADDRESS` with the actual wallet address you want to investigate. | Field | Description | | :------------------------------ | :-------------------------------- | | `Transfer.Currency.MintAddress` | Which token was sent | | `Transfer.Receiver.Address` | Who received the tokens | | `Transfer.Amount` | How many tokens were sent | | `Transfer.AmountInUSD` | USD value at the time of transfer | * **Specific token only**: Add `tokenAddress: {is: "TOKEN_ADDRESS"}` to narrow down to one token * **Increase results**: Change `count: 20` to up to `10000` for deeper history * **Add receiver filter**: Use `where: {Transfer: {Receiver: {Address: {is: "RECEIVER_ADDRESS"}}}}` to trace transfers between two specific wallets *** ## How do I get incoming transfers to a wallet? Find incoming transfers to a wallet using the `receiverAddress` selector. ```graphql theme={null} query { Solana { Transfers( limit: {count: 20} receiverAddress: {is: "WALLET_ADDRESS"} orderBy: {descending: Block_Time} ) { Block { Time } Transfer { Currency { MintAddress } Sender { Address } Amount AmountInUSD } } } } ``` The Transfers Cube supports both `senderAddress` and `receiverAddress` selectors. Combine them with `where` for additional filtering (e.g., time range or minimum amount). *** ## How do I get all transfers of a specific token? Track all transfers of a specific token across the network. ```graphql theme={null} query { Solana { Transfers( limit: {count: 20} tokenAddress: {is: "TOKEN_ADDRESS"} orderBy: {descending: Block_Time} ) { Block { Time } Transaction { Hash } Transfer { Sender { Address } Receiver { Address } Amount AmountInUSD } } } } ``` * **Whale alerts**: Add `where: {Transfer: {AmountInUSD: {gt: 100000}}}` to only see large transfers (>\$100K) * **Exclude dust**: Add `where: {Transfer: {Amount: {gt: 0.01}}}` to filter out negligible amounts * **Time-bounded**: Combine with `where: {Block: {Time: {since: "2025-03-27T00:00:00Z"}}}` for today's transfers *** ## Multi-Chain Examples ```graphql theme={null} query { Solana { Transfers( limit: {count: 5} orderBy: {descending: Block_Time} ) { Block { Time } Transfer { Currency { MintAddress } Sender { Address } Receiver { Address } Amount } } } } ``` ```graphql theme={null} query { EVM(network: eth) { Transfers( limit: {count: 5} orderBy: {descending: Block_Time} ) { Block { Time } Transfer { Currency { MintAddress } Sender { Address } Receiver { Address } Amount } } } } ``` ```graphql theme={null} query { EVM(network: bsc) { Transfers( limit: {count: 5} orderBy: {descending: Block_Time} ) { Block { Time } Transfer { Currency { MintAddress } Sender { Address } Receiver { Address } Amount } } } } ``` ```graphql theme={null} query { EVM(network: polygon) { Transfers( limit: {count: 5} orderBy: {descending: Block_Time} ) { Block { Time } Transfer { Currency { MintAddress } Sender { Address } Receiver { Address } Amount } } } } ``` *** ## Next Steps Query DEX trading data — token trades, wallet activity, and top traders. Look up wallet balances, balance history, and top token holders. Explore DEX pool and liquidity data. Fetch candlestick data, trade stats, market cap, and token metadata. # Endpoints & Authentication Source: https://docs.chainstream.io/en/graphql/getting-started/endpoints GraphQL endpoint URL, authentication, request format, and supported networks ## GraphQL Endpoint All GraphQL queries are sent to a single endpoint: ``` https://graphql.chainstream.io/graphql ``` Both **POST** and **GET** methods are supported. | Method | Content-Type | Use Case | | :----- | :-------------------------- | :------------------------------------------------------------------- | | `POST` | `application/json` | Recommended for all queries — supports variables and complex queries | | `GET` | Query string (`?query=...`) | Simple queries, browser testing, caching-friendly | Use **POST** for production workloads. GET requests encode the query in the URL, which has length limits and makes complex queries unwieldy. *** ## Authentication Authenticate by passing your API Key in the `X-API-KEY` header. This is the same API Key used for the REST Data API — no separate credentials needed. ``` X-API-KEY: your_api_key ``` Get your API Key from [ChainStream Dashboard](https://www.chainstream.io/dashboard) → **Applications** → **Create New App**. The key starts with `cs_live_...`. ### Required Headers | Header | Value | Required | | :------------- | :----------------- | :--------- | | `Content-Type` | `application/json` | Yes (POST) | | `X-API-KEY` | `cs_live_...` | Yes | *** ## Request Format A GraphQL request body is a JSON object with two fields: | Field | Type | Description | | :---------- | :------- | :---------------------------------------------------------------- | | `query` | `string` | The GraphQL query or mutation string | | `variables` | `object` | Optional variables referenced in the query via `$variable` syntax | ### POST Example ```bash theme={null} curl -X POST "https://graphql.chainstream.io/graphql" \ -H "Content-Type: application/json" \ -H "X-API-KEY: your_api_key" \ -d '{ "query": "{ Solana { DEXTrades(limit: {count: 5}, orderBy: {descending: Block_Time}) { Block { Time } Trade { Buy { Currency { MintAddress } Amount } } } } }" }' ``` For complex queries, save the query to a file and reference it: ```bash theme={null} # Save query to file cat > query.graphql << 'EOF' { Solana { DEXTrades(limit: {count: 5}, orderBy: {descending: Block_Time}) { Block { Time } Trade { Buy { Currency { MintAddress } Amount } } } } } EOF # Send request curl -X POST "https://graphql.chainstream.io/graphql" \ -H "Content-Type: application/json" \ -H "X-API-KEY: your_api_key" \ -d "{\"query\": \"$(cat query.graphql | tr '\n' ' ')\"}" ``` ```javascript theme={null} const response = await fetch("https://graphql.chainstream.io/graphql", { method: "POST", headers: { "Content-Type": "application/json", "X-API-KEY": "your_api_key", }, body: JSON.stringify({ query: `{ Solana { DEXTrades(limit: {count: 5}, orderBy: {descending: Block_Time}) { Block { Time } Trade { Buy { Currency { MintAddress } Amount } } } } }`, }), }); const { data, extensions } = await response.json(); console.log(data.Solana.DEXTrades); ``` ```python theme={null} import requests resp = requests.post( "https://graphql.chainstream.io/graphql", headers={ "Content-Type": "application/json", "X-API-KEY": "your_api_key", }, json={ "query": """{ Solana { DEXTrades(limit: {count: 5}, orderBy: {descending: Block_Time}) { Block { Time } Trade { Buy { Currency { MintAddress } Amount } } } } }""", }, ) data = resp.json() print(data["data"]["Solana"]["DEXTrades"]) ``` ### GET Example ```bash theme={null} curl -G "https://graphql.chainstream.io/graphql" \ -H "X-API-KEY: your_api_key" \ --data-urlencode 'query={ Solana { DEXTrades(limit: {count: 5}, orderBy: {descending: Block_Time}) { Block { Time } } } }' ``` *** ## Supported Networks Wrap Cube queries in the appropriate **Chain Group** to select the network: | Chain Group | Blockchain | Chain ID | | :------------------ | :-------------- | :------- | | `Solana` | Solana | — | | `EVM(network: eth)` | Ethereum | 1 | | `EVM(network: bsc)` | BNB Chain (BSC) | 56 | ```graphql theme={null} # Solana { Solana { DEXTrades(limit: {count: 5}) { ... } } } # Ethereum { EVM(network: eth) { DEXTrades(limit: {count: 5}) { ... } } } # BSC { EVM(network: bsc) { DEXTrades(limit: {count: 5}) { ... } } } ``` *** ## Response Format All responses are JSON with the following structure: ```json theme={null} { "data": { "Solana": { "DEXTrades": [ { "Block": { "Time": "2025-03-27T10:15:30Z" }, "..." : "..." } ] } }, "extensions": { "credits": { "total": 50, "cubes": [ { "cube": "DEXTrades", "credits": 50, "row_count": 5 } ] } } } ``` | Field | Description | | :------------------------- | :---------------------------------------------------------------- | | `data` | The query result — matches the shape of your query | | `errors` | Present only when there are validation or execution errors | | `extensions.credits.total` | Total credit units consumed by this query | | `extensions.credits.cubes` | Per-Cube breakdown: Cube name, credits charged, and rows returned | The `extensions.credits` field is included when credits are consumed. See [Billing & Credits](/en/graphql/billing/graphql-billing) for details on how credits are calculated. ### Error Response When a query is malformed or fails, the response includes an `errors` array: ```json theme={null} { "data": null, "errors": [ { "message": "Unknown field 'InvalidField' on type 'DEXTrades'", "locations": [{ "line": 3, "column": 5 }] } ] } ``` Use the [GraphQL IDE](https://ide.chainstream.io) to validate queries interactively before integrating them into your application. The IDE provides auto-complete and inline error highlighting. *** ## Next Steps Follow the step-by-step tutorial to run a real query from the IDE or cURL. Dive into the 25 Cubes, field types, filtering operators, and aggregation functions. # First Query Source: https://docs.chainstream.io/en/graphql/getting-started/first-query Run your first GraphQL query step by step — from the IDE and cURL **Estimated time**: 5 minutes ## Prerequisites Before you begin, make sure you have: * A registered ChainStream account ([Register here](https://www.chainstream.io/dashboard)) * An API Key (starts with `cs_live_...`) The GraphQL API shares the same API Key as the REST Data API. If you already have a key from the REST API, you can reuse it here. *** ## Step 1: Get Your API Key 1. Log in to [ChainStream Dashboard](https://www.chainstream.io/dashboard) 2. Go to **Applications** 3. Click **Create New App** (or select an existing app) 4. Copy your **API Key** *** ## Step 2: Open the GraphQL IDE Visit the ChainStream GraphQL IDE: [https://ide.chainstream.io](https://ide.chainstream.io) The IDE provides auto-complete, syntax highlighting, inline documentation, and query history — making it the fastest way to explore the schema and build queries. *** ## Step 3: Configure Authentication In the IDE, open the **Headers** panel (bottom-left) and add your API Key: ```json theme={null} { "X-API-KEY": "your_api_key" } ``` *** ## Step 4: Run a Sample Query Paste the following query into the editor. It fetches the **latest 10 DEX trades on Solana**, including block time, transaction hash, buy/sell token info, amounts, USD price, and the DEX protocol name. ```graphql theme={null} query { Solana { DEXTrades( limit: {count: 10} orderBy: {descending: Block_Time} ) { Block { Time Slot } Transaction { Hash } Trade { Buy { Currency { MintAddress } Amount PriceInUSD } Sell { Currency { MintAddress } Amount } Dex { ProtocolName } } } } } ``` [Open in GraphQL IDE](https://ide.chainstream.io) — paste the query above to run it interactively with auto-complete and schema exploration. Click the **Play** button (or press `Ctrl+Enter` / `Cmd+Enter`) to execute. *** ## cURL Equivalent You can run the same query from your terminal: ```bash theme={null} curl -X POST "https://graphql.chainstream.io/graphql" \ -H "Content-Type: application/json" \ -H "X-API-KEY: your_api_key" \ -d '{ "query": "{ Solana { DEXTrades(limit: {count: 10}, orderBy: {descending: Block_Time}) { Block { Time Slot } Transaction { Hash } Trade { Buy { Currency { MintAddress } Amount PriceInUSD } Sell { Currency { MintAddress } Amount } Dex { ProtocolName } } } } }" }' ``` *** ## Response Example A successful response looks like this: ```json theme={null} { "data": { "Solana": { "DEXTrades": [ { "Block": { "Time": "2025-03-27T10:32:18Z", "Slot": 325847291 }, "Transaction": { "Hash": "4vKzR8g...x9bQ" }, "Trade": { "Buy": { "Currency": { "MintAddress": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" }, "Amount": 1523.45, "PriceInUSD": 1.0001 }, "Sell": { "Currency": { "MintAddress": "So11111111111111111111111111111111111111112" }, "Amount": 10.237 }, "Dex": { "ProtocolName": "Raydium" } } }, { "Block": { "Time": "2025-03-27T10:32:17Z", "Slot": 325847289 }, "Transaction": { "Hash": "3mPqW7n...kR2J" }, "Trade": { "Buy": { "Currency": { "MintAddress": "DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263" }, "Amount": 48291037.12, "PriceInUSD": 0.00003152 }, "Sell": { "Currency": { "MintAddress": "So11111111111111111111111111111111111111112" }, "Amount": 10.5 }, "Dex": { "ProtocolName": "Orca" } } } ] } }, "extensions": { "credits": { "total": 50, "cubes": [ { "cube": "DEXTrades", "credits": 50, "row_count": 10 } ] } } } ``` *** ## Understanding the Response The response mirrors the structure of your query: | Path | Description | | :-------------------------------- | :--------------------------------------------------------------------- | | `Block.Time` | Block timestamp in ISO 8601 format | | `Block.Slot` | Solana slot number (Solana-specific) | | `Transaction.Hash` | On-chain transaction hash | | `Trade.Buy.Currency.MintAddress` | Token address of the bought asset | | `Trade.Buy.Amount` | Amount of the bought token | | `Trade.Buy.PriceInUSD` | USD price of the bought token at trade time | | `Trade.Sell.Currency.MintAddress` | Token address of the sold asset | | `Trade.Sell.Amount` | Amount of the sold token | | `Trade.Dex.ProtocolName` | DEX protocol that executed the trade (e.g. Raydium, Orca, PancakeSwap) | The `extensions.credits` object shows how many billing credits this query consumed and your remaining balance. See [Billing & Credits](/en/graphql/billing/graphql-billing) for details. *** ## Try Modifying the Query Now that you have a working query, try these modifications: Change `network: sol` to `network: eth` to query Ethereum DEX trades (Uniswap, SushiSwap, etc.). Filter trades from the last hour by adding a `where` clause: ```graphql theme={null} Solana { DEXTrades( limit: {count: 10} orderBy: {descending: Block_Time} where: {Block: {Time: {after: "2025-03-27T09:00:00Z"}}} ) { ... } } ``` Filter by token mint address to see trades for a specific token: ```graphql theme={null} Solana { DEXTrades( limit: {count: 10} orderBy: {descending: Block_Time} where: {Trade: {Buy: {Currency: {MintAddress: {is: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"}}}}} ) { ... } } ``` Count total trades per DEX protocol: ```graphql theme={null} Solana { DEXTrades( where: {Block: {Time: {after: "2025-03-27T00:00:00Z"}}} ) { count Trade { Dex { ProtocolName } } } } ``` *** ## Next Steps Explore all 25 Cubes, field types, filtering operators, and aggregation functions. Browse real-world query examples for DEX trades, transfers, OHLC, holders, and more. Master the IDE — query templates, saved queries, variables panel, and code export. Understand how query credits are calculated and how to optimize costs. # Overview Source: https://docs.chainstream.io/en/graphql/getting-started/overview ChainStream GraphQL — OLAP analytical GraphQL interface for multi-chain on-chain data ChainStream GraphQL is an OLAP analytical API that exposes multi-chain on-chain data (Solana, Ethereum, BSC, Polygon) through a single GraphQL endpoint. Query exactly the fields you need, aggregate data on the fly, and explore the schema interactively — all powered by a high-performance OLAP database. ## What is ChainStream GraphQL ChainStream GraphQL provides a **declarative query interface** for on-chain analytical data. Instead of calling dozens of REST endpoints with fixed response shapes, you write a single GraphQL query that specifies exactly what data you want, how it should be filtered, and how it should be aggregated. The service is built on **activecube-rs**, which dynamically generates a GraphQL schema from **Cube** definitions — each Cube represents an analytical data model (e.g. DEX trades, token transfers, OHLC candles). Queries are compiled into optimized SQL and executed against a high-performance OLAP database. *** ## GraphQL vs REST Data API
| | **GraphQL API** | **REST Data API** | | :------------------ | :----------------------------------------------------- | :-------------------------------------------------- | | **Query Style** | Declarative — you define shape, filters, aggregation | Imperative — fixed endpoints with predefined params | | **Field Selection** | Client picks exactly the fields needed | Server returns a fixed response schema | | **Aggregation** | Built-in `count`, `sum`, `avg`, `min`, `max` per query | Predefined aggregated endpoints only | | **Endpoint** | Single endpoint for all data models | One endpoint per resource | | **Pagination** | `limit` + `offset` in query arguments | `limit` + `offset` / cursor in query params | | **Best For** | Analytics, dashboards, flexible exploration | Simple lookups, real-time price, wallet balance | | **Latency** | Optimized for throughput over latency | Optimized for low-latency single-resource reads |
Use **GraphQL** when you need flexible analytical queries — aggregating trades, computing PnL across time ranges, or building custom dashboards. Use the **REST API** when you need fast, simple lookups like current token price or wallet balance. *** ## Core Advantages One URL serves 25 data Cubes across 4 chains. No endpoint sprawl — just change your query. Request only the columns you need. No over-fetching, no under-fetching — ideal for bandwidth-constrained clients. Compute `count`, `sum`, `avg`, `min`, `max` directly in your query without post-processing. *** ## Supported Chains | Network ID | Blockchain | Chain Group | Coverage | | :--------- | :-------------- | :---------- | :--------------------------------------------------------------------------------------------- | | `eth` | Ethereum | EVM | Full DEX, transfers, balance updates, events, traces, token stats | | `bsc` | BNB Chain (BSC) | EVM | Full DEX, transfers, balance updates, events, traces, token stats | | `polygon` | Polygon | EVM | Prediction markets (PredictionTrades/Managements/Settlements). Other Cubes are being deployed. | | `sol` | Solana | Solana | Full DEX, transfers, instructions, token holders, OHLC, PnL | Queries are organized into three **Chain Groups**: **EVM** (requires a `network` argument), **Solana**, and **Trading** (cross-chain OHLC and token statistics). See [Chain Groups](/en/graphql/schema/chain-groups) for details. *** ## Available Data Cubes 25 Cubes are available across three Chain Groups, each representing a distinct analytical model: * **DEXTrades** — Individual DEX swap events with buy/sell amounts, prices, and DEX protocol info * **DEXTradeByTokens** — DEX trades indexed by token for efficient per-token queries * **DEXOrders** — DEX order events including limit orders *(Solana only)* * **DEXPoolEvents** — Liquidity add/remove events on DEX pools * **DEXPools** — DEX pool snapshots with current reserves and metadata * **DEXPoolSlippages** — Pool slippage data *(EVM only)* * **TokenSupplyUpdates** — Mint and burn events affecting token supply * **Transfers** — Token transfer events with sender, receiver, amounts, and USD values * **BalanceUpdates** — Wallet balance change events per token * **TokenHolders** — Current holder list and distribution for a token * **WalletTokenPnL** — PnL per wallet-token pair * **Pairs** — OHLC candlestick data at configurable time intervals (formerly referenced as OHLC) * **Tokens** — Aggregated trade statistics per token: volume, trade count, unique traders (formerly referenced as TokenTradeStats) * **Blocks** — Block-level data (timestamps, height, miners/validators) * **Transactions** — Transaction-level data (hash, status, gas/fees) * **TransactionBalances** — Per-transaction balance changes * **Events** — Smart contract event logs *(EVM only)* * **Calls** — Internal call traces *(EVM only)* * **Instructions** — Instruction-level data *(Solana only)* * **InstructionBalanceUpdates** — Instruction-level balance changes *(Solana only)* * **Rewards** — Validator/staking rewards *(Solana only)* * **MinerRewards** — Miner/validator rewards *(EVM only)* * **Uncles** — Uncle block data *(EVM only)* * **PredictionTrades** — Prediction market trade events *(EVM — Polygon)* * **PredictionManagements** — Prediction market management events *(EVM — Polygon)* * **PredictionSettlements** — Prediction market settlement events *(EVM — Polygon)* *** ## Key Query Parameters Beyond standard filtering and pagination, ChainStream GraphQL supports two powerful parameters at the Chain Group level: | Parameter | Values | Description | | :--------------- | :------------------------------------------ | :---------------------------------------------------------------------------- | | **`dataset`** | `realtime`, `archive`, `combined` (default) | Controls data source scope — recent data only, historical data, or full range | | **`aggregates`** | `yes`, `no`, `only` | Controls whether to use pre-aggregated tables for faster analytical queries | See [Dataset & Aggregates](/en/graphql/schema/dataset-aggregates) for detailed usage and examples. *** ## Architecture ```mermaid theme={null} graph LR A[Your App / AI Agent] --> B[GraphQL IDE] A --> C[Any GraphQL Client] B --> D[APISIX Gateway] C --> D D -->|Auth + Rate Limit| E[chainstream-graphql] E -->|"activecube-rs (GraphQL to SQL)"| F[(OLAP Database)] ``` All requests pass through the APISIX gateway for authentication and rate limiting. The `chainstream-graphql` service compiles GraphQL queries into optimized SQL executed against the OLAP analytical database. *** ## Next Steps Configure the endpoint URL, authentication headers, and understand the request/response format. Run your first GraphQL query step by step — from the IDE or cURL. Explore the interactive GraphQL IDE with auto-complete, query templates, and code export. # Code Export Source: https://docs.chainstream.io/en/graphql/ide/code-export Generate ready-to-use code snippets from your GraphQL queries in 7 programming languages ## Overview The Code Export feature converts your current GraphQL query into a ready-to-use code snippet in your language of choice. The generated code includes the full HTTP request setup — endpoint URL, authentication headers, query body, and variables — so you can copy it directly into your project. *** ## Supported Languages
| Language | Format | Use Case | | :------------- | :----------------- | :-------------------------------------------------- | | **cURL** | Shell command | Quick terminal testing, CI/CD scripts | | **Python** | `requests` library | Backend services, data pipelines, Jupyter notebooks | | **JavaScript** | `fetch` API | Browser apps, Node.js services | | **Go** | `net/http` | Backend microservices, CLI tools | | **Rust** | `reqwest` crate | High-performance services | | **Ruby** | `net/http` | Rails applications, scripts | | **PHP** | `cURL` extension | PHP backends, WordPress plugins |
*** ## How to Export Enter or load a query into the editor. Make sure it executes successfully before exporting. Click the **Export Code** button in the toolbar. A modal opens with the language selector and generated snippet. Choose your target language from the dropdown. The snippet updates immediately. Click the **Copy** button to copy the generated code to your clipboard. The exported code uses the GraphQL endpoint and API key from your current IDE configuration. If you've set a custom endpoint or headers, those are reflected in the generated snippet. *** ## Example Snippets The following examples export a simple DEXTrades query — fetching the 10 latest Solana DEX trades: ```graphql theme={null} query { Solana { DEXTrades( limit: {count: 10} orderBy: {descending: Block_Time} ) { Block { Time } Transaction { Hash } Trade { Buy { Currency { MintAddress } Amount PriceInUSD } Sell { Currency { MintAddress } Amount } Dex { ProtocolName } } } } } ``` ```bash theme={null} curl -X POST "https://graphql.chainstream.io/graphql" \ -H "Content-Type: application/json" \ -H "X-API-KEY: your_api_key" \ -d '{ "query": "{ Solana { DEXTrades(limit: {count: 10}, orderBy: {descending: Block_Time}) { Block { Time } Transaction { Hash } Trade { Buy { Currency { MintAddress } Amount PriceInUSD } Sell { Currency { MintAddress } Amount } Dex { ProtocolName } } } } }" }' ``` ```python theme={null} import requests url = "https://graphql.chainstream.io/graphql" headers = { "Content-Type": "application/json", "X-API-KEY": "your_api_key", } query = """ { Solana { DEXTrades( limit: {count: 10} orderBy: {descending: Block_Time} ) { Block { Time } Transaction { Hash } Trade { Buy { Currency { MintAddress } Amount PriceInUSD } Sell { Currency { MintAddress } Amount } Dex { ProtocolName } } } } } """ response = requests.post(url, json={"query": query}, headers=headers) data = response.json() print(data) ``` ```javascript theme={null} const response = await fetch("https://graphql.chainstream.io/graphql", { method: "POST", headers: { "Content-Type": "application/json", "X-API-KEY": "your_api_key", }, body: JSON.stringify({ query: `{ Solana { DEXTrades( limit: {count: 10} orderBy: {descending: Block_Time} ) { Block { Time } Transaction { Hash } Trade { Buy { Currency { MintAddress } Amount PriceInUSD } Sell { Currency { MintAddress } Amount } Dex { ProtocolName } } } } }`, }), }); const data = await response.json(); console.log(data); ``` ```go theme={null} package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) func main() { payload := map[string]string{ "query": `{ Solana { DEXTrades(limit: {count: 10}, orderBy: {descending: Block_Time}) { Block { Time } Transaction { Hash } Trade { Buy { Currency { MintAddress } Amount PriceInUSD } Sell { Currency { MintAddress } Amount } Dex { ProtocolName } } } } }`, } body, _ := json.Marshal(payload) req, _ := http.NewRequest("POST", "https://graphql.chainstream.io/graphql", bytes.NewBuffer(body)) req.Header.Set("Content-Type", "application/json") req.Header.Set("X-API-KEY", "your_api_key") resp, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer resp.Body.Close() result, _ := io.ReadAll(resp.Body) fmt.Println(string(result)) } ``` ```rust theme={null} use reqwest::header::{HeaderMap, HeaderValue, CONTENT_TYPE}; use serde_json::json; #[tokio::main] async fn main() -> Result<(), reqwest::Error> { let mut headers = HeaderMap::new(); headers.insert(CONTENT_TYPE, HeaderValue::from_static("application/json")); headers.insert("X-API-KEY", HeaderValue::from_static("your_api_key")); let body = json!({ "query": r#"{ Solana { DEXTrades(limit: {count: 10}, orderBy: {descending: Block_Time}) { Block { Time } Transaction { Hash } Trade { Buy { Currency { MintAddress } Amount PriceInUSD } Sell { Currency { MintAddress } Amount } Dex { ProtocolName } } } } }"# }); let client = reqwest::Client::new(); let res = client .post("https://graphql.chainstream.io/graphql") .headers(headers) .json(&body) .send() .await?; println!("{}", res.text().await?); Ok(()) } ``` *** ## What's Included in Exported Code Every generated snippet includes: | Component | Description | | :----------------- | :---------------------------------------------- | | **Endpoint URL** | `https://graphql.chainstream.io/graphql` | | **Authentication** | `X-API-KEY` header from your IDE Headers panel | | **Content-Type** | `application/json` | | **Query body** | The full GraphQL query from the editor | | **Variables** | Included if the Variables panel contains values | Remember to replace `your_api_key` with your actual API key before running the exported code. The IDE does not embed your real key in exported snippets for security. *** ## Tips * **Test before exporting** — Run the query in the IDE first to confirm it works. Exported code copies the query as-is. * **Parameterize with variables** — Use GraphQL variables instead of hardcoded values. The exported code includes the `variables` JSON alongside the query. * **Check dependencies** — Python snippets use `requests`, Rust uses `reqwest`, Go uses the standard library. Make sure the required packages are installed in your project. # GraphQL IDE Source: https://docs.chainstream.io/en/graphql/ide/introduction Interactive browser-based IDE for exploring, writing, and testing ChainStream GraphQL queries The ChainStream GraphQL IDE is a browser-based development environment purpose-built for writing, testing, and sharing GraphQL analytical queries across Solana, Ethereum, BSC, and Polygon. No installation required — open the URL and start querying. [https://ide.chainstream.io](https://ide.chainstream.io) *** ## Feature Highlights Full-featured code editor with GraphQL syntax highlighting, schema-driven autocomplete, and real-time error detection. Visual schema browser in the sidebar — explore Chain Groups, Cubes, fields, and filters without writing introspection queries. Built-in templates organized by chain and Cube — load, customize, and execute in seconds. Save queries locally with titles. Work on multiple queries in parallel with tabbed editing. Export your query as a ready-to-use code snippet in 7 languages: cURL, Python, JavaScript, Go, Rust, Ruby, and PHP. Built-in AI assistant that can generate GraphQL queries from natural language descriptions and explain query results. Requires sign-in. Generate a shareable URL for any query. Recipients can open it in the IDE with the query pre-loaded. Real-time feedback on request state, latency (ms), response size, and Credit Units consumed per query. Dark-themed interface aligned with ChainStream branding, optimized for extended query sessions. *** ## IDE Layout The IDE is organized into the following regions, from top to bottom: **Full-width top bar** — Execute (▶), Prettify, Save/Fork, Export Code, Share buttons, and the endpoint URL input. **Left** — Three tabs: **Query Builder** (schema tree), **Queries** (built-in templates), **Saved** (your saved queries) **Center** — Monaco editor (with Tab Bar, Variables / Headers panels), and syntax-highlighted JSON response panel below **Right** — Natural language query generation and result explanation (requires sign-in) **Full-width bottom bar** — Request state, latency (ms), response size, and CU consumed. *** ## Quick Start Navigate to [ide.chainstream.io](https://ide.chainstream.io) in your browser. You can set your API key in two ways: **Option A — Manual entry**: Click the **Headers** panel at the bottom of the editor and enter: ```json theme={null} { "X-API-KEY": "your_api_key" } ``` **Option B — Sign in**: Click **Sign In** in the top bar and log in with your ChainStream account. Your API keys will be automatically loaded and selectable from the key dropdown. Don't have a key yet? Create one in the [ChainStream Dashboard](https://www.chainstream.io/dashboard) → **Applications** → **Create New App**. Open the sidebar (**Ctrl/Cmd+B**), expand a chain (e.g. **Solana**), then click a template like **DEXTrades → Latest Trades**. The query loads into the editor with placeholder values. Replace any `TOKEN_ADDRESS`, `WALLET_ADDRESS`, or `POOL_ADDRESS` placeholders with real on-chain addresses. Press **Ctrl/Cmd+Enter** or click the **Execute** (▶) button. Results appear in the right panel, and the status bar shows latency and CU cost. *** ## Query Builder (Schema Browser) The sidebar includes a visual **Query Builder** that replaces the standard GraphiQL documentation panel. It displays the full schema as an interactive tree: * **Chain Groups** (EVM, Solana, Trading) at the top level * **Cubes** within each group * **Fields**, **filters**, and **ordering options** for each Cube Click any field to insert it into your query. This is powered by the backend's `/ide/builder-schema` endpoint, which provides a structured representation of the entire schema. *** ## AI Assistant The AI Assistant panel (right side) helps you: * **Generate queries** from natural language descriptions (e.g., "Get the top 10 Solana DEX trades by volume today") * **Explain results** — paste a response and get a plain-language summary The AI Assistant requires signing in with your ChainStream account. It uses the same API key as your current IDE session. *** ## Share Queries Generate a shareable URL for any query by clicking the **Share** button in the toolbar. The URL encodes the query, variables, and network selection using a `#q=` fragment. Recipients can open the link to see the query pre-loaded in their IDE. *** ## Learn More Explore the Monaco editor, panels, toolbar, keyboard shortcuts, and status bar. Browse the full catalog of built-in templates across all Cubes. Save, organize, and manage your frequently used queries. Generate ready-to-use code snippets in 7 programming languages. # Query Editor Source: https://docs.chainstream.io/en/graphql/ide/query-editor Monaco-powered GraphQL editor with autocomplete, syntax highlighting, panels, and real-time query execution ## Monaco Editor The query editor is built on [Monaco](https://microsoft.github.io/monaco-editor/) — the same engine behind VS Code — with a GraphQL language worker that provides: * **Syntax highlighting** for GraphQL operations, fields, arguments, and directives * **Schema-driven autocomplete** — press `Ctrl+Space` to see available fields, arguments, and types based on the live schema * **Real-time error detection** — red underlines and error markers for invalid field names, missing arguments, or type mismatches * **Bracket matching** and **auto-closing** for braces, parentheses, and strings * **Multi-cursor editing** for batch changes Autocomplete is schema-aware. As you type inside a Cube (e.g. `DEXTrades`), only the fields and arguments valid for that Cube appear in the suggestion list. *** ## Editor Panels The editor area is divided into three tabs at the bottom. Switch between them to configure different parts of your request. ### Query Panel The main editing area where you write GraphQL queries. This is where Monaco's autocomplete, highlighting, and error detection are active. ```graphql theme={null} query { Solana { DEXTrades( limit: {count: 10} orderBy: {descending: Block_Time} ) { Block { Time } Transaction { Hash } Trade { Buy { Currency { MintAddress } Amount PriceInUSD } Sell { Currency { MintAddress } Amount } Dex { ProtocolName } } } } } ``` ### Variables Panel Use the Variables panel to pass JSON variables to parameterized queries. This keeps your queries reusable — change variable values without editing the query text. ```graphql theme={null} query LatestTrades($limit: Int!) { Solana { DEXTrades( limit: {count: $limit} orderBy: {descending: Block_Time} ) { Block { Time } Trade { Buy { Currency { MintAddress } Amount PriceInUSD } Sell { Currency { MintAddress } Amount } } } } } ``` ```json theme={null} { "limit": 20 } ``` ### Headers Panel Configure HTTP headers sent with every request. The Headers panel is **shown by default** with the `X-API-KEY` header pre-configured. ```json theme={null} { "X-API-KEY": "your_api_key" } ``` You can add additional custom headers as needed. All headers are sent as part of the POST request to the GraphQL endpoint. The `Content-Type: application/json` header is automatically included — you do not need to set it manually. *** ## Toolbar The toolbar sits at the top of the editor and provides quick-access actions: | Button | Action | Description | | :-------------- | :-------------- | :--------------------------------------------------------------------------- | | **Execute** (▶) | Run query | Sends the current query (with variables and headers) to the GraphQL endpoint | | **Prettify** | Format query | Auto-formats the query with consistent indentation and line breaks | | **Copy** | Copy query | Copies the current query text to the clipboard | | **Merge** | Merge fragments | Merges inline fragments into a single flattened query | | **Save Query** | Save locally | Saves the current query with a title and optional tags | | **Export Code** | Export snippet | Generates a code snippet for the current query in your chosen language | *** ## Executing Queries To execute a query: 1. Write or load a query into the editor 2. Set your `X-API-KEY` in the Headers panel 3. Click the **Execute** button (▶) in the toolbar, or press **Ctrl/Cmd+Enter** The response appears in the **Results Panel** on the right side of the editor with full JSON syntax highlighting. If the query contains errors, the error response is displayed with the error message and location details. *** ## Results Panel The results panel displays the JSON response from the GraphQL endpoint with: * **Syntax highlighting** for JSON keys, strings, numbers, and booleans * **Collapsible nodes** for navigating deeply nested responses * **Copy response** support via right-click context menu A typical successful response includes a `data` object matching your query structure, plus an `extensions.credits` object showing billing information. *** ## Status Bar The status bar at the bottom of the IDE provides real-time feedback on query execution: | Indicator | Values | Description | | :---------- | :--------------------------------------------- | :----------------------------------------------------- | | **State** | `Ready` · `Executing...` · `Success` · `Error` | Current request lifecycle state | | **Latency** | e.g. `120ms` | Round-trip time from request sent to response received | | **Size** | e.g. `2.4 KB` | Response body size | | **Credits** | e.g. `8 CU` | Credit Units consumed by this query | Credit Units (CU) reflect the computational cost of your query. Queries scanning more data or returning larger result sets consume more CU. See [Billing & Credits](/en/graphql/billing/graphql-billing) for details. *** ## Keyboard Shortcuts
| Shortcut | Action | | :--------------------- | :--------------------- | | `Ctrl/Cmd + Enter` | Execute query | | `Ctrl/Cmd + B` | Toggle sidebar | | `Ctrl + Space` | Trigger autocomplete | | `Ctrl/Cmd + Shift + P` | Command palette | | `Ctrl/Cmd + /` | Toggle line comment | | `Ctrl/Cmd + D` | Select next occurrence | | `Ctrl/Cmd + Shift + F` | Format / Prettify | | `Alt + Up/Down` | Move line up/down |
On macOS, replace `Ctrl` with `Cmd`. The IDE automatically detects your operating system and displays the appropriate modifier key. # Query Templates Source: https://docs.chainstream.io/en/graphql/ide/query-templates Built-in query templates organized by chain and Cube — load, customize, and execute common on-chain analytical queries ## What Are Query Templates Query templates are pre-written GraphQL queries that cover the most common analytical use cases across Solana, Ethereum, and BSC. Each template targets a specific Cube and comes pre-filled with the correct query structure, fields, and filter arguments — ready to run after replacing placeholder values. Templates help you: * **Learn the schema** by example — see how fields, filters, and ordering work in practice * **Start quickly** without writing queries from scratch * **Discover Cubes** you might not have known about *** ## Accessing Templates Click the sidebar toggle or press **Ctrl/Cmd+B** to open the left panel. The sidebar has two tabs: **Queries** (templates) and **Saved** (your saved queries). Select **Queries**. Templates are organized in a tree: **Chain** (Solana / Ethereum / BSC) → **Cube** (DEXTrades, Transfers, etc.) → **Template**. Click any template to load it into the query editor. Placeholder values are highlighted for easy replacement. *** ## Template Organization Templates follow a two-level hierarchy: ``` Chain (Solana / Ethereum / BSC) └── Cube └── Template ``` Each chain contains the same set of Cubes and templates, pre-configured with the correct `network` value (`sol`, `eth`, or `bsc`). *** ## Template Catalog
| Cube | Templates | Count | | :--------------------- | :------------------------------------------------------------------------- | :---- | | **DEXTrades** | Latest Trades · Token Trades · Pair Trades · Trades by DEX · Wallet Trades | 5 | | **Transfers** | Token Transfers · Wallet Transfers | 2 | | **BalanceUpdates** | Token Balance Updates · Wallet Balance Updates | 2 | | **DEXPools** | Pool Info · Token Pools · Liquidity Snapshots | 3 | | **TokenSupplyUpdates** | Mint & Burn Events · Market Cap (via TokenSupplyUpdates) | 2 | | **TokenHolders** | Top Holders | 1 | | **WalletTokenPnL** | Wallet PnL | 1 | | **Pairs** | Price Candles | 1 | | **Tokens** | Trade Statistics · Search Tokens (via token dimensions) | 2 |
The most commonly used Cubes are covered across **19 templates**. Each template is available for all supported chains. *** ## Template Details by Cube | Template | Description | Placeholders | | :---------------- | :------------------------------------ | :------------------- | | **Latest Trades** | Most recent DEX trades on the network | — | | **Token Trades** | Trades involving a specific token | `TOKEN_ADDRESS` | | **Pair Trades** | Trades for a specific token pair | `TOKEN_ADDRESS` (×2) | | **Trades by DEX** | Trades filtered by DEX protocol name | — | | **Wallet Trades** | All DEX trades executed by a wallet | `WALLET_ADDRESS` | | Template | Description | Placeholders | | :------------------- | :----------------------------------------- | :--------------- | | **Token Transfers** | Transfer events for a specific token | `TOKEN_ADDRESS` | | **Wallet Transfers** | All transfers sent or received by a wallet | `WALLET_ADDRESS` | | Template | Description | Placeholders | | :------------------------- | :----------------------------------------- | :--------------- | | **Token Balance Updates** | Balance change events for a specific token | `TOKEN_ADDRESS` | | **Wallet Balance Updates** | All balance changes for a wallet | `WALLET_ADDRESS` | | Template | Description | Placeholders | | :---------------------- | :--------------------------------------------- | :-------------- | | **Pool Info** | Metadata and reserves for a specific pool | `POOL_ADDRESS` | | **Token Pools** | All liquidity pools containing a token | `TOKEN_ADDRESS` | | **Liquidity Snapshots** | Historical liquidity data for a pool over time | `POOL_ADDRESS` | | Template | Description | Placeholders | | :--------------------- | :---------------------------------------------- | :-------------- | | **Mint & Burn Events** | Mint and burn events affecting a token's supply | `TOKEN_ADDRESS` | | **Market Cap** | Market capitalization snapshot for a token | `TOKEN_ADDRESS` | | Template | Description | Placeholders | | :-------------- | :--------------------------------------------- | :-------------- | | **Top Holders** | Largest holders of a specific token by balance | `TOKEN_ADDRESS` | | Template | Description | Placeholders | | :------------- | :-------------------------------------------------- | :-------------------------------- | | **Wallet PnL** | Realized and unrealized PnL for a wallet-token pair | `WALLET_ADDRESS`, `TOKEN_ADDRESS` | | Template | Description | Placeholders | | :---------------- | :---------------------------------------------- | :-------------- | | **Price Candles** | OHLC candlestick data at configurable intervals | `TOKEN_ADDRESS` | | Template | Description | Placeholders | | :------------------- | :------------------------------------------------------ | :-------------- | | **Trade Statistics** | Aggregated trade volume, count, and unique traders | `TOKEN_ADDRESS` | | **Search Tokens** | Full-text search for tokens by name, symbol, or address | — | *** ## Placeholders Templates use uppercase placeholders to indicate values you need to replace with real on-chain addresses before executing. | Placeholder | Description | Example | | :--------------- | :-------------------------- | :-------------------------------------------------------------- | | `TOKEN_ADDRESS` | Token contract/mint address | `EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v` (USDC on Solana) | | `WALLET_ADDRESS` | Wallet public address | `5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1` | | `POOL_ADDRESS` | DEX liquidity pool address | `58oQChx4yWmvKdwLLZzBi4ChoCc2fqCUWBkwMihLYQo2` | Placeholders appear as literal strings in the query (e.g. `MintAddress: {is: "TOKEN_ADDRESS"}`). Replace the entire placeholder string including quotes with your actual address. *** ## Example: Using a Template Here's how to use the **DEXTrades → Latest Trades** template on Solana: Navigate to **Solana → DEXTrades → Latest Trades** and click to load. The editor populates with: ```graphql theme={null} query { Solana { DEXTrades( limit: {count: 10} orderBy: {descending: Block_Time} ) { Block { Time Slot } Transaction { Hash } Trade { Buy { Currency { MintAddress Symbol Name } Amount PriceInUSD } Sell { Currency { MintAddress Symbol Name } Amount } Dex { ProtocolName } } } } } ``` This template has no placeholders — it fetches the 10 most recent trades. Press **Ctrl/Cmd+Enter** to run. Modify the query to add filters, change the limit, or select different fields. The schema autocomplete helps you discover available options. # Saved Queries Source: https://docs.chainstream.io/en/graphql/ide/saved-queries Save, organize, and manage your frequently used GraphQL queries locally in the IDE ## Overview The GraphQL IDE lets you save queries to your browser for quick access later. Saved queries persist across browser sessions and appear in the sidebar's **Saved** tab, giving you a personal library of go-to queries without needing external tools. *** ## Saving a Query Enter a query in the editor, or load one from the [templates](/en/graphql/ide/query-templates). Click the **Save Query** button in the toolbar. A dialog appears with two fields: * **Title** (required) — A descriptive name for the query * **Tags** (optional) — Comma-separated labels for organization (e.g. `solana, dex, monitoring`) Click **Save**. The query is stored locally and immediately appears in the sidebar **Saved** tab. Use descriptive titles that include the chain and Cube name, e.g. "Solana — Latest Raydium Trades" or "ETH — USDC Top Holders". This makes queries easy to find as your collection grows. *** ## Loading a Saved Query 1. Open the sidebar (**Ctrl/Cmd+B**) 2. Switch to the **Saved** tab 3. Click on any saved query to load it into the editor The query text, variables, and headers are all restored to the state when the query was saved. *** ## Deleting a Saved Query To delete a saved query: 1. Open the sidebar and switch to the **Saved** tab 2. Hover over the query you want to remove — a **delete** icon appears 3. Click the delete icon to remove the query Deletion is permanent. There is no undo — once deleted, the query cannot be recovered. *** ## Storage Details | Property | Detail | | :-------------------- | :---------------------------------------------------------------- | | **Storage mechanism** | Browser `localStorage` | | **Persistence** | Survives page refreshes and browser restarts | | **Scope** | Per-browser, per-origin (same domain) | | **Sync** | Not synced across devices or browsers | | **Clearing** | Clearing browser data or `localStorage` removes all saved queries | Saved queries are stored entirely in your browser's `localStorage`. They are **not** sent to any server and are not accessible from other devices. If you need to share a query, use the [Code Export](/en/graphql/ide/code-export) feature to generate a portable snippet. *** ## Organizing with Tags Tags help you categorize and filter saved queries as your collection grows. Some recommended tagging strategies: Use chain-specific tags like `solana`, `ethereum`, `bsc` to quickly filter queries for a particular network. Tag queries with the Cube name: `dextrades`, `transfers`, `ohlc`, `holders`, etc. Functional tags like `monitoring`, `analysis`, `debug`, `dashboard` indicate the query's purpose. Tag with specific project names or token symbols: `usdc`, `bonk`, `raydium`, `uniswap`. There's no limit on the number of tags per query. Combine multiple tagging dimensions — e.g. `solana, dextrades, raydium, monitoring` — for maximum searchability. *** ## Best Practices * **Save iteratively** — Save working versions of queries as you refine them. Use versioned titles like "OHLC v1", "OHLC v2" if needed. * **Clean up regularly** — Delete queries you no longer use to keep the sidebar manageable. * **Export before clearing** — If you plan to clear browser data, export important queries as code snippets first via [Code Export](/en/graphql/ide/code-export). * **One query per concern** — Avoid saving monolithic queries that do too much. Smaller, focused queries are easier to reuse and compose. # Chain Groups Source: https://docs.chainstream.io/en/graphql/schema/chain-groups How Cubes are organized into EVM, Solana, and Trading Chain Groups ## Overview ChainStream GraphQL organizes its 25 Cubes into three **Chain Groups**. Each group represents a blockchain ecosystem and determines which Cubes are available, how the `network` parameter works, and what chain-specific fields exist. ```graphql theme={null} type ChainStream { EVM(network: Network!, dataset: Dataset, aggregates: Aggregates) { ... } Solana(dataset: Dataset, aggregates: Aggregates) { ... } Trading(dataset: Dataset, aggregates: Aggregates) { ... } } ``` *** ## EVM The **EVM** group contains Cubes for all EVM-compatible blockchains. It **requires** a `network` argument to specify which chain to query. ### Available Networks | Network ID | Blockchain | | :--------- | :-------------- | | `eth` | Ethereum | | `bsc` | BNB Chain (BSC) | | `polygon` | Polygon | **Polygon data availability:** Currently only **Prediction Markets** Cubes (`PredictionTrades`, `PredictionManagements`, `PredictionSettlements`) have data available for Polygon. Other Cubes (DEXTrades, Blocks, Transfers, etc.) are being deployed — queries against them may return errors. ### Cubes **Shared with Solana:** `DEXTrades`, `DEXTradeByTokens`, `Transfers`, `BalanceUpdates`, `DEXPoolEvents`, `TokenSupplyUpdates`, `Blocks`, `Transactions`, `TransactionBalances`, `DEXPools`, `TokenHolders`, `WalletTokenPnL` **EVM-only:** * `Events` — Smart contract event logs (decoded topics and data) * `Calls` — Internal call traces (CALL, DELEGATECALL, CREATE, etc.) * `MinerRewards` — Block rewards breakdown (static, dynamic, uncle, burned fees) * `DEXPoolSlippages` — Pool price slippage analysis * `Uncles` — Uncle block data (primarily Ethereum PoW historical) * `PredictionTrades` — Prediction market trades *(primarily Polygon)* * `PredictionManagements` — Prediction market management events *(primarily Polygon)* * `PredictionSettlements` — Prediction market settlements *(primarily Polygon)* ### Example Query ```graphql theme={null} query { EVM(network: eth, dataset: combined) { DEXTrades( limit: {count: 10} orderBy: {descending: Block_Time} ) { Block { Time Number } Transaction { Hash } Trade { Buy { Currency { SmartContract Symbol } Amount PriceInUSD } Sell { Currency { SmartContract Symbol } Amount } Dex { ProtocolName } } } } } ``` *** ## Solana The **Solana** group contains Cubes for the Solana blockchain. The network is implicit (`sol`) — no `network` argument is needed. ### Cubes **Shared with EVM:** `DEXTrades`, `DEXTradeByTokens`, `Transfers`, `BalanceUpdates`, `DEXPoolEvents`, `TokenSupplyUpdates`, `Blocks`, `Transactions`, `TransactionBalances`, `DEXPools`, `TokenHolders`, `WalletTokenPnL` **Solana-only:** * `Instructions` — Program instruction data (program address, method, accounts, logs) * `InstructionBalanceUpdates` — Balance changes at instruction level * `Rewards` — Validator and staking rewards * `DEXOrders` — DEX order book events (limit orders, cancellations, fills) ### Example Query ```graphql theme={null} query { Solana(dataset: realtime) { DEXTrades( limit: {count: 10} orderBy: {descending: Block_Time} ) { Block { Time Slot } Transaction { Hash } Trade { Buy { Currency { MintAddress Symbol } Amount PriceInUSD } Sell { Currency { MintAddress Symbol } Amount } Dex { ProgramAddress ProtocolName } } } } } ``` ### Field Names Across Chains The table below shows the conventional field names for each chain. However, the Record type contains **all fields from all chains as a superset** — both `MintAddress` and `SmartContract` exist in every Cube's Record type and return the same underlying data. You can use either name on any chain. | Concept | Conventional (Solana) | Conventional (EVM) | Cross-chain? | | :--------------- | :-------------------- | :----------------- | :---------------------- | | Token address | `MintAddress` | `SmartContract` | Both work on all chains | | Transaction ID | `Signature` / `Hash` | `Hash` | Both work on all chains | | Block identifier | `Slot` | `Number` | Both work on all chains | | Program/Contract | `ProgramAddress` | `SmartContract` | Both work on all chains | | Fee payer | `FeePayer` | `From` | Both work on all chains | This means you can use a **single query template** across all chains without changing field names. For example, `Currency { MintAddress }` works on both Solana and EVM queries. *** ## Trading The **Trading** group provides **cross-chain pre-aggregated** trading analytics. It combines data from all supported chains into unified materialized views with a `chain` dimension for filtering. ### Cubes * `Pairs` — OHLC candlestick data (open/high/low/close, volume, trade count) * `Tokens` — Per-token trade statistics (volume, buy/sell breakdown, unique traders) ### Key Differences from EVM/Solana Groups 1. **No `network` argument** — The Trading group combines data across chains. Use the `chain` dimension within the data to filter by network. 2. **Cross-chain data** — A single query can return data for `sol`, `eth`, and `bsc` together. 3. **Pre-aggregated** — Data is materialized at minute granularity from the DWM layer. ### Example: Cross-Chain OHLC ```graphql theme={null} query { Trading(aggregates: yes) { Pairs( where: { Token: { Address: { is: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" } } } limit: {count: 60} orderBy: {descending: Block_Time} ) { Token { Address } Market { Network } Interval { Time } Price { Ohlc { Open High Low Close } } Volume { Usd Native } Stats { TradeCount BuyCount SellCount } } } } ``` ### Example: Token Trade Stats by Chain ```graphql theme={null} query { Trading { Tokens( where: { Token: { Address: { is: "0xdac17f958d2ee523a2206206994597c13d831ec7" } } Market: { Network: { is: "eth" } } } limit: {count: 30} orderBy: {descending: Block_Time} ) { Interval { Time } Volume { Usd BuyVolumeUSD SellVolumeUSD } Stats { TradeCount UniqueBuyers UniqueSellers } } } } ``` *** ## Chain Group Comparison | Feature | EVM | Solana | Trading | | :----------------------- | :------------------------------------------------------------------ | :---------------------------------------------------------- | :----------------------- | | **`network` argument** | Required (`eth`, `bsc`, `polygon`) | Not needed (implicit `sol`) | Not needed (cross-chain) | | **Unique Cubes** | Events, Calls, MinerRewards, Uncles, DEXPoolSlippages, Prediction\* | Instructions, InstructionBalanceUpdates, Rewards, DEXOrders | Pairs, Tokens | | **Data granularity** | Per-event (DWD) + aggregated (DWM/DWS) | Per-event + instruction-level | Pre-aggregated (DWM) | | **`dataset` support** | Yes (most Cubes) | Yes (most Cubes) | Yes | | **`aggregates` support** | Yes | Yes | Yes | *** ## Related Documentation Detailed field structures and use cases for all 25 Cubes. Control data source scope and pre-aggregation behavior. # Data Cubes Source: https://docs.chainstream.io/en/graphql/schema/cubes All 25 GraphQL Cubes — field structures, selectors, defaults, and use cases organized by Chain Group ## What is a Cube? A **Cube** is an analytical data model that maps to one or more OLAP database tables. Each Cube defines: * **Dimensions** — queryable fields organized in a nested hierarchy (e.g., `Block.Time`, `Trade.Buy.Currency.MintAddress`) * **Selectors** — shortcut filter arguments at the top level (e.g., `tokenAddress`) that simplify common filter patterns * **Metrics** — aggregation functions (`count`, `sum`, etc.) available on the Record type * **Defaults** — default filters and pagination limits applied automatically When you query a Cube, activecube-rs compiles your GraphQL query into optimized SQL against the Cube's backing table, which follows the naming pattern `{chain}_{table_name}` (e.g., `sol_dex_trades`, `eth_transfers`). *** ## Cube Overview 25 Cubes are organized into three Chain Groups. Each Cube belongs to a data warehouse layer: * **DWD** (Detail) — raw per-event data, highest granularity * **DWM** (Aggregated) — pre-computed rollups (e.g., per-minute) * **DWS** (Summary) — highly aggregated snapshots * **DIM** (Dimension) — reference/lookup tables
| Cube | Chain Group | Layer | Purpose | | :---------------------------- | :------------ | :---- | :------------------------------------------ | | **DEXTrades** | EVM, Solana | DWD | Per-trade DEX swap events | | **DEXTradeByTokens** | EVM, Solana | DWD | DEX trades indexed by token (buy/sell side) | | **Transfers** | EVM, Solana | DWD | Token transfer events | | **BalanceUpdates** | EVM, Solana | DWD | Wallet balance change events | | **DEXPoolEvents** | EVM, Solana | DWD | Liquidity add/remove events | | **TokenSupplyUpdates** | EVM, Solana | DWD | Token mint/burn events | | **Blocks** | EVM, Solana | DWD | Block-level data | | **Transactions** | EVM, Solana | DWD | Transaction-level data | | **TransactionBalances** | EVM, Solana | DWD | Per-transaction balance changes | | **Instructions** | Solana | DWD | Solana instruction data | | **InstructionBalanceUpdates** | Solana | DWD | Instruction-level balance changes | | **Rewards** | Solana | DWD | Validator/staking rewards | | **DEXOrders** | Solana | DWD | DEX order events (limit orders) | | **Events** | EVM | DWD | Smart contract event logs | | **Calls** | EVM | DWD | Internal call traces | | **MinerRewards** | EVM | DWD | Miner/validator rewards | | **DEXPoolSlippages** | EVM | DWD | Pool slippage data | | **Uncles** | EVM | DWD | Uncle block data | | **Pairs** | Trading | DWM | OHLC candlestick data (cross-chain) | | **Tokens** | Trading | DWM | Per-token trade statistics (cross-chain) | | **DEXPools** | EVM, Solana | DWS | Pool snapshots with current reserves | | **TokenHolders** | EVM, Solana | DWS | Token holder balances | | **WalletTokenPnL** | EVM, Solana | DWS | Per wallet-token PnL | | **PredictionTrades** | EVM (Polygon) | DWD | Prediction market trades | | **PredictionManagements** | EVM (Polygon) | DWD | Prediction market management events | | **PredictionSettlements** | EVM (Polygon) | DWD | Prediction market settlements |
*** ## EVM + Solana Shared Cubes These Cubes are available in both the **EVM** and **Solana** Chain Groups. **Table**: `{chain}_dex_trades` **Default limit**: 25 (max 10,000) **Default filter**: `IsSuspect = false` (bot/MEV trades excluded by default) **Selectors**: `tokenAddress`, `walletAddress`, `poolAddress`, `dexProgram`, `date` **Metrics**: `count`, `sum`, `avg`, `min`, `max`, `uniq` **Key Fields:** ```graphql theme={null} DEXTradesRecord { Block { Time, Slot, Height } Transaction { Hash, FeeInNative } Trade { Buy { Currency { MintAddress }, Amount, PriceInUSD, Account { Owner } } Sell { Currency { MintAddress }, Amount, Account { Owner } } Dex { ProgramAddress, ProtocolName } } Pool { Address } IsSuspect } ``` **Use cases**: Trade history, wallet trade analysis, DEX volume breakdown, large trade detection. **Table**: `{chain}_dex_trades_enriched` (UNION subquery — one row per trade side) **Selectors**: `tokenAddress`, `sideType`, `poolAddress`, `dexProgram`, `date` **Metrics**: `count`, `sum`, `avg`, `min`, `max`, `uniq` **Key Fields:** ```graphql theme={null} DEXTradeByTokensRecord { Block { Time, Slot, Height } Transaction { Signature, Fee, FeeInUSD } Trade { Currency { MintAddress, Symbol, Name } Amount, AmountInUSD, PriceInUSD, PriceInNative Side { Type, Currency { MintAddress }, Amount } Account { Owner } Dex { ProgramAddress, ProtocolName } Market { PoolAddress } } } ``` **Use cases**: Per-token trade queries (both buy and sell sides), token volume analytics, efficient single-token filtering. **Table**: `{chain}_transfers` **Selectors**: `tokenAddress`, `senderAddress`, `receiverAddress`, `date` **Metrics**: `count`, `sum`, `avg`, `uniq` **Key Fields:** ```graphql theme={null} TransfersRecord { Block { Time, Slot } Transaction { Hash, Signer } Transfer { Currency { MintAddress } Sender { Address, TokenAccount } Receiver { Address, TokenAccount } Amount, AmountInUSD, PriceInUSD } } ``` **Use cases**: Wallet transfer history, whale monitoring, exchange deposit/withdrawal tracking. **Table**: `{chain}_balance_updates` **Selectors**: `ownerAddress`, `tokenAddress`, `date` **Metrics**: `count`, `sum`, `avg`, `min`, `max`, `uniq` **Key Fields:** ```graphql theme={null} BalanceUpdatesRecord { Block { Time, Slot } Transaction { Hash } BalanceUpdate { Currency { MintAddress, Decimals } Account { Address, Owner } PreBalance, PostBalance PreBalanceInUSD, PostBalanceInUSD } } ``` **Use cases**: Balance change tracking, position monitoring, accumulation/distribution detection. **Table**: `{chain}_dex_pool_events_enriched` **Selectors**: `poolAddress`, `tokenAddress`, `date` **Metrics**: `count`, `sum`, `avg`, `max` **Key Fields:** ```graphql theme={null} DEXPoolEventsRecord { Block { Time } Transaction { Signature } Pool { Market { Address, BaseCurrency { ... }, QuoteCurrency { ... } } Dex { ProgramAddress, ProtocolName } Base { PostAmount, ChangeAmount, PriceInUSD } Quote { PostAmount, ChangeAmount } LiquidityInUSD } } ``` **Use cases**: Liquidity add/remove monitoring, pool TVL tracking, new pool detection. **Table**: `{chain}_token_supplies` **Selectors**: `tokenAddress` **Key Fields:** ```graphql theme={null} TokenSupplyUpdatesRecord { Block { Time } TokenSupplyUpdate { Currency { MintAddress, Decimals } PostBalance, MarketCapInUSD, PriceInUSD, FDVInUSD, TotalSupply } } ``` **Use cases**: Mint/burn event tracking, supply change alerts, market cap history. **Table**: `{chain}_blocks` **Selectors**: `date` **Metrics**: `count`, `sum`, `avg`, `min`, `max` **Key Fields:** ```graphql theme={null} BlocksRecord { Block { Time, Date, Height, Hash, ParentHash, TxCount # Solana-specific Slot, ParentSlot, RewardsCount # EVM-specific Number, Coinbase, GasLimit, GasUsed, BaseFee, Difficulty } } ``` **Use cases**: Block production monitoring, gas analysis (EVM), slot tracking (Solana). **Table**: `{chain}_transactions` **Selectors**: `date`, `txHash`/`txSignature`, `fromAddress`, `toAddress`, `feePayer`, `signer` **Metrics**: `count`, `sum`, `avg`, `min`, `max` **Key Fields:** ```graphql theme={null} TransactionsRecord { Block { Time, Slot, Height } Transaction { # Solana: Signature, Fee, FeePayer, Signer, Result { Success } # EVM: Hash, From, To, Value, Gas, GasPrice, Nonce, Type } Fee { ... } # EVM EIP-1559 fee breakdown Receipt { ... } # EVM receipt fields } ``` **Use cases**: Transaction lookup, gas/fee analysis, activity monitoring. **Table**: `{chain}_transaction_balances` **Selectors**: `date`, `address`, `currency` **Metrics**: `count`, `sum`, `avg`, `min`, `max` **Key Fields:** ```graphql theme={null} TransactionBalancesRecord { Block { Time } Transaction { Hash, Index } TokenBalance { Address, TokenAccount Currency { SmartContract, Symbol, Name, Decimals } PreBalance, PostBalance, Change PreBalanceInUSD, PostBalanceInUSD, ChangeInUSD UpdateType } } ``` **Use cases**: Per-transaction balance impact analysis, token flow tracing. This Cube does not support `dataset` switching (no `_realtime` / `_archive` table variants). *** ## Solana-Only Cubes These Cubes are only available in the **Solana** Chain Group. **Table**: `sol_instructions_enriched` **Selectors**: `date`, `programId`, `txSignature` **Metrics**: `count`, `uniq` **Key Fields:** ```graphql theme={null} InstructionsRecord { Block { Time, Slot } Transaction { Signature } Instruction { Index, Depth, InternalSeqNumber Program { Address, Name, Method } Accounts # Array of account addresses Data # Raw instruction data CallPath, Logs } } ``` **Use cases**: Program interaction analysis, instruction-level debugging, protocol usage tracking. **Table**: `sol_balance_updates_enriched` **Selectors**: `date`, `tokenAddress`, `ownerAddress`, `programId` **Metrics**: `count`, `sum`, `avg`, `min`, `max`, `uniq` **Key Fields:** ```graphql theme={null} InstructionBalanceUpdatesRecord { Block { Time, Slot } Transaction { Signature } Instruction { Index, Program { Address } } BalanceUpdate { Currency { MintAddress, Decimals } Account { Address, Owner } Amount, AmountInUSD PreBalance, PostBalance } } ``` **Use cases**: Instruction-level balance impact analysis, program fee tracking. This Cube does not support `dataset` switching. **Table**: `sol_rewards` **Selectors**: `date`, `address` **Metrics**: `count`, `sum`, `avg` **Key Fields:** ```graphql theme={null} RewardsRecord { Block { Time, Slot } Reward { Address # Validator/staker address Amount # Reward amount in SOL AmountInUSD # Reward value in USD PostBalance # Balance after reward RewardType # Type: voting, staking, etc. Commission # Validator commission } } ``` **Use cases**: Staking reward tracking, validator performance, reward history. **Table**: `sol_dex_orders` **Selectors**: `date`, `marketAddress`, `orderType`, `ownerAddress` **Metrics**: `count`, `sum`, `avg`, `uniq` **Key Fields:** ```graphql theme={null} DEXOrdersRecord { Block { Time, Slot } Transaction { Signature } OrderEvent { Type # Order type (place, cancel, fill, etc.) Market { Address } Order { Id, BuySide, LimitPrice, Mint, Owner } Dex { ProgramAddress, ProtocolName } } } ``` **Use cases**: Order book analysis, limit order tracking, market microstructure research. *** ## EVM-Only Cubes These Cubes are only available in the **EVM** Chain Group (`eth`, `bsc`, `polygon`). **Table**: `{chain}_logs_enriched` **Selectors**: `date`, `contractAddress`, `txHash`, `topic0` **Metrics**: `count`, `uniq` **Key Fields:** ```graphql theme={null} EventsRecord { Block { Time, Number } Transaction { Hash, From, To } Log { SmartContract # Contract emitting the event Index # Log index in transaction Signature { Name, Signature } Topics # Event topics array Data # ABI-encoded event data } } ``` **Use cases**: Smart contract event monitoring, protocol activity tracking, custom event filtering. **Table**: `{chain}_traces_enriched` **Selectors**: `date`, `txHash`, `toAddress` **Metrics**: `count`, `sum`, `uniq` **Key Fields:** ```graphql theme={null} CallsRecord { Block { Time, Number } Transaction { Hash } Call { Index, Depth From, To Opcode # CALL, DELEGATECALL, STATICCALL, CREATE, etc. Gas, GasUsed Input, Output Value # ETH/BNB transferred Signature { Name, Signature } } } ``` **Use cases**: Internal transaction tracing, contract interaction analysis, MEV detection. **Table**: `{chain}_miner_rewards` **Selectors**: `date`, `miner` **Metrics**: `count`, `sum`, `avg`, `min`, `max` **Key Fields:** ```graphql theme={null} MinerRewardsRecord { Block { Time, Number, Hash } Reward { Miner TotalReward, TotalRewardInUSD BurntFees, DynamicReward, StaticReward TxFees, UncleReward } } ``` **Use cases**: Validator/miner reward analysis, block reward trends, MEV revenue tracking. **Table**: `{chain}_dex_pool_slippages` **Selectors**: `date`, `poolAddress` **Metrics**: `count`, `avg`, `min`, `max` **Key Fields:** ```graphql theme={null} DEXPoolSlippagesRecord { Block { Time } Price { Pool { SmartContract, CurrencyA { ... }, CurrencyB { ... } } AtoB, BtoA # Current prices AtoBMin, AtoBMax # Price range SlippageBasisPoints # Slippage in basis points Dex { ProtocolName } } } ``` **Use cases**: Slippage monitoring, pool depth analysis, execution quality assessment. **Table**: `{chain}_uncles` **Selectors**: `date`, `miner` **Metrics**: `count` **Key Fields:** ```graphql theme={null} UnclesRecord { Block { Time, Number } Uncle { Index, Hash, ParentHash Miner, Difficulty, Number GasLimit, GasUsed, Timestamp } } ``` **Use cases**: Uncle block analysis, network health monitoring (primarily Ethereum PoW historical data). *** ## Trading Cubes (Cross-chain) These Cubes are in the **Trading** Chain Group. They aggregate data across all supported chains (`sol`, `eth`, `bsc`) and include a `chain` dimension for filtering. **Table**: Materialized views across chains (`{chain}_ohlc_mv`) **Selectors**: `tokenAddress`, `chain`, `date` **Metrics**: `count`, `sum`, `avg`, `min`, `max` **Key Fields:** ```graphql theme={null} PairsRecord { Token { Address } Market { Network } # Chain identifier (sol, eth, bsc) Block { Time } Interval { Time } # Minute-bucket timestamp Price { Ohlc { Open, High, Low, Close } } Volume { Usd, Native } Stats { TradeCount, BuyCount, SellCount } } ``` **Use cases**: Candlestick charts, price history, volume analysis, cross-chain price comparison. **Table**: Materialized views across chains (`{chain}_token_trade_stats_mv`) **Selectors**: `tokenAddress`, `chain`, `date` **Metrics**: `count`, `sum`, `avg`, `min`, `max` **Key Fields:** ```graphql theme={null} TokensRecord { Token { Address } Market { Network } # Chain identifier Block { Time } Interval { Time } # Minute-bucket timestamp Volume { Usd, BuyVolumeUSD, SellVolumeUSD, Base } Stats { TradeCount, BuyCount, SellCount UniqueBuyers, UniqueSellers } } ``` **Use cases**: Buy/sell pressure analysis, unique trader counts, volume trends, cross-chain token comparison. *** ## Summary Cubes (DWS) Summary Cubes provide **highly aggregated, snapshot-style** data for quick lookups. **Table**: `{chain}_dex_pools` (DWS layer) **Selectors**: `poolAddress`, `tokenA`, `tokenB` **Metrics**: `count` **Key Fields:** ```graphql theme={null} DEXPoolsRecord { Pool { Address TokenAAddress, TokenBAddress ProgramAddress LiquidityUSD PriceAtoB, PriceBtoA LastUpdated } } ``` **Use cases**: Pool discovery, current liquidity rankings, pool metadata lookup. This Cube does not support `dataset` switching or time-based filtering. It represents the latest snapshot of pool state. **Table**: `{chain}_token_holders` **Selectors**: `tokenAddress` **Key Fields:** ```graphql theme={null} TokenHoldersRecord { Token { Address } Holder { Address } LatestBalance LatestBalanceUSD FirstSeen LastSeen } ``` **Use cases**: Top holders list, holder distribution, whale tracking. This Cube does not support `dataset` switching. **Table**: `{chain}_wallet_token_pnl` **Selectors**: `walletAddress` **Key Fields:** ```graphql theme={null} WalletTokenPnLRecord { Wallet { Address } Token { Address } BuyVolumeUSDState, SellVolumeUSDState BuyCountState, SellCountState FirstTradeState, LastTradeState } ``` **Use cases**: Wallet PnL per token, trading performance leaderboards, portfolio analysis. This Cube does not support `dataset` switching. *** ## Prediction Market Cubes These Cubes are available in the **EVM** Chain Group, primarily used on Polygon for prediction market protocols. **Table**: `{chain}_prediction_trades` **Selectors**: `date`, `conditionId`, `questionId`, `marketplace` **Metrics**: `count`, `sum`, `avg`, `min`, `max`, `uniq` **Key Fields:** ```graphql theme={null} PredictionTradesRecord { Block { Time } Transaction { Hash } Trade { Buyer, Seller, Amount, Price, Fee } Prediction { Condition { Id, Outcomes } Question { Id } Outcome, OutcomeToken Marketplace { ProtocolName } CollateralToken { SmartContract } } } ``` **Use cases**: Prediction market trade history, outcome pricing, marketplace volume. Prediction Market Cubes do not support `dataset` switching. **Table**: `{chain}_prediction_managements` **Selectors**: `date`, `eventType`, `conditionId`, `questionId` **Metrics**: `count`, `sum`, `avg`, `min`, `max`, `uniq` **Key Fields:** ```graphql theme={null} PredictionManagementsRecord { Block { Time } Transaction { Hash } Management { EventType, Description, Group Prediction { Condition { ... }, Question { ... }, Marketplace { ... } } } } ``` **Use cases**: Market creation/resolution tracking, condition management events. **Table**: `{chain}_prediction_settlements` **Selectors**: `date`, `eventType`, `conditionId`, `holder` **Metrics**: `count`, `sum`, `avg`, `min`, `max`, `uniq` **Key Fields:** ```graphql theme={null} PredictionSettlementsRecord { Block { Time } Transaction { Hash } Settlement { EventType, Holder OutcomeTokenIds, Amounts Prediction { Condition { ... }, CollateralToken { ... }, Marketplace { ... } } } } ``` **Use cases**: Settlement tracking, payout analysis, position redemption monitoring. *** ## Choosing the Right Cube Pick the most aggregated Cube that satisfies your query. DWM/DWS Cubes are orders of magnitude faster than DWD Cubes for time-series and summary data. | Need | Recommended Cube | Layer | | :-------------------------- | :--------------- | :---- | | Individual trade events | DEXTrades | DWD | | Per-token trade queries | DEXTradeByTokens | DWD | | Token transfer history | Transfers | DWD | | Candlestick / price charts | Pairs | DWM | | Trade volume over time | Tokens | DWM | | Current top holders | TokenHolders | DWS | | Wallet PnL breakdown | WalletTokenPnL | DWS | | Pool current state | DEXPools | DWS | | Liquidity events | DEXPoolEvents | DWD | | Smart contract events (EVM) | Events | DWD | | Internal traces (EVM) | Calls | DWD | | Solana instructions | Instructions | DWD | | Prediction market trades | PredictionTrades | DWD | *** ## Dataset Compatibility Not all Cubes support the `dataset` parameter (realtime/archive/combined). The following Cubes always query the full table regardless of the `dataset` value: * `TokenHolders`, `WalletTokenPnL`, `DEXPools` (DWS layer — always latest snapshot) * `TransactionBalances` * `PredictionTrades`, `PredictionManagements`, `PredictionSettlements` See [Dataset & Aggregates](/en/graphql/schema/dataset-aggregates) for details. *** ## Next Steps Understand the EVM, Solana, and Trading Chain Groups. Learn to filter with `where` and selector shortcuts. Aggregate data with count, sum, avg, min, max, uniq. # Dataset & Aggregates Source: https://docs.chainstream.io/en/graphql/schema/dataset-aggregates Control data source scope and pre-aggregation behavior with the dataset and aggregates parameters ## Overview Every Chain Group in ChainStream GraphQL accepts two optional parameters that control **which underlying tables** are queried. These parameters let you optimize for freshness, query speed, or data completeness depending on your use case. *** ## Dataset Parameter The `dataset` parameter controls the **time scope** of the data being queried. It determines whether the query hits real-time tables, archive tables, or both. | Value | Description | Typical Use Case | | :--------- | :-------------------------------------------------------------------------------------------- | :----------------------------------------------------- | | `combined` | Queries both real-time and archive data **(default)** — typically covers the last \~7–10 days | General-purpose queries where you need the full range | | `realtime` | Only recent data (approximately the last 24 hours) | Monitoring dashboards, latest trades, real-time alerts | | `archive` | Only historical data within the retention window (\~7–10 days) | Historical analysis, backfilling, trend research | ### Usage ```graphql theme={null} query { Solana(dataset: realtime) { DEXTrades(limit: {count: 10}, orderBy: {descending: Block_Time}) { Block { Time } Trade { Buy { Currency { MintAddress } Amount PriceInUSD } } } } } ``` ```graphql theme={null} query { EVM(network: eth, dataset: archive) { Transfers( where: { Block: { Time: { after: "2026-01-01T00:00:00Z", before: "2026-02-01T00:00:00Z" } } } limit: {count: 100} ) { Block { Time } Transfer { Currency { MintAddress } Amount AmountInUSD } } } } ``` ### Historical Data Backfilling When building data pipelines or recovering from downtime, you can use `dataset: archive` with time-range filters to backfill historical data: 1. Record the last processed timestamp or block height 2. Query `dataset: archive` with a `where` filter from your last checkpoint to the current time 3. Process the backfilled data 4. Switch to `dataset: realtime` for ongoing monitoring ```graphql theme={null} query BackfillTrades { Solana(dataset: archive) { DEXTrades( where: { Block: { Time: { after: "2026-04-01T00:00:00Z" before: "2026-04-02T00:00:00Z" } } } limit: {count: 10000} orderBy: {ascending: Block_Time} ) { Block { Time Slot } Transaction { Hash } Trade { Buy { Currency { MintAddress } Amount PriceInUSD } Sell { Currency { MintAddress } Amount } } } } } ``` ### Tables Without Dataset Support Some Cubes always query the same table regardless of the `dataset` value. These include: * **DWS Cubes**: `TokenHolders`, `WalletTokenPnL`, `DEXPools` — these represent current-state snapshots * **Special tables**: `TransactionBalances`, `PredictionTrades`, `PredictionManagements`, `PredictionSettlements` For these Cubes, `dataset` is silently ignored. *** ## Aggregates Parameter The `aggregates` parameter controls whether the query uses **pre-aggregated materialized views** (DWM layer) instead of raw detail tables (DWD layer). Pre-aggregated tables contain pre-computed rollups (typically per-minute) that are significantly faster to query. | Value | Description | Typical Use Case | | :----- | :----------------------------------------------------------------- | :--------------------------------------------- | | `yes` | Prefer pre-aggregated tables when available **(default behavior)** | Most analytical queries | | `no` | Use raw detail tables only | When you need per-event granularity | | `only` | Only use pre-aggregated tables | Maximum query speed, accepts limited field set | ### Usage ```graphql theme={null} query { EVM(network: eth, aggregates: only) { Pairs( where: { Token: { Address: { is: "0xdac17f958d2ee523a2206206994597c13d831ec7" } } } limit: {count: 100} orderBy: {descending: Block_Time} ) { Interval { Time } Price { Ohlc { Open High Low Close } } Volume { Usd } } } } ``` ### When to Use Each Mode | Scenario | Recommended | Why | | :------------------------ | :----------------- | :----------------------------------------------- | | Building OHLC charts | `aggregates: only` | Pre-computed candlestick data, fastest response | | Volume trends over time | `aggregates: yes` | Leverages pre-aggregated volume stats | | Individual trade analysis | `aggregates: no` | Need per-event detail that rollups don't provide | | Counting unique traders | `aggregates: yes` | Pre-computed unique counts available | *** ## Combining Both Parameters You can use `dataset` and `aggregates` together: ```graphql theme={null} query { Trading(dataset: realtime, aggregates: yes) { Tokens( where: { Token: { Address: { is: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" } } } limit: {count: 60} orderBy: {descending: Block_Time} ) { Interval { Time } Volume { Usd BuyVolumeUSD SellVolumeUSD } Stats { TradeCount UniqueBuyers UniqueSellers } } } } ``` This query fetches the last \~60 minutes of cross-chain token trade statistics using real-time data with pre-aggregated tables for maximum speed. *** ## Performance Considerations `dataset: realtime` queries a smaller table partition, resulting in faster response times for monitoring use cases. `aggregates: yes` or `only` leverages pre-computed rollups that are orders of magnitude faster than scanning raw event tables. For the fastest possible OHLC or volume queries, combine `dataset: realtime` with `aggregates: only`. This targets the smallest, most optimized data slice. *** ## Related Documentation See how dataset and aggregates fit into the overall query structure. Check which Cubes support dataset switching. # Filtering Source: https://docs.chainstream.io/en/graphql/schema/filtering Filter query results using selector shortcuts and the where argument — operators, nested filters, OR logic, and defaults There are two ways to filter data in ChainStream GraphQL: 1. **Selector shortcuts** — top-level arguments like `tokenAddress` that provide a convenient shorthand for common filters 2. **`where` argument** — a nested filter object that supports the full range of operators and arbitrary dimension filtering **Best Practice: Always add a time filter.** For DWD (detail) Cubes like DEXTrades, Transfers, and BalanceUpdates, queries without a `Block.Time` filter may scan very large table partitions. Always include `where: {Block: {Time: {after: "..."}}}` to limit the scan range and avoid potential memory limits on the OLAP engine. You can combine both in the same query. *** ## Selector Shortcuts Selectors are **convenience arguments** on Cube fields that map to common `where` filter patterns. They accept the same filter input types as `where` fields (e.g., `StringFilter` with `is`, `in`, `like`, etc.), not plain strings. | Selector | Maps To | Available On | | :---------------- | :----------------------------------------- | :------------------------------------------------------------------------------------------------------------- | | `tokenAddress` | Primary token address column for each Cube | DEXTrades, Transfers, BalanceUpdates, DEXPools, TokenSupplyUpdates, Pairs, Tokens, DEXPoolEvents, TokenHolders | | `walletAddress` | Wallet/account owner address | DEXTrades, WalletTokenPnL | | `poolAddress` | Pool contract address | DEXTrades, DEXPools | | `senderAddress` | Transfer sender address | Transfers | | `receiverAddress` | Transfer receiver address | Transfers | | `ownerAddress` | Token account owner address | BalanceUpdates | | `dexProgram` | DEX program/contract address | DEXTrades | | `date` | Block timestamp (DateTime filter) | DEXTrades, Transfers, BalanceUpdates, DEXPools | **These two queries are equivalent:** ```graphql theme={null} query { Solana { DEXTrades( tokenAddress: {is: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"} limit: { count: 10 } ) { Block { Time } Trade { Buy { Amount PriceInUSD } } } } } ``` ```graphql theme={null} query { Solana { DEXTrades( where: { Trade: { Buy: { Currency: { MintAddress: { is: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" } } } } } limit: { count: 10 } ) { Block { Time } Trade { Buy { Amount PriceInUSD } } } } } ``` Selectors support all filter operators — not just exact match. For example, `tokenAddress: {in: ["ADDR_1", "ADDR_2"]}` matches multiple tokens, and `date: {after: "2025-01-01T00:00:00Z"}` filters by time. *** ## The `where` Argument The `where` argument accepts a nested input object that mirrors the Cube's dimension hierarchy. Each leaf field maps to a **filter primitive** with typed operators. ### Structure ```graphql theme={null} where: { DimensionGroup: { DimensionField: { operator: value } } } ``` **Example** — Filter DEXTrades where block time is after a date AND buy amount is greater than 1000: ```graphql theme={null} query { Solana { DEXTrades( where: { Block: { Time: { after: "2025-01-01T00:00:00Z" } } Trade: { Buy: { Amount: { gt: 1000 } } } } limit: { count: 20 } ) { Block { Time } Trade { Buy { Amount PriceInUSD } } } } } ``` When multiple fields are specified at the same level in `where`, they are combined with **AND** logic. *** ## Filter Primitive Types Every leaf dimension maps to one of these filter input types: ### StringFilter For text fields like addresses, hashes, protocol names. | Operator | Type | Description | | :------- | :---------- | :--------------------------------------- | | `is` | `String` | Exact match | | `not` | `String` | Not equal | | `in` | `[String!]` | Matches any value in the list | | `notIn` | `[String!]` | Excludes all values in the list | | `like` | `String` | SQL LIKE pattern matching (`%` wildcard) | ```graphql theme={null} where: { Trade: { Dex: { ProtocolName: { in: ["Raydium", "Orca"] } } } } ``` ### IntFilter / FloatFilter For numeric fields like amounts, prices, counts. | Operator | Type | Description | | :------- | :---------- | :------------------------------ | | `eq` | `Number` | Equal to | | `ne` | `Number` | Not equal to | | `gt` | `Number` | Greater than | | `gte` | `Number` | Greater than or equal | | `lt` | `Number` | Less than | | `lte` | `Number` | Less than or equal | | `in` | `[Number!]` | Matches any value in the list | | `notIn` | `[Number!]` | Excludes all values in the list | ```graphql theme={null} where: { Trade: { Buy: { PriceInUSD: { gte: 0.001, lte: 1.0 } } } } ``` ### DateTimeFilter For timestamp fields. Values are ISO 8601 strings. | Operator | Type | Description | | :-------- | :----------------------- | :--------------------------------- | | `after` | `DateTime` | After this timestamp (exclusive) | | `before` | `DateTime` | Before this timestamp (exclusive) | | `since` | `DateTime` | Since this timestamp (inclusive) | | `till` | `DateTime` | Until this timestamp (inclusive) | | `between` | `[DateTime!, DateTime!]` | Between two timestamps (inclusive) | ```graphql theme={null} where: { Block: { Time: { since: "2025-03-01T00:00:00Z", till: "2025-03-31T23:59:59Z" } } } ``` `after`/`before` are **exclusive** (strict inequality). `since`/`till` are **inclusive**. `between` takes a two-element array and is inclusive on both ends. ### BoolFilter For boolean fields. | Operator | Type | Description | | :------- | :-------- | :------------------------- | | `eq` | `Boolean` | Equal to `true` or `false` | ```graphql theme={null} where: { IsSuspect: { eq: true } } ``` *** ## OR Logic with `any` By default, all conditions in `where` are combined with AND. To express OR logic, use the `any` array field — each element is a full filter object, and records matching **any** of them are returned. ```graphql theme={null} query { Solana { DEXTrades( where: { any: [ { Trade: { Buy: { Currency: { MintAddress: { is: "TOKEN_A" } } } } } { Trade: { Buy: { Currency: { MintAddress: { is: "TOKEN_B" } } } } } ] } limit: { count: 20 } ) { Trade { Buy { Currency { MintAddress } Amount } } } } } ``` `any` can be combined with other top-level `where` fields. The `any` conditions are OR'd together, then AND'd with any sibling conditions. *** ## Default Filters Some Cubes apply default filters automatically. You can override them by explicitly setting the filter in your `where` clause. | Cube | Default Filter | Effect | | :-------- | :------------------ | :--------------------------------- | | DEXTrades | `IsSuspect = false` | Excludes bot/MEV trades by default | To **include** suspect trades, explicitly set the filter: ```graphql theme={null} query { Solana { DEXTrades( where: { IsSuspect: { eq: true } } limit: { count: 10 } ) { Block { Time } Trade { Buy { Amount } } IsSuspect } } } ``` Or remove the filter entirely by not specifying `IsSuspect` in `where` — the default `false` still applies. To query **all** trades regardless of suspect status, use OR: ```graphql theme={null} where: { any: [ { IsSuspect: { eq: true } } { IsSuspect: { eq: false } } ] } ``` *** ## Combining Selectors and `where` Selectors and `where` filters are combined with AND. This lets you use selectors for the primary entity and `where` for additional refinement: ```graphql theme={null} query { Solana { DEXTrades( tokenAddress: {is: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"} where: { Block: { Time: { after: "2025-03-01T00:00:00Z" } } Trade: { Buy: { Amount: { gt: 100 } } } } orderBy: {descending: Block_Time} limit: { count: 50 } ) { Block { Time } Transaction { Hash } Trade { Buy { Amount PriceInUSD } Sell { Currency { MintAddress } Amount } Dex { ProtocolName } } } } } ``` This query fetches the 50 most recent USDC trades on Solana where the buy amount exceeds 100, ordered by time descending. *** ## Next Steps Sort results and page through data with `orderBy` and `limit`. Aggregate filtered data with count, sum, avg, min, max, uniq. # Metrics & Aggregation Source: https://docs.chainstream.io/en/graphql/schema/metrics-aggregation Aggregate data with count, sum, avg, min, max, and uniq — the of parameter, selectWhere for HAVING, and when to use metrics vs pre-aggregated Cubes ## What Are Metrics? Metrics are **aggregation functions** available as fields on Cube Record types. They let you compute statistics directly in your GraphQL query without post-processing. When you select a metric field alongside dimension fields, the query groups by the selected dimensions and computes the metric for each group. **Supported metrics:** | Metric | SQL Equivalent | Description | | :------ | :---------------------------- | :---------------------------- | | `count` | `COUNT(*)` or `COUNT(column)` | Count rows or distinct values | | `sum` | `SUM(column)` | Sum of numeric values | | `avg` | `AVG(column)` | Average of numeric values | | `min` | `MIN(column)` | Minimum value | | `max` | `MAX(column)` | Maximum value | | `uniq` | `COUNT(DISTINCT column)` | Count of unique values | *** ## Metric Fields on Record Types Metrics appear as **top-level fields** on each Cube's Record type. Not all Cubes support all metrics — it depends on the Cube definition. ```graphql theme={null} type DEXTradesRecord { # Dimension fields... Block { ... } Trade { ... } # Metric fields count: Int sum(of: DEXTradesSumOf!): Float } ``` To use a metric, simply include it in your field selection: ```graphql theme={null} query { Solana { DEXTrades( tokenAddress: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" where: { Block: { Time: { after: "2025-03-27T00:00:00Z" } } } ) { count Trade { Dex { ProtocolName } } } } } ``` This query groups DEX trades by protocol name and returns the count for each group. *** ## The `of` Parameter Metrics like `sum`, `avg`, `min`, `max`, and `uniq` require an `of` parameter that specifies **which dimension** to aggregate. The `of` value is an enum generated per Cube, following the dimension path naming convention. ```graphql theme={null} sum(of: Trade_Buy_Amount) avg(of: Trade_Buy_PriceInUSD) min(of: Block_Time) max(of: Trade_Sell_Amount) uniq(of: Trade_Buy_Account_Owner) ``` ### Example: Total Buy Volume by DEX ```graphql theme={null} query { Solana { DEXTrades( tokenAddress: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" where: { Block: { Time: { after: "2025-03-27T00:00:00Z" } } } ) { count sum(of: Trade_Buy_Amount) Trade { Dex { ProtocolName } } } } } ``` **Response:** ```json theme={null} { "data": { "Solana": { "DEXTrades": [ { "count": 1842, "sum": 2847291.45, "Trade": { "Dex": { "ProtocolName": "Raydium" } } }, { "count": 923, "sum": 1293847.12, "Trade": { "Dex": { "ProtocolName": "Orca" } } } ] } } } ``` *** ## count — Counting Rows `count` without an `of` parameter counts the total rows in each group (equivalent to `COUNT(*)`): ```graphql theme={null} query { Solana { DEXTrades( where: { Block: { Time: { after: "2025-03-27T00:00:00Z" } } } ) { count } } } ``` When used with dimension fields, it returns the count per group: ```graphql theme={null} query { Solana { DEXTrades( where: { Block: { Time: { after: "2025-03-27T00:00:00Z" } } } ) { count Trade { Dex { ProtocolName } } } } } ``` *** ## uniq — Count Distinct `uniq` maps to `COUNT(DISTINCT column)` in SQL. Use it to count unique values of a dimension: ```graphql theme={null} query { Solana { DEXTrades( tokenAddress: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" where: { Block: { Time: { after: "2025-03-27T00:00:00Z" } } } ) { uniq(of: Trade_Buy_Account_Owner) } } } ``` This returns the number of **unique buyer wallets** that traded USDC today on Solana. *** ## selectWhere — HAVING-Style Filtering `selectWhere` lets you filter **on aggregation results**, similar to SQL's `HAVING` clause. It is applied after grouping and aggregation, allowing you to filter groups based on their metric values. ```graphql theme={null} query { Solana { DEXTrades( where: { Block: { Time: { after: "2026-04-01T00:00:00Z" } } } ) { count(selectWhere: { gt: "100" }) Trade { Dex { ProtocolName } } } } } ``` This returns only DEX protocols that had **more than 100 trades** — protocols with fewer trades are excluded from the result. `selectWhere` values must be passed as **strings** (e.g., `"100"` not `100`). They are parsed as numeric values internally. `selectWhere` supports these comparison operators: | Operator | Description | | :------- | :-------------------- | | `gt` | Greater than | | `ge` | Greater than or equal | | `lt` | Less than | | `le` | Less than or equal | | `eq` | Equal to | **Known limitation:** When using `selectWhere`, the `orderBy` field must reference a dimension that is part of the implicit GROUP BY (i.e., a field you are selecting) or an aggregation result. Ordering by a field not in the GROUP BY (e.g., `Block_Time`) will produce a database error. *** ## Practical Example: Top Traders Find the top 10 wallets by trade count for a token today, showing their total buy volume and unique trade count: ```graphql theme={null} query TopTraders { Solana { DEXTrades( tokenAddress: "DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263" where: { Block: { Time: { after: "2025-03-27T00:00:00Z" } } } orderBy: {descending: Block_Time} limit: { count: 10 } ) { count sum(of: Trade_Buy_Amount) Trade { Buy { Account { Owner } } } } } } ``` **Response:** ```json theme={null} { "data": { "Solana": { "DEXTrades": [ { "count": 47, "sum": 892341023.5, "Trade": { "Buy": { "Account": { "Owner": "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU" } } } }, { "count": 31, "sum": 451203847.2, "Trade": { "Buy": { "Account": { "Owner": "3kMq5RezM9XBbBGRNxP9vXkJHAfG8S7gn5WfBsHFQr7T" } } } } ] } } } ``` *** ## Combining Multiple Metrics You can select multiple metric fields in a single query: ```graphql theme={null} query { Solana { DEXTrades( tokenAddress: "So11111111111111111111111111111111111111112" where: { Block: { Time: { after: "2025-03-27T00:00:00Z" } } } ) { count sum(of: Trade_Buy_Amount) min(of: Trade_Buy_PriceInUSD) max(of: Trade_Buy_PriceInUSD) uniq(of: Trade_Buy_Account_Owner) Trade { Dex { ProtocolName } } } } } ``` This returns per-DEX statistics: trade count, total volume, price range, and unique traders — all in one query. *** ## Metrics vs Pre-Aggregated Cubes A common question: should I use metrics on DWD Cubes or query DWM/DWS Cubes directly? | Approach | When to Use | Performance | | :----------------------------------------------------- | :----------------------------------------------------------- | :--------------------------------------------- | | **Metrics on DWD** (e.g., `DEXTrades.count`) | Custom aggregations, ad-hoc groupings, flexible time windows | Slower — aggregates raw events at query time | | **DWM Cubes** (e.g., `Pairs`, `Tokens`) | Standard time-series analysis, OHLC charts, volume over time | Fast — reads pre-computed minute-level rollups | | **DWS Cubes** (e.g., `TokenHolders`, `WalletTokenPnL`) | Current snapshots, cumulative totals, leaderboards | Fastest — reads pre-aggregated summary data | **Rule of thumb**: Use DWM/DWS Cubes when they cover your use case — they're pre-aggregated and significantly faster. Fall back to DWD Cubes with metrics when you need custom groupings or aggregation logic that pre-built Cubes don't support. ### Decision Guide Use **Pairs** (DWM). It already has pre-computed open/high/low/close/volume per minute. No need to aggregate DEXTrades yourself. Use **Tokens** (DWM). It pre-aggregates trade counts, volumes, and unique traders per minute. Use **TokenHolders** (DWS). Pre-computed latest balances per holder — much faster than aggregating BalanceUpdates. Use **DEXTrades** with `count` + `sum(of: Trade_Buy_Amount)` grouped by `Trade.Dex.ProtocolName`. This isn't available as a pre-built Cube, so DWD metrics are the right choice. Use **WalletTokenPnL** (DWS). Pre-computed buy/sell volumes and trade counts per wallet-token pair. *** ## Next Steps Explore all 25 Cubes and their field structures. See real-world query examples with metrics and aggregation. # Ordering & Pagination Source: https://docs.chainstream.io/en/graphql/schema/ordering-pagination Sort query results with the orderBy input object and paginate with limit — naming conventions, defaults, and offset-based pagination ## orderBy InputObject Each Cube generates an `{Cube}OrderBy` input object with `ascending` and `descending` fields. Each field accepts a `CompareFields` enum value that follows the dimension path joined by underscores: ``` {DimensionGroup}_{DimensionField} ``` For nested dimensions, each level is joined: ``` Block_Time Trade_Buy_Amount Trade_Buy_PriceInUSD ``` Usage: ```graphql theme={null} orderBy: {descending: Block_Time} # newest first orderBy: {ascending: Trade_Buy_Amount} # smallest amount first ``` ### Common CompareFields Values
| CompareFields Value | Example Usage | Cube(s) | Description | | :--------------------- | :-------------------------------------------- | :-------------------------------------------------------------------------------- | :--------------------------------- | | `Block_Time` | `orderBy: {descending: Block_Time}` | DEXTrades, Transfers, BalanceUpdates, DEXPools, TokenSupplyUpdates, Pairs, Tokens | Newest first | | `Block_Time` | `orderBy: {ascending: Block_Time}` | DEXTrades, Transfers, BalanceUpdates, DEXPools, TokenSupplyUpdates, Pairs, Tokens | Oldest first | | `Interval_Time_Start` | `orderBy: {ascending: Interval_Time_Start}` | Pairs, Tokens | Oldest first (interval start time) | | `Trade_Buy_Amount` | `orderBy: {descending: Trade_Buy_Amount}` | DEXTrades | Largest buy amount first | | `Trade_Buy_PriceInUSD` | `orderBy: {descending: Trade_Buy_PriceInUSD}` | DEXTrades | Highest USD price first | | `Transfer_AmountInUSD` | `orderBy: {descending: Transfer_AmountInUSD}` | Transfers | Largest USD transfer first | | `LatestBalanceUSD` | `orderBy: {descending: LatestBalanceUSD}` | TokenHolders | Largest holder first | | `BuyVolumeUSDState` | `orderBy: {descending: BuyVolumeUSDState}` | WalletTokenPnL | Highest buy volume first |
Use the [GraphQL IDE](https://ide.chainstream.io) auto-complete to discover all available `CompareFields` values for a Cube — type `orderBy: {descending:` and the IDE will show available fields. ### Usage Pass an `orderBy` input object with either `descending` or `ascending` set to a `CompareFields` value: ```graphql theme={null} query { Solana { DEXTrades( orderBy: {descending: Block_Time} limit: { count: 10 } ) { Block { Time } Trade { Buy { Amount PriceInUSD } } } } } ``` `orderBy` accepts a **single** direction/field pair. Multi-column sorting is not supported — the query is sorted by one dimension at a time. *** ## limit Argument The `limit` argument controls how many rows are returned and supports offset-based pagination: ```graphql theme={null} input LimitInput { count: Int # Number of rows to return offset: Int # Number of rows to skip } ``` ### Default and Maximum Limits Each Cube has a **default** limit applied when you omit the `limit` argument, and a **maximum** cap: | Cube | Default `count` | Maximum `count` | | :----------------- | :-------------- | :-------------- | | DEXTrades | 25 | 10,000 | | Transfers | 25 | 10,000 | | BalanceUpdates | 25 | 10,000 | | DEXPools | 25 | 10,000 | | TokenSupplyUpdates | 25 | 10,000 | | Pairs | 25 | 10,000 | | Tokens | 25 | 10,000 | | DEXPoolEvents | 25 | 10,000 | | TokenHolders | 25 | 10,000 | | WalletTokenPnL | 25 | 10,000 | If you request a `count` exceeding the maximum, the server silently caps it at the maximum value. *** ## Offset-Based Pagination Use `offset` to page through result sets. The pattern is straightforward: * **Page 1**: `limit: { count: 50, offset: 0 }` * **Page 2**: `limit: { count: 50, offset: 50 }` * **Page 3**: `limit: { count: 50, offset: 100 }` ### Example: Paginated Token Holders ```graphql theme={null} query { Solana { TokenHolders( tokenAddress: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" orderBy: {descending: LatestBalanceUSD} limit: { count: 20, offset: 0 } ) { Holder { Address } LatestBalance LatestBalanceUSD } } } ``` ```graphql theme={null} query { Solana { TokenHolders( tokenAddress: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" orderBy: {descending: LatestBalanceUSD} limit: { count: 20, offset: 20 } ) { Holder { Address } LatestBalance LatestBalanceUSD } } } ``` ### Pagination Tips Without a stable sort order, rows may shift between pages. Always pair `limit` with an `orderBy` that produces a deterministic order. Large `offset` values (e.g., 50,000+) may degrade performance since the database must scan and skip rows. For very large datasets, narrow your query with `where` filters instead of paginating deeply. If a page returns fewer rows than the requested `count`, you've reached the end of the dataset. Alternatively, use the `count` metric field to get total row count upfront. *** ## Practical Examples ### Latest Large Trades Fetch the 10 most recent DEX trades on Solana with a buy value over \$10,000: ```graphql theme={null} query { Solana { DEXTrades( where: { Trade: { Buy: { PriceInUSD: { gt: 10000 } } } } orderBy: {descending: Block_Time} limit: { count: 10 } ) { Block { Time } Trade { Buy { Currency { MintAddress } Amount PriceInUSD } Dex { ProtocolName } } } } } ``` ### OHLC Candles — Last 60 Minutes Fetch 1-minute candles for a token, sorted chronologically: ```graphql theme={null} query { Trading { Pairs( where: { Token: { Address: { is: "So11111111111111111111111111111111111111112" } } Market: { Network: { is: "sol" } } Block: { Time: { after: "2025-03-27T09:00:00Z" } } } orderBy: {ascending: Block_Time} limit: { count: 60 } ) { Block { Time } Price { Ohlc { Open High Low Close } } Volume { Usd } Stats { TradeCount } } } } ``` ### Top 50 Token Holders Fetch the top 50 holders sorted by USD balance: ```graphql theme={null} query { Solana { TokenHolders( tokenAddress: "DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263" orderBy: {descending: LatestBalanceUSD} limit: { count: 50 } ) { Holder { Address } LatestBalance LatestBalanceUSD FirstSeen LastSeen } } } ``` *** ## Next Steps Combine ordering with filters to build precise analytical queries. Aggregate ordered data with count, sum, avg, min, max, uniq. # Schema Overview Source: https://docs.chainstream.io/en/graphql/schema/schema-overview How the ChainStream GraphQL schema is structured — Chain Groups, Cube fields, generated types, and introspection ## Dynamic Schema Generation The ChainStream GraphQL schema is **dynamically generated** at startup by **activecube-rs**, a Rust library that compiles **Cube** definitions into a fully-typed [async-graphql](https://github.com/async-graphql/async-graphql) schema. Each Cube maps to an analytical data model backed by an OLAP table, and activecube-rs automatically produces: * A **top-level Query field** for the Cube (nested under its Chain Group) * A **Record type** (`{Cube}Record`) representing the selectable dimensions * A **Filter input** (`{Cube}Filter`) matching the dimension hierarchy * An **OrderBy enum** (`{Cube}OrderBy`) with ASC/DESC variants for every dimension path This means the schema is always in sync with the underlying data models — no handwritten SDL files to maintain. Because the schema is generated from Cube definitions, any new data model added in Rust is automatically reflected in the GraphQL endpoint after deployment. *** ## Root Query Structure The root query type is named `ChainStream`. Cubes are organized into three **Chain Groups**, each exposed as a top-level field: ```graphql theme={null} type ChainStream { EVM(network: Network!, dataset: Dataset, aggregates: Aggregates) { DEXTrades(...): [DEXTradesRecord!]! Transfers(...): [TransfersRecord!]! BalanceUpdates(...): [BalanceUpdatesRecord!]! Blocks(...): [BlocksRecord!]! Transactions(...): [TransactionsRecord!]! Events(...): [EventsRecord!]! Calls(...): [CallsRecord!]! # ... more EVM Cubes } Solana(dataset: Dataset, aggregates: Aggregates) { DEXTrades(...): [DEXTradesRecord!]! Instructions(...): [InstructionsRecord!]! DEXOrders(...): [DEXOrdersRecord!]! # ... more Solana Cubes } Trading(dataset: Dataset, aggregates: Aggregates) { Pairs(...): [PairsRecord!]! Tokens(...): [TokensRecord!]! } } ``` There are no `Mutation` or `Subscription` types — the GraphQL API is read-only analytical queries. *** ## Chain Groups Cubes are organized into three groups based on the blockchain ecosystem they target: | Chain Group | `network` Argument | Available Networks | Description | | :---------- | :----------------- | :-------------------------------- | :----------------------------------------------------------------------------------------- | | **EVM** | Required | `eth`, `bsc`, `polygon` | Shared Cubes for all EVM-compatible chains | | **Solana** | Not needed | `sol` (implicit) | Cubes for Solana including chain-specific ones (Instructions, DEXOrders) | | **Trading** | Not needed | Cross-chain (`sol`, `eth`, `bsc`) | Pre-aggregated trading analytics (OHLC candles, token statistics) with a `chain` dimension | The **EVM** group requires a `network` argument to select which chain to query. **Solana** and **Trading** do not need a `network` argument — Solana is implicit, and Trading includes a `chain` dimension within the data. See [Chain Groups](/en/graphql/schema/chain-groups) for the full breakdown of which Cubes belong to each group. *** ## Chain Group Parameters Every Chain Group accepts two optional parameters that control data source behavior: ### Dataset The `dataset` parameter controls the time scope of data queried: | Value | Description | | :--------- | :----------------------------------------------------------------- | | `combined` | Full range — queries both recent and historical data **(default)** | | `realtime` | Recent data only (approximately the last 24 hours) | | `archive` | Historical data up to the retention TTL | ```graphql theme={null} query { Solana(dataset: realtime) { DEXTrades(limit: {count: 10}, orderBy: {descending: Block_Time}) { Block { Time } Trade { Buy { Amount } } } } } ``` ### Aggregates The `aggregates` parameter controls whether pre-aggregated (DWM/DWS) tables are used: | Value | Description | | :----- | :----------------------------------------------------------------------------- | | `yes` | Prefer pre-aggregated tables when available **(default for applicable Cubes)** | | `no` | Use raw detail tables only | | `only` | Only use pre-aggregated tables (faster but limited fields) | ```graphql theme={null} query { Trading(aggregates: only) { Pairs( where: { Token: { Address: { is: "0x..." } } } limit: {count: 100} ) { Interval { Time } Price { Ohlc { Open High Low Close } } Volume { Usd } } } } ``` See [Dataset & Aggregates](/en/graphql/schema/dataset-aggregates) for detailed usage, supported tables, and performance guidance. *** ## Common Argument Pattern Within a Chain Group, every Cube field accepts the same set of standard arguments, plus optional Cube-specific **selectors**: | Argument | Type | Required | Description | | :---------- | :-------------- | :------- | :---------------------------------------------------- | | `where` | `{Cube}Filter` | No | Nested filter object matching the dimension hierarchy | | `limit` | `LimitInput` | No | Pagination: `{count: Int, offset: Int}` | | `orderBy` | `{Cube}OrderBy` | No | Sort order enum (`{Path}_ASC` / `{Path}_DESC`) | | *selectors* | Filter input | No | Shortcut filters (e.g., `tokenAddress: {is: "..."}`) | ```graphql theme={null} query { Solana { DEXTrades( tokenAddress: {is: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"} where: { Block: { Time: { after: "2026-01-01T00:00:00Z" } } } limit: { count: 50, offset: 0 } orderBy: {descending: Block_Time} ) { Block { Time } Trade { Buy { Amount PriceInUSD } } } } } ``` ### LimitInput ```graphql theme={null} input LimitInput { count: Int # Number of rows to return offset: Int # Number of rows to skip (for pagination) } ``` Default `count` varies by Cube (typically 25). Maximum is 10,000 for most Cubes. *** ## Generated Types per Cube For each Cube, activecube-rs generates three companion types: `{Cube}Record` — The return type containing all selectable dimensions and metrics. Field structure mirrors the Cube's dimension hierarchy. `{Cube}Filter` — A nested input object where each dimension maps to a filter primitive (`StringFilter`, `IntFilter`, `DateTimeFilter`, etc.). `{Cube}OrderBy` — Enum variants for every dimension path in both ASC and DESC directions (e.g., `Block_Time_ASC`, `Trade_Buy_Amount_DESC`). **Example for DEXTrades:** ```graphql theme={null} # Record type (return shape) type DEXTradesRecord { Block: DEXTradesBlockRecord Transaction: DEXTradesTransactionRecord Trade: DEXTradesTradeRecord Pool: DEXTradesPoolRecord IsSuspect: Boolean count: Int sum(of: DEXTradesSumOf!): Float } # Filter input input DEXTradesFilter { Block: DEXTradesBlockFilter Transaction: DEXTradesTransactionFilter Trade: DEXTradesTradeFilter Pool: DEXTradesPoolFilter IsSuspect: BoolFilter any: [DEXTradesFilter!] # OR logic } # OrderBy enum (partial) enum DEXTradesOrderBy { Block_Time_ASC Block_Time_DESC Trade_Buy_Amount_ASC Trade_Buy_Amount_DESC # ... } ``` *** ## Introspection The schema supports standard GraphQL introspection. You can explore types, fields, and arguments using `__schema` and `__type` queries: ```graphql theme={null} query { __schema { queryType { fields { name description args { name type { name } } } } } } ``` ```graphql theme={null} query { __type(name: "DEXTradesRecord") { name fields { name type { name kind ofType { name } } } } } ``` ```graphql theme={null} query { __type(name: "StringFilter") { name inputFields { name type { name kind } } } } ``` The [GraphQL IDE](https://ide.chainstream.io) auto-fetches the introspection schema to power auto-complete and inline documentation. You can explore the full schema interactively without writing introspection queries manually. *** ## Next Steps Explore all 25 Cubes — their fields, selectors, and data warehouse layers. Understand the EVM, Solana, and Trading Chain Groups and their available Cubes. Control data source scope and pre-aggregation behavior with `dataset` and `aggregates`. Learn how to use `where` filters and selector shortcuts to narrow your queries. Sort results and paginate through large datasets with `orderBy` and `limit`. Use `count`, `sum`, `avg`, `min`, `max`, and `uniq` to aggregate data in your queries. # Changelog Source: https://docs.chainstream.io/en/changelog/index Version history for ChainStream API and SDKs ## 2026 ### 2026-02-04 **SDK v0.2.6 / v0.1.3** - Multi-language SDK Sync Update **SDK Updates** * TypeScript SDK v0.2.6 * WebSocket connection stability improvements * Fixed subscription reconnection issues * Python SDK v0.1.3 * Async client performance optimization * Enhanced type hints * Go SDK v0.1.3 * Error handling improvements * Memory usage optimization * Rust SDK v0.1.3 * First stable release * Complete API coverage *** ### 2026-02-03 **SDK v0.2.0** - Multi-language SDK Official Release **Major Updates** * 🎉 Python SDK v0.1.0 officially released * 🎉 Go SDK v0.1.0 officially released * 🎉 Rust SDK v0.1.0 officially released * TypeScript SDK upgraded to v0.2.x series **New Features** * Unified multi-language SDK architecture * Complete OpenAPI client support * WebSocket real-time data subscription **SDK Versions** | Language | Version | Status | | ---------- | ------- | ------ | | TypeScript | v0.2.4 | Stable | | Python | v0.1.1 | Stable | | Go | v0.1.1 | Stable | | Rust | v0.1.1 | Stable | *** ### 2026-01-29 **SDK Updates** * TypeScript SDK v0.1.26 * Full KYT API support * Webhook endpoint management API **Improvements** * KYT transaction risk assessment response time improved * Webhook signature verification documentation updated *** ### 2026-01-20 **New Features** * Token liquidity snapshots API (`/v1/token/{chain}/{address}/liquiditysnapshots`) * Token traders tag API (`/v1/token/{chain}/{address}/traders/tag`) **SDK Updates** * TypeScript SDK v0.1.22 * Added liquidity snapshot methods * Type definitions optimized *** ### 2026-01-15 **New Features** * Webhook system officially released * Token creation notifications (`sol.token.created`) * Token migration notifications (`sol.token.migrated`) * Webhook secret rotation API **SDK Updates** * TypeScript SDK v0.1.20 * Webhook endpoint management * Secret rotation methods *** ### 2026-01-04 **API v1.4.0** - New Year Update **New Features** * KYA (Know Your Address) API * Address risk assessment endpoints * Batch address queries **SDK Updates** * TypeScript SDK v0.1.19 * Complete KYA API support * Batch query optimization **Improvements** * Average API response time reduced by 30% * More detailed error messages *** ## 2025 ### 2025-12-23 **Improvements** * Improved Solana data coverage * WebSocket heartbeat mechanism optimization * Token metadata caching strategy improvements **SDK Updates** * TypeScript SDK v0.1.15 * WebSocket reconnection logic optimization * Heartbeat timeout configuration *** ### 2025-12-01 **API v1.3.0** - KYT Official Release **New Features** * 🎉 KYT (Know Your Transaction) API officially released * Transaction risk assessment * Fund source tracing * Risk alert generation * Token developer info API (`/v1/token/{chain}/dev/{devAddress}/tokens`) **SDK Updates** * TypeScript SDK v0.1.14 * Complete KYT API support * Risk assessment methods **Improvements** * DEX quote aggregation supports more protocols * Optimized routing algorithm for large trades *** ### 2025-10-15 **New Features** * Token security check API (`/v1/token/{chain}/{address}/security`) * Token mint/burn history API (`/v1/token/{chain}/{address}/mintandburn`) * Token creation info query (`/v1/token/{chain}/{address}/creation`) **SDK Updates** * TypeScript SDK v0.1.11 * Security check methods * Token history queries **Improvements** * Price data latency reduced to under 50ms * K-line data supports more time periods *** ### 2025-09-27 **SDK v0.1.0** - TypeScript SDK Official Release **Major Updates** * 🎉 TypeScript SDK v0.1.0 officially released * Complete REST API client * WebSocket real-time data subscription support **Features** * Token API full support * Wallet API full support * DEX API full support * Ranking API full support * WebSocket subscription methods *** ### 2025-09-18 **New Features** * Wallet balance update history API * Wallet PnL calculation API * Batch token queries **SDK Updates** * TypeScript SDK v0.0.12 * Wallet-related methods * Batch query support *** ### 2025-09-08 **New Features** * WebSocket real-time data push officially released * Supported subscription types: * Token candles (`dex-token-candles`) * Token stats (`dex-token-stats`) * Token holders (`token-holders`) * New tokens (`dex-new-token`) * Wallet balance (`wallet-balance`) * Wallet trades (`wallet-trade`) **SDK Updates** * TypeScript SDK v0.0.7 * WebSocket client * Auto-reconnection support *** ### 2025-09-03 **New Features** * DEX quote and routing API * Token K-line data API * Token market data API **SDK Updates** * TypeScript SDK v0.0.4 * DEX trading methods * K-line queries *** ### 2025-09-01 **API v1.0.0** - ChainStream API Official Release **Initial Features** * 🎉 ChainStream API officially released * Full Solana chain support * Core features: * Token info and price queries * Token holder analysis * DEX trading data * Wallet balance and stats * Ranking API **SDK Updates** * TypeScript SDK v0.0.2 * First usable version * Basic API support *** ### 2025-08-31 **TypeScript SDK v0.0.1** - Initial Release * TypeScript SDK first published to npm * Package: `@chainstream-io/sdk` *** ## SDK Version Overview ### Latest Versions | SDK | Version | Release Date | Package Manager | | ---------- | ------- | ------------ | ----------------------------------------------------------------------------- | | TypeScript | v0.2.6 | 2026-02-04 | [npm](https://www.npmjs.com/package/@chainstream-io/sdk) | | Python | v0.1.3 | 2026-02-04 | [PyPI](https://pypi.org/project/chainstream/) | | Go | v0.1.3 | 2026-02-04 | [pkg.go.dev](https://pkg.go.dev/github.com/chainstream-io/chainstream-sdk/go) | | Rust | v0.1.3 | 2026-02-04 | [crates.io](https://crates.io/crates/chainstream) | ### TypeScript SDK Version History | Series | Range | Release Period | Description | | ------ | -------------- | ------------------ | --------------------------------------- | | v0.2.x | 0.2.1 - 0.2.6 | 2026-02 | Multi-language SDK unified architecture | | v0.1.x | 0.1.4 - 0.1.26 | 2025-09 \~ 2026-01 | Feature stable versions | | v0.0.x | 0.0.1 - 0.0.12 | 2025-08 \~ 2025-09 | Early testing versions | *** ## Version Policy ### API Versions * **Major** (v1, v2): Breaking changes * **Minor** (v1.1, v1.2): New features, backward compatible * **Patch** (v1.1.1): Bug fixes ### SDK Versions SDKs follow Semantic Versioning (SemVer): * **Major**: Breaking changes * **Minor**: New features * **Patch**: Bug fixes ### Deprecation Policy * Deprecated endpoints retained for at least 6 months * Deprecation warnings added to response headers * Major changes announced 30 days in advance *** ## Subscribe to Updates Subscribe to version update notifications Join the community for latest updates # Go Source: https://docs.chainstream.io/en/sdks/go ChainStream Go SDK ## Installation ```bash theme={null} go get github.com/chainstream-io/chainstream-go-sdk ``` ## Quick Start ```go theme={null} import chainstream "github.com/chainstream-io/chainstream-go-sdk" client, err := chainstream.NewChainStreamClient(accessToken, &chainstream.ChainStreamClientOptions{}) if err != nil { log.Fatal(err) } defer client.Close() ``` ## REST API Example Query token information: ```go theme={null} package main import ( "context" "encoding/json" "fmt" "io" "log" chainstream "github.com/chainstream-io/chainstream-go-sdk" "github.com/chainstream-io/chainstream-go-sdk/openapi/token" ) const ACCESS_TOKEN = "YOUR_ACCESS_TOKEN" func main() { fmt.Println("Querying Token via API...") // Initialize SDK client client, err := chainstream.NewChainStreamClient(ACCESS_TOKEN, &chainstream.ChainStreamClientOptions{}) if err != nil { log.Fatalf("Failed to create client: %v", err) } defer client.Close() chain := token.Sol tokenAddress := "So11111111111111111111111111111111111111112" // SOL fmt.Printf("Querying: %s/%s\n", chain, tokenAddress) // Call API via SDK resp, err := client.Token.GetToken(context.Background(), chain, tokenAddress) if err != nil { log.Fatalf("API call failed: %v", err) } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { log.Fatalf("Failed to read response: %v", err) } var result interface{} if err := json.Unmarshal(body, &result); err != nil { log.Fatalf("Failed to parse JSON: %v", err) } fmt.Println("\nResult:") prettyJSON, _ := json.MarshalIndent(result, "", " ") fmt.Println(string(prettyJSON)) } ``` ## WebSocket Example Subscribe to real-time token candle data: ```go theme={null} package main import ( "fmt" "os" "os/signal" "syscall" chainstream "github.com/chainstream-io/chainstream-go-sdk" "github.com/chainstream-io/chainstream-go-sdk/openapi/token" "github.com/chainstream-io/chainstream-go-sdk/stream" ) const ACCESS_TOKEN = "YOUR_ACCESS_TOKEN" func main() { fmt.Println("Starting WebSocket subscription...") // Create ChainStreamClient (WebSocket will auto-connect on subscribe) client, err := chainstream.NewChainStreamClient(ACCESS_TOKEN, &chainstream.ChainStreamClientOptions{ StreamURL: "wss://realtime-dex.chainstream.io/connection/websocket", }) if err != nil { fmt.Printf("Failed to create client: %v\n", err) os.Exit(1) } defer client.Close() chain := "sol" tokenAddress := "So11111111111111111111111111111111111111112" // SOL fmt.Printf("Subscribing to Token Candles: %s/%s\n", chain, tokenAddress) fmt.Println("Listening... (Press Ctrl+C to stop)") // Subscribe to Token Candles (WebSocket auto-connects) messageCount := 0 unsubscribe := client.Stream.SubscribeTokenCandles(chain, tokenAddress, token.N1s, func(data stream.TokenCandle) { messageCount++ fmt.Printf("[%d] open=%s, close=%s, high=%s, low=%s, volume=%s\n", messageCount, data.Open, data.Close, data.High, data.Low, data.Volume, ) }, "") defer unsubscribe() // Handle interrupt signal interrupt := make(chan os.Signal, 1) signal.Notify(interrupt, syscall.SIGINT, syscall.SIGTERM) // Wait for interrupt signal <-interrupt fmt.Println("\nReceived interrupt, closing connection...") fmt.Printf("Total messages received: %d\n", messageCount) } ``` ## Concurrent Requests ```go theme={null} var wg sync.WaitGroup tokens := []string{"ADDR1", "ADDR2", "ADDR3"} results := make([]*token.Token, len(tokens)) for i, addr := range tokens { wg.Add(1) go func(i int, addr string) { defer wg.Done() resp, _ := client.Token.GetToken(ctx, token.Sol, addr) results[i] = resp }(i, addr) } wg.Wait() ``` ## Resources View source code Package documentation # Overview Source: https://docs.chainstream.io/en/sdks/overview Choose the right ChainStream SDK for you ## Official SDKs ChainStream provides official SDKs in multiple languages, wrapping common API operations for a better development experience. For Node.js and browser applications For data analysis and backend services For high-performance backend services For systems programming and performance-critical applications ## SDK Features All SDKs provide: * **REST API Client**: Call all ChainStream data APIs * **WebSocket Client**: Subscribe to real-time data streams * **Auto Authentication**: Automatic token management * **Type Safety**: Full type definitions (TypeScript, Go, Rust) ## Installation ```bash theme={null} npm install @chainstream-io/sdk ``` ```bash theme={null} pip install chainstream-sdk ``` ```bash theme={null} go get github.com/chainstream-io/chainstream-go-sdk ``` ```toml theme={null} # Add to Cargo.toml [dependencies] chainstream-sdk = "0.1" ``` ## Quick Comparison ```typescript theme={null} import { ChainStreamClient } from '@chainstream-io/sdk'; const client = new ChainStreamClient('YOUR_ACCESS_TOKEN'); // REST API call const token = await client.token.getToken('sol', 'TOKEN_ADDRESS'); // WebSocket subscription client.stream.subscribeTokenCandles({ chain: 'sol', tokenAddress: 'TOKEN_ADDRESS', resolution: Resolution['1s'], callback: (data) => console.log(data) }); ``` ```python theme={null} from chainstream import ChainStreamClient from chainstream.stream import Resolution client = ChainStreamClient(access_token='YOUR_ACCESS_TOKEN') # REST API call token = await client.token.get_metadata('sol', 'TOKEN_ADDRESS') # WebSocket subscription await client.stream.subscribe_token_candles( chain='sol', token_address='TOKEN_ADDRESS', resolution=Resolution.S1, callback=lambda data: print(data) ) ``` ```go theme={null} import chainstream "github.com/chainstream-io/chainstream-go-sdk" client, _ := chainstream.NewChainStreamClient(accessToken, &chainstream.ChainStreamClientOptions{}) // REST API call resp, _ := client.Token.GetToken(ctx, "sol", "TOKEN_ADDRESS") // WebSocket subscription client.Stream.SubscribeTokenCandles("sol", "TOKEN_ADDRESS", token.N1s, func(data stream.TokenCandle) { fmt.Println(data) }, "") ``` ```rust theme={null} use chainstream_sdk::{ChainStreamClient, stream::{Resolution, TokenCandle}}; let client = ChainStreamClient::new("YOUR_ACCESS_TOKEN", None); // WebSocket subscription client.stream.subscribe_token_candles( "sol", "TOKEN_ADDRESS", Resolution::X1s, |candle: TokenCandle| { println!("{:?}", candle); }, None, ).await?; ``` ## SDK vs Direct API | Feature | SDK | Direct API | | --------------- | ---------------- | --------------------- | | Type Safety | Yes (TS/Go/Rust) | No | | Auth Management | Automatic | Manual | | Error Handling | Wrapped | Raw HTTP errors | | WebSocket | Built-in | Manual implementation | | Code Volume | Less | More | | Flexibility | Medium | Full | ## Next Steps View TypeScript documentation View Python documentation View Go documentation View Rust documentation # Python Source: https://docs.chainstream.io/en/sdks/python ChainStream Python SDK ## Installation ```bash theme={null} pip install chainstream-sdk ``` ## Quick Start ```python theme={null} from chainstream import ChainStreamClient client = ChainStreamClient(access_token='YOUR_ACCESS_TOKEN') ``` ## REST API Example Query token metadata: ```python theme={null} import asyncio from chainstream.openapi_client import ApiClient, Configuration from chainstream.openapi_client.api.token_api import TokenApi from chainstream.openapi_client.models.chain_symbol import ChainSymbol ACCESS_TOKEN = 'YOUR_ACCESS_TOKEN' BASE_URL = 'https://api.chainstream.io' async def main(): # Configure API client config = Configuration( host=BASE_URL, access_token=ACCESS_TOKEN, ) async with ApiClient(config) as api_client: # Create token API instance token_api = TokenApi(api_client) chain = ChainSymbol.SOL token_address = 'So11111111111111111111111111111111111111112' # SOL print(f'Querying Token: {chain.value}/{token_address}') # Get token metadata result = await token_api.get_metadata( chain=chain, token_address=token_address, ) print('Token Metadata:') print(f' Name: {result.name}') print(f' Symbol: {result.symbol}') print(f' Decimals: {result.decimals}') if __name__ == '__main__': asyncio.run(main()) ``` ## WebSocket Example Subscribe to real-time token candle data: ```python theme={null} import asyncio import signal from chainstream import ChainStreamClient from chainstream.stream import Resolution, TokenCandle ACCESS_TOKEN = 'YOUR_ACCESS_TOKEN' async def main(): client = ChainStreamClient(ACCESS_TOKEN) chain = 'sol' token_address = 'So11111111111111111111111111111111111111112' # SOL resolution = Resolution.S1 print(f'Subscribing to Token Candles: {chain}/{token_address}') print('Listening... (Press Ctrl+C to stop)\n') message_count = 0 def on_candle(candle: TokenCandle) -> None: nonlocal message_count message_count += 1 print( f'[{message_count}] open={candle.open}, close={candle.close}, ' f'high={candle.high}, low={candle.low}, volume={candle.volume}' ) unsub = await client.stream.subscribe_token_candles( chain=chain, token_address=token_address, resolution=resolution, callback=on_candle, ) # Create an event to wait for Ctrl+C stop_event = asyncio.Event() def signal_handler(sig, frame): print(f'\nReceived {message_count} messages') print('Closing connection...') stop_event.set() signal.signal(signal.SIGINT, signal_handler) await stop_event.wait() # Cleanup unsub.unsubscribe() await client.close() if __name__ == '__main__': asyncio.run(main()) ``` ## More Examples ### Search Tokens ```python theme={null} results = await token_api.search_token(keyword='bonk') for t in results: print(f'{t.symbol}: {t.address}') ``` ### Get Wallet PnL ```python theme={null} from chainstream.openapi_client.api.wallet_api import WalletApi async with ApiClient(config) as api_client: wallet_api = WalletApi(api_client) pnl = await wallet_api.get_pnl( chain=ChainSymbol.SOL, wallet_address='WALLET_ADDRESS', ) print(f'Total PnL: {pnl.total_pnl_usd}') ``` ### Get Trade List ```python theme={null} from chainstream.openapi_client.api.trade_api import TradeApi async with ApiClient(config) as api_client: trade_api = TradeApi(api_client) trades = await trade_api.get_trades( chain=ChainSymbol.SOL, token_address='TOKEN_ADDRESS', limit=20, ) for trade in trades: print(f'{trade.timestamp}: {trade.side} {trade.amount}') ``` *** ## Pandas Integration ```python theme={null} import pandas as pd candles = await client.token.get_candles('sol', 'TOKEN_ADDRESS', resolution='1h', limit=100) df = pd.DataFrame(candles) df['timestamp'] = pd.to_datetime(df['timestamp'], unit='s') ``` *** ## Error Handling ```python theme={null} from chainstream.openapi_client.exceptions import ApiException try: result = await token_api.get_token(chain=ChainSymbol.SOL, token_address='INVALID') except ApiException as e: print(f'API error {e.status}: {e.reason}') if e.status == 429: import asyncio await asyncio.sleep(2) ``` *** ## Resources View source code Package registry # Rust Source: https://docs.chainstream.io/en/sdks/rust ChainStream Rust SDK ## Installation Add to your `Cargo.toml`: ```toml theme={null} [dependencies] chainstream-sdk = "0.1" tokio = { version = "1", features = ["full"] } ``` ## Quick Start ```rust theme={null} use chainstream_sdk::ChainStreamClient; #[tokio::main] async fn main() -> Result<(), Box> { let client = ChainStreamClient::new("YOUR_ACCESS_TOKEN", None); // Use the client... Ok(()) } ``` ## REST API Example Query token metadata: ```rust theme={null} use chainstream_sdk::{openapi, CHAINSTREAM_BASE_URL}; use reqwest_middleware::{ClientBuilder, ClientWithMiddleware}; // Middleware to add Bearer token to requests struct BearerAuthMiddleware { token: String, } #[async_trait::async_trait] impl reqwest_middleware::Middleware for BearerAuthMiddleware { async fn handle( &self, mut req: reqwest::Request, extensions: &mut http::Extensions, next: reqwest_middleware::Next<'_>, ) -> reqwest_middleware::Result { req.headers_mut().insert( reqwest::header::AUTHORIZATION, format!("Bearer {}", self.token).parse().unwrap(), ); next.run(req, extensions).await } } #[tokio::main] async fn main() -> Result<(), Box> { let access_token = "YOUR_ACCESS_TOKEN"; // Create HTTP client with Bearer token middleware let http_client: ClientWithMiddleware = ClientBuilder::new(reqwest::Client::new()) .with(BearerAuthMiddleware { token: access_token.to_string(), }) .build(); // Create OpenAPI client let client = openapi::Client::new_with_client(CHAINSTREAM_BASE_URL, http_client); // Call API let result = client.get_supported_blockchains().send().await?; let blockchains = result.into_inner(); println!("Supported blockchains: {:#?}", blockchains); Ok(()) } ``` ## WebSocket Example Subscribe to real-time token candle data: ```rust theme={null} use chainstream_sdk::{ stream::{Resolution, TokenCandle}, ChainStreamClient, }; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; use tokio::signal; #[tokio::main] async fn main() -> Result<(), Box> { let access_token = "YOUR_ACCESS_TOKEN"; let client = ChainStreamClient::new(&access_token, None); let chain = "sol"; let token_address = "So11111111111111111111111111111111111111112"; // SOL let resolution = Resolution::X1s; println!("Subscribing to token candles: {}/{}", chain, token_address); println!("Press Ctrl+C to exit...\n"); let message_count = Arc::new(AtomicUsize::new(0)); let message_count_clone = message_count.clone(); // Subscribe to token candles let _unsub = client .stream .subscribe_token_candles( chain, token_address, resolution, move |candle: TokenCandle| { let count = message_count_clone.fetch_add(1, Ordering::SeqCst) + 1; println!( "[{}] open={}, close={}, high={}, low={}, volume={}", count, candle.open, candle.close, candle.high, candle.low, candle.volume ); }, None, ) .await?; // Wait for Ctrl+C signal::ctrl_c().await?; println!("\nReceived {} messages", message_count.load(Ordering::SeqCst)); client.close().await; Ok(()) } ``` ## Resources View source code Package registry # TypeScript Source: https://docs.chainstream.io/en/sdks/typescript ChainStream TypeScript/JavaScript SDK ## Installation ```bash npm theme={null} npm install @chainstream-io/sdk ``` ```bash yarn theme={null} yarn add @chainstream-io/sdk ``` ```bash pnpm theme={null} pnpm add @chainstream-io/sdk ``` ## Quick Start ```typescript theme={null} import { ChainStreamClient } from '@chainstream-io/sdk'; const client = new ChainStreamClient('YOUR_ACCESS_TOKEN'); ``` ## REST API Example Query token information: ```typescript theme={null} import { ChainStreamClient } from '@chainstream-io/sdk'; const ACCESS_TOKEN = 'YOUR_ACCESS_TOKEN'; async function main() { // Initialize SDK client const client = new ChainStreamClient(ACCESS_TOKEN); const chain = 'sol'; const tokenAddress = 'So11111111111111111111111111111111111111112'; // SOL console.log(`Querying Token: ${chain}/${tokenAddress}`); try { // Call API via SDK const result = await client.token.getToken(chain, tokenAddress); console.log('Result:'); console.log(JSON.stringify(result, null, 2)); } catch (error) { console.error('API call failed:', error); } } main(); ``` ## WebSocket Example Subscribe to real-time token candle data: ```typescript theme={null} import { ChainStreamClient, Resolution } from '@chainstream-io/sdk'; const ACCESS_TOKEN = 'YOUR_ACCESS_TOKEN'; async function main() { const client = new ChainStreamClient(ACCESS_TOKEN, { autoConnectWebSocket: true, }); const chain = 'sol'; const tokenAddress = 'So11111111111111111111111111111111111111112'; // SOL console.log(`Subscribing to Token Candles: ${chain}/${tokenAddress}`); console.log('Listening... (Press Ctrl+C to stop)\n'); // Subscribe to WebSocket via SDK client.stream.subscribeTokenCandles({ chain, tokenAddress, resolution: Resolution['1s'], callback: data => { console.log(new Date().toISOString(), JSON.stringify(data)); }, }); // Keep the process alive process.on('SIGINT', () => { console.log('\nClosing connection...'); process.exit(0); }); // Keep running await new Promise(() => {}); } main().catch(error => { console.error('Test failed:', error.message); process.exit(1); }); ``` ## More Examples ### Search Tokens ```typescript theme={null} const results = await client.token.searchToken('bonk'); console.log(results); ``` See [Token - Search](/en/api-reference/endpoint/data/token/v2/token-search-get) for full parameters. ### Get Trade List ```typescript theme={null} const trades = await client.trade.getTrades('sol', { tokenAddress: 'TOKEN_ADDRESS', limit: 20, }); console.log(trades); ``` See [Trade - List](/en/api-reference/endpoint/data/trade/v2/trade-chain-get) for full parameters. ### Get Wallet PnL ```typescript theme={null} const pnl = await client.wallet.getPnl('sol', 'WALLET_ADDRESS'); console.log(`Total PnL: ${pnl.totalPnlUsd}`); ``` See [Wallet - PnL](/en/api-reference/endpoint/data/wallet/v2/wallet-chain-walletaddress-pnl-get) for full parameters. ### Get Token Candles (K-line) ```typescript theme={null} const candles = await client.token.getCandles('sol', 'TOKEN_ADDRESS', { resolution: '1h', limit: 24, }); for (const c of candles) { console.log(`${c.time}: O=${c.open} H=${c.high} L=${c.low} C=${c.close}`); } ``` See [Token - Candles](/en/api-reference/endpoint/data/token/v2/token-chain-tokenaddress-candles-get) for full parameters. ### Get New Tokens (Ranking) ```typescript theme={null} const newTokens = await client.ranking.getNewTokens('sol'); for (const token of newTokens) { console.log(`${token.symbol}: ${token.address}`); } ``` See [Ranking - New Tokens](/en/api-reference/endpoint/data/ranking/v2/ranking-chain-newtokens-get) for full parameters. *** ## Error Handling ```typescript theme={null} import { ChainStreamClient, ChainStreamError } from '@chainstream-io/sdk'; try { const token = await client.token.getToken('sol', 'INVALID_ADDRESS'); } catch (error) { if (error instanceof ChainStreamError) { console.error(`Error code: ${error.code}`); console.error(`Error message: ${error.message}`); } } ``` ### Retry with Exponential Backoff For rate-limited requests (HTTP 429), implement retry logic: ```typescript theme={null} async function withRetry(fn: () => Promise, maxRetries = 3): Promise { for (let attempt = 0; attempt <= maxRetries; attempt++) { try { return await fn(); } catch (error) { if (error instanceof ChainStreamError && error.code === 429 && attempt < maxRetries) { const delay = Math.pow(2, attempt) * 1000; await new Promise(resolve => setTimeout(resolve, delay)); continue; } throw error; } } throw new Error('Max retries exceeded'); } const token = await withRetry(() => client.token.getToken('sol', 'TOKEN_ADDRESS')); ``` *** ## Resources View source code Package registry