diff --git a/public/images/tutorial-icons/go_logo_black.png b/public/images/tutorial-icons/go_logo_black.png
new file mode 100644
index 00000000000..f68a065d332
Binary files /dev/null and b/public/images/tutorial-icons/go_logo_black.png differ
diff --git a/public/images/tutorial-icons/rust_logo_blk.svg b/public/images/tutorial-icons/rust_logo_blk.svg
new file mode 100644
index 00000000000..1a6c762d4ec
--- /dev/null
+++ b/public/images/tutorial-icons/rust_logo_blk.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/config/sidebar.ts b/src/config/sidebar.ts
index 6b0a13ed1ac..6fcfc33c5ea 100644
--- a/src/config/sidebar.ts
+++ b/src/config/sidebar.ts
@@ -234,11 +234,6 @@ export const SIDEBAR: Partial> = {
title: "Overview",
url: "data-streams",
},
- {
- title: "Getting Started",
- url: "data-streams/getting-started",
- highlightAsCurrent: ["data-streams/getting-started-hardhat"],
- },
{
title: "Developer Responsibilities",
url: "data-streams/developer-responsibilities",
@@ -254,59 +249,86 @@ export const SIDEBAR: Partial> = {
],
},
{
- section: "Stream Addresses",
+ section: "Streams & Report Schemas",
contents: [
{
- title: "Crypto streams",
+ title: "Cryptocurrency Streams",
url: "data-streams/crypto-streams",
+ children: [
+ {
+ title: "Report Schema v3",
+ url: "data-streams/reference/report-schema",
+ },
+ ],
},
{
- title: "RWA streams",
+ title: "Real World Asset (RWA) Streams",
url: "data-streams/rwa-streams",
+ children: [
+ {
+ title: "Report Schema v4",
+ url: "data-streams/reference/report-schema-v4",
+ },
+ ],
},
{
- title: "Market hours",
+ title: "Market Hours",
url: "data-streams/market-hours",
},
],
},
{
- section: "Guides",
+ section: "Streams Trade",
contents: [
{
- title: "Streams Trade",
- url: "data-streams/tutorials/streams-trade/",
- children: [
- {
- title: "Handle StreamsLookup errors",
- url: "data-streams/tutorials/streams-trade/streams-trade-lookup-error-handler",
- },
+ title: "Overview",
+ url: "data-streams/streams-trade",
+ },
+ {
+ title: "Getting Started",
+ url: "data-streams/getting-started",
+ highlightAsCurrent: ["data-streams/getting-started-hardhat"],
+ },
+ {
+ title: "Handle StreamsLookup errors",
+ url: "data-streams/tutorials/streams-trade/streams-trade-lookup-error-handler",
+ },
+ ],
+ },
+ {
+ section: "Streams Direct",
+ contents: [
+ {
+ title: "Overview",
+ url: "data-streams/streams-direct",
+ },
+ {
+ title: "Fetch and decode reports",
+ url: "data-streams/tutorials/streams-direct/streams-direct-api-go",
+ highlightAsCurrent: [
+ "data-streams/tutorials/streams-direct/streams-direct-api-rust",
+ "data-streams/tutorials/streams-direct/streams-direct-api-rwa-go",
+ "data-streams/tutorials/streams-direct/streams-direct-api-rwa-rust",
],
},
{
- title: "Streams Direct",
- url: "data-streams/tutorials/streams-direct/",
- children: [
- {
- title: "Fetch and decode reports",
- url: "data-streams/tutorials/streams-direct/streams-direct-api",
- highlightAsCurrent: ["data-streams/tutorials/streams-direct/streams-direct-api-rwa"],
- },
- {
- title: "Stream and decode reports (WebSocket)",
- url: "data-streams/tutorials/streams-direct/streams-direct-ws",
- highlightAsCurrent: ["data-streams/tutorials/streams-direct/streams-direct-ws-rwa"],
- },
- {
- title: "Verify report data",
- url: "data-streams/tutorials/streams-direct/evm-onchain-report-verification",
- highlightAsCurrent: [
- "data-streams/tutorials/streams-direct/solana-onchain-report-verification",
- "data-streams/tutorials/streams-direct/solana-offchain-report-verification",
- ],
- },
+ title: "Stream and decode reports (WebSocket)",
+ url: "data-streams/tutorials/streams-direct/streams-direct-ws-go",
+ highlightAsCurrent: [
+ "data-streams/tutorials/streams-direct/streams-direct-ws-rust",
+ "data-streams/tutorials/streams-direct/streams-direct-ws-rwa-go",
+ "data-streams/tutorials/streams-direct/streams-direct-ws-rwa-rust",
],
},
+ {
+ title: "Verify report data (EVM)",
+ url: "data-streams/tutorials/streams-direct/evm-onchain-report-verification",
+ },
+ {
+ title: "Verify report data (Solana)",
+ url: "data-streams/tutorials/streams-direct/solana-onchain-report-verification",
+ highlightAsCurrent: ["data-streams/tutorials/streams-direct/solana-offchain-report-verification"],
+ },
],
},
{
@@ -326,16 +348,11 @@ export const SIDEBAR: Partial> = {
section: "Reference",
contents: [
{
- title: "Report Schemas",
- url: "data-streams/reference/report-schema",
- highlightAsCurrent: ["data-streams/reference/report-schema-v4"],
- },
- {
- title: "Streams Trade Interface",
+ title: "Streams Trade",
url: "data-streams/reference/streams-trade-interface",
},
{
- title: "Streams Direct Interface",
+ title: "Streams Direct",
url: "data-streams/reference/streams-direct",
children: [
{
@@ -347,11 +364,12 @@ export const SIDEBAR: Partial> = {
url: "data-streams/reference/streams-direct/streams-direct-interface-ws",
},
{
- title: "SDK Reference",
+ title: "SDK References",
url: "data-streams/reference/streams-direct/streams-direct-go-sdk",
+ highlightAsCurrent: ["data-streams/reference/streams-direct/streams-direct-rust-sdk"],
},
{
- title: "Onchain report data verification (EVM chains)",
+ title: "Onchain report verification (EVM chains)",
url: "data-streams/reference/streams-direct/streams-direct-onchain-verification",
},
],
diff --git a/src/content/data-streams/index.mdx b/src/content/data-streams/index.mdx
index 8ccf020e31d..17143a5474e 100644
--- a/src/content/data-streams/index.mdx
+++ b/src/content/data-streams/index.mdx
@@ -4,8 +4,8 @@ title: "Chainlink Data Streams"
isIndex: true
whatsnext:
{
- "Learn the basics about how to retrieve Data Streams reports using the Streams Trade implementation": "/data-streams/getting-started",
- "Learn how to fetch and decode Data Streams reports using the Streams Direct API": "/data-streams/tutorials/streams-direct/streams-direct-api",
+ "Learn how to retrieve Data Streams reports with the Streams Trade implementation": "/data-streams/getting-started",
+ "Learn how to fetch and decode Data Streams reports with the Streams Direct API": "/data-streams/tutorials/streams-direct/streams-direct-api",
"Find the list of available Stream IDs": "/data-streams/crypto-streams",
"Find the schema of data to expect from Data Streams reports": "/data-streams/reference/report-schema",
}
@@ -16,63 +16,51 @@ import DataStreams from "@features/data-streams/common/DataStreams.astro"
-Chainlink Data Streams provides low-latency delivery of market data offchain that you can verify onchain. With Chainlink Data Streams, decentralized applications (dApps) now have on-demand access to high-frequency market data backed by decentralized, fault-tolerant, and transparent infrastructure.
+Chainlink Data Streams delivers low-latency market data offchain, which you can verify onchain. This approach provides decentralized applications (dApps) with on-demand access to high-frequency market data backed by decentralized, fault-tolerant, and transparent infrastructure.
-Traditional push-based oracles provide regular updates onchain when certain price thresholds or update time periods have been met. Chainlink Data Streams is built using a new pull-based oracle design that maintains trust-minimization using onchain verification.
+Traditional push-based oracles update onchain data at set intervals or when certain price thresholds are met. In contrast, Chainlink Data Streams uses a pull-based design that preserves trust-minimization with onchain verification.
+
+## Sub-Second Data and Commit-and-Reveal
+
+Chainlink Data Streams supports sub-second data resolution for latency-sensitive use cases by retrieving data only when needed. You can combine the data with any transaction in near real time. A “commit-and-reveal” approach mitigates frontrunning by making trade data and stream data visible atomically on-chain.
## Comparison to push-based oracles
-Chainlink's push-based oracles provide regular updates onchain. Chainlink Data Streams operates as a pull-based oracle where you can retrieve the data in a report and use it onchain any time. Verifying the report onchain confirms that the data was agreed upon and signed by the DON. While many applications benefit from push-based oracles and require data only after it has been verified onchain, some applications require access to data that is updated at a higher frequency and delivered with lower latency. Pull-based oracles deliver these benefits while still cryptographically signing the data to ensure its veracity.
+Chainlink's push-based oracles regularly publish price data onchain. By contrast, Chainlink Data Streams relies on a pull-based design, letting you retrieve a report and verify it onchain whenever you need it. Verification confirms that the decentralized oracle network (DON) agreed on and signed the data. Some applications only need onchain data at fixed intervals, which suits push-based oracles. However, others require higher-frequency updates and lower latency. Pull-based oracles meet these needs and still provide cryptographic guarantees about data accuracy.
-Additionally, pull-based oracles deliver data onchain more efficiently by retrieving and verifying the data only when the application needs it. For example, a decentralized exchange might retrieve a Data Streams report and verify the data onchain when a user executes a trade. A push-based oracle repeatedly delivers data onchain even when that data is not immediately required by users.
+Pull-based oracles also operate more efficiently by retrieving data only when necessary. For example, a decentralized exchange might fetch a Data Streams report and verify it onchain only when a user executes a trade, rather than continuously pushing updates that might not be immediately used.
## Comprehensive market insights
-Chainlink Data Streams provides price points such as mid prices and [Liquidity-Weighted Bid and Ask](/data-streams/concepts/liquidity-weighted-prices) (LWBA) prices for Crypto Streams. LWBA prices adjust dynamically based on the current state of order books, which offers greater insights into market liquidity and depth. Liquidity-weighted prices enhance trading accuracy, improve risk management, and increase transactional efficiency as they dynamically reflect the true market conditions based on volume and liquidity.
+Chainlink Data Streams offers price points such as mid prices and [Liquidity-Weighted Bid and Ask](/data-streams/concepts/liquidity-weighted-prices) (LWBA) for Crypto Streams. LWBA prices reflect current order book conditions, providing deeper insight into market liquidity and depth. With additional parameters, such as volatility and liquidity metrics, Data Streams helps protocols enhance trading accuracy, improve onchain risk management, and dynamically adjust margins or settlement conditions in response to real-time market shifts.
## High availability and resilient infrastructure
-The Data Streams API services use an [active-active multi-site deployment](/data-streams/architecture#active-active-multi-site-deployment) setup as a highly available and resilient architecture across multiple distributed and fully-isolated origins. This setup ensures that the services are operational even if one origin fails, which provides robust fault tolerance and high availability.
+Data Streams API services use an [active-active multi-site deployment](/data-streams/architecture#active-active-multi-site-deployment) model across multiple distributed and isolated origins. This architecture ensures continuous operations even if one origin fails, delivering robust fault tolerance and high availability.
## Use cases
-Pull-based oracles allow decentralized applications to access data that is updated at a high frequency and delivered with low latency, which enables several new use cases:
+Access to low-latency, high-frequency data enables a variety of onchain applications:
-- **Perpetual Futures:** Low-latency data and frontrunning prevention enable onchain perpetual futures protocols that can compete on performance with centralized exchanges while still using more transparent and decentralized infrastructure.
-- **Options:** Pull-based oracles allow timely and precise settlement of options contracts. Additionally, Data Streams provides more detailed market liquidity data that can support dynamic onchain risk management logic.
-- **Prediction Markets:** Higher frequency data updates allow for applications where users can act quickly in response to real-time events and be confident in the accuracy of the data used in the settlement.
+- **Perpetual Futures:** Sub-second data and frontrunning mitigation allow onchain perpetual futures protocols to compete with centralized exchanges on performance while retaining transparency and decentralization.
+- **Options:** Pull-based oracles provide timely settlement of options contracts with the added benefit of market liquidity data to support dynamic onchain risk management.
+- **Prediction Markets:** High-frequency updates let participants act on real-time data, ensuring quick reactions to events and accurate settlement.
## Data Streams implementations
-### Streams Trade: Using Data Streams with Chainlink Automation
-
-When combined with [Chainlink Automation](/chainlink-automation/introduction), Chainlink Data Streams allows decentralized applications to automate trade execution, mitigate frontrunning, and limit bias or adverse incentives in executing non-user-triggered orders.
-
-
+### Streams Trade
-Read more about the [Streams Trade Architecture](/data-streams/architecture#streams-trade-architecture) and an [example trading flow](/data-streams/architecture#example-trading-flow-using-streams-trade), or learn how to [get started](/data-streams/getting-started) with Streams Trade.
+Streams Trade combines Chainlink Data Streams with Chainlink Automation to deliver automated trade execution with frontrunning mitigation. This approach suits dApps that require automated, trust-minimized trade execution and high-frequency market data. Chainlink Automation ensures near-instant onchain access to data while keeping the execution of user transactions fair and reliable.
-**Note**: Before implementing Streams Trade, ensure that Chainlink Automation is available on your desired network by checking the [Automation Supported Networks page](/chainlink-automation/overview/supported-networks).
+[Learn more about Streams Trade](/data-streams/streams-trade)
-### Streams Direct: Using Data Streams with your own bot
+### Streams Direct
-Streams Direct offers a direct approach to integrating low-latency and high-frequency data into your applications. You can use the [Data Streams SDK](/data-streams/reference/streams-direct/streams-direct-go-sdk) to fetch reports (REST API) or to subscribe to report updates (WebSocket connection) from the Data Streams Aggregation Network, and an onchain smart contract to [verify reports](/data-streams/reference/streams-direct/streams-direct-onchain-verification).
-
-For instance, you can use Chainlink Data Streams with the Streams Direct implementation to display indicative pricing offchain on your front end or with your bot to settle trades onchain.
-
-#### On-demand offchain workflows
-
-
+Streams Direct provides direct access to Data Streams through SDKs and APIs. This solution suits applications that need programmatic data retrieval and verification, whether for offchain display or onchain settlement. It delivers high-frequency, low-latency data for any custom use case.
-Explore an example of offchain price updates through Streams Direct in the [Architecture](/data-streams/architecture#streams-direct-architecture) guide, or follow this [guide](/data-streams/tutorials/streams-direct/streams-direct-api) to learn how to fetch and decode Data Streams reports using the Data Streams SDK.
+[Learn more about Streams Direct](/data-streams/streams-direct)
diff --git a/src/content/data-streams/reference/report-schema-v4.mdx b/src/content/data-streams/reference/report-schema-v4.mdx
index 2488ad8ff98..6865d89133c 100644
--- a/src/content/data-streams/reference/report-schema-v4.mdx
+++ b/src/content/data-streams/reference/report-schema-v4.mdx
@@ -12,21 +12,23 @@ import { PageTabs } from "@components"
-Real World Asset (RWA) streams adhere to the report schema outlined below:
+Real World Asset (RWA) streams adhere to the report schema outlined below.
-| Value | Type | Description |
+## Schema Fields
+
+| Field | Type | Description |
| ----------------------- | --------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `feedID` | `bytes32` | The unique identifier for the stream |
| `validFromTimestamp` | `uint32` | The earliest timestamp during which the price is valid |
diff --git a/src/content/data-streams/reference/report-schema.mdx b/src/content/data-streams/reference/report-schema.mdx
index 351d0abf017..6e33712fab1 100644
--- a/src/content/data-streams/reference/report-schema.mdx
+++ b/src/content/data-streams/reference/report-schema.mdx
@@ -12,30 +12,32 @@ import { PageTabs } from "@components"
-Crypto streams adhere to the report schema outlined below:
+Cryptocurrency streams adhere to the report schema outlined below.
-| Value | Type | Description |
-| ----------------------- | --------- | ------------------------------------------------------------------------------------- |
-| `feedID` | `bytes32` | The unique identifier for the stream |
-| `validFromTimestamp` | `uint32` | The earliest timestamp during which the price is valid |
-| `observationsTimestamp` | `uint32` | The latest timestamp during which the price is valid |
-| `nativeFee` | `uint192` | The cost to verify this report onchain when paying with the blockchain's native token |
-| `linkFee` | `uint192` | The cost to verify this report onchain when paying with LINK |
-| `expiresAt` | `uint32` | The expiration date of this report |
-| `price` | `int192` | The DON's consensus median price for this report carried to 18 decimal places |
-| `bid` | `int192` | The simulated price impact of a buy order up to the X% depth of liquidity usage |
-| `ask` | `int192` | Simulated price impact of a sell order up to the X% depth of liquidity usage |
+## Schema Fields
-**Note**: Future Crypto streams may use different report schemas.
+| Field | Type | Description |
+| ----------------------- | --------- | ------------------------------------------------- |
+| `feedID` | `bytes32` | Unique identifier for the data stream |
+| `validFromTimestamp` | `uint32` | Start timestamp of price validity period |
+| `observationsTimestamp` | `uint32` | End timestamp of price validity period |
+| `nativeFee` | `uint192` | Verification cost in native blockchain tokens |
+| `linkFee` | `uint192` | Verification cost in LINK tokens |
+| `expiresAt` | `uint32` | Timestamp when this report expires |
+| `price` | `int192` | DON consensus median price (18 decimal places) |
+| `bid` | `int192` | Simulated buy impact price at X% liquidity depth |
+| `ask` | `int192` | Simulated sell impact price at X% liquidity depth |
+
+**Note**: Future Cryptocurrency streams may use different report schemas.
diff --git a/src/content/data-streams/reference/streams-direct/index.mdx b/src/content/data-streams/reference/streams-direct/index.mdx
index f54341bfdac..ec20cf9f1d0 100644
--- a/src/content/data-streams/reference/streams-direct/index.mdx
+++ b/src/content/data-streams/reference/streams-direct/index.mdx
@@ -9,6 +9,18 @@ import DataStreams from "@features/data-streams/common/DataStreams.astro"
-- [REST API](/data-streams/reference/streams-direct/streams-direct-interface-api)
-- [WebSocket](/data-streams/reference/streams-direct/streams-direct-interface-ws)
-- [Onchain report data verification](/data-streams/reference/streams-direct/streams-direct-onchain-verification)
+### API Interfaces
+
+- [REST API](/data-streams/reference/streams-direct/streams-direct-interface-api) - HTTP-based interface for simple integrations
+- [WebSocket](/data-streams/reference/streams-direct/streams-direct-interface-ws) - Real-time data streaming via WebSocket connection
+
+### SDK Integration
+
+- [Go SDK](/data-streams/reference/streams-direct/streams-direct-go-sdk) - Native Go language integration
+- [Rust SDK](/data-streams/reference/streams-direct/streams-direct-rust-sdk) - Native Rust language integration
+
+### Verification
+
+- [Onchain report data verification](/data-streams/reference/streams-direct/streams-direct-onchain-verification) - Verify the authenticity of received data on EVM chains
+
+**Note:** You can also verify Data Streams reports on Solana using the [onchain](/data-streams/tutorials/streams-direct/solana-onchain-report-verification) or [offchain](/data-streams/tutorials/streams-direct/solana-offchain-report-verification) integration methods.
diff --git a/src/content/data-streams/reference/streams-direct/streams-direct-go-sdk.mdx b/src/content/data-streams/reference/streams-direct/streams-direct-go-sdk.mdx
index 66e1e84d65a..3d49aaba6ff 100644
--- a/src/content/data-streams/reference/streams-direct/streams-direct-go-sdk.mdx
+++ b/src/content/data-streams/reference/streams-direct/streams-direct-go-sdk.mdx
@@ -10,9 +10,27 @@ whatsnext:
---
import DataStreams from "@features/data-streams/common/DataStreams.astro"
+import { PageTabs } from "@components"
+
+
This documentation provides a detailed reference for the Data Streams SDK for Go. It implements a client library that offers a domain-oriented abstraction for interacting with the Data Streams API and enables both point-in-time data retrieval and real-time data streaming with built-in fault tolerance capabilities.
## streams
diff --git a/src/content/data-streams/reference/streams-direct/streams-direct-onchain-verification.mdx b/src/content/data-streams/reference/streams-direct/streams-direct-onchain-verification.mdx
index 8a1f61a750d..a52f344c11e 100644
--- a/src/content/data-streams/reference/streams-direct/streams-direct-onchain-verification.mdx
+++ b/src/content/data-streams/reference/streams-direct/streams-direct-onchain-verification.mdx
@@ -1,7 +1,11 @@
---
section: dataStreams
date: Last Modified
-title: "Onchain Data Verification"
+title: "Onchain report verification (EVM chains)"
+whatsnext:
+ {
+ "Learn how to verify report data onchain (EVM chains)": "/data-streams/tutorials/streams-direct/evm-onchain-report-verification",
+ }
---
import { CodeSample, Aside } from "@components"
diff --git a/src/content/data-streams/reference/streams-direct/streams-direct-rust-sdk.mdx b/src/content/data-streams/reference/streams-direct/streams-direct-rust-sdk.mdx
new file mode 100644
index 00000000000..e1b69841949
--- /dev/null
+++ b/src/content/data-streams/reference/streams-direct/streams-direct-rust-sdk.mdx
@@ -0,0 +1,310 @@
+---
+section: dataStreams
+date: Last Modified
+title: "Streams Direct SDK (Rust)"
+whatsnext:
+ {
+ "Learn how to fetch and decode Data Streams reports using the Data Streams SDK": "/data-streams/tutorials/streams-direct/streams-direct-api-rust",
+ "Learn how to stream and decode reports via a WebSocket connection using the Data Streams SDK": "/data-streams/tutorials/streams-direct/streams-direct-ws-rust",
+ }
+---
+
+import DataStreams from "@features/data-streams/common/DataStreams.astro"
+import { PageTabs } from "@components"
+
+
+
+
+
+The [Data Streams SDK for Rust](https://github.com/smartcontractkit/data-streams-sdk/tree/main/rust) provides a client library for interacting with Chainlink Data Streams. It offers both point-in-time data retrieval and real-time data streaming capabilities with built-in fault tolerance.
+
+## Requirements
+
+- Rust 1.70 or later
+- Valid Data Streams API credentials
+
+## Features
+
+- **REST API Client**: Fetch point-in-time data from Data Streams
+- **WebSocket Client**: Stream real-time data with automatic reconnection
+- **Report Decoding**: Built-in support for decoding and validating multiple report formats (V3, V4)
+- **High Availability**: WebSocket connection management with failover support
+- **Tracing Support**: Optional logging via the [`tracing`](https://crates.io/crates/tracing) crate
+- **Async/Await**: Built on Tokio for efficient async operations
+
+## Installation
+
+Add the SDK to your project by including it in your `Cargo.toml`:
+
+```toml
+[dependencies]
+data-streams-sdk = { git = "https://github.com/smartcontractkit/data-streams-sdk.git", subdir = "rust/crates/sdk" }
+data-streams-report = { git = "https://github.com/smartcontractkit/data-streams-sdk.git", subdir = "rust/crates/report" }
+```
+
+### Feature Flags
+
+The SDK provides several feature flags to customize its functionality:
+
+- `"rest"`: Enables the REST API client (enabled by default)
+- `"websocket"`: Enables the WebSocket client for real-time streaming (enabled by default)
+- `"tracing"`: Enables logging with the `tracing` crate (optional)
+- `"full"`: Enables all features (default)
+
+## Report Types
+
+The Rust SDK supports multiple report formats, including **V3 (Crypto)** and **V4 (RWA)**. For the complete list of fields and their detailed descriptions, refer to the dedicated schema pages:
+
+- [V3 (Cryptocurrency) Report Schema](/data-streams/reference/report-schema)
+- [V4 (RWA) Report Schema](/data-streams/reference/report-schema-v4)
+
+Below are basic code snippets for decoding these reports with the SDK:
+
+### V3 Reports (Crypto Streams)
+
+```rust
+use data_streams_report::report::v3::ReportDataV3;
+
+// After you get 'report_blob' (for example, from 'decode_full_report' or a contract call):
+let report_data = ReportDataV3::decode(&report_blob)?;
+
+// Access whichever fields you need:
+println!("Benchmark Price: {}", report_data.benchmark_price);
+println!("Bid: {}", report_data.bid);
+println!("Ask: {}", report_data.ask);
+
+// ... etc.
+```
+
+For more details on every field in V3 (Crypto) reports, see the [V3 report schema page](/data-streams/reference/report-schema).
+
+### V4 Reports (RWA Streams)
+
+```rust
+use data_streams_report::report::v4::ReportDataV4;
+
+let report_data = ReportDataV4::decode(&report_blob)?;
+
+// Example usage:
+println!("Price: {}", report_data.price);
+println!("Market Status: {}", report_data.market_status);
+// ... etc.
+```
+
+For more details on every field in V4 (RWA) reports, see the [V4 report schema page](/data-streams/reference/report-schema-v4).
+
+## Authentication
+
+The SDK uses HMAC authentication for all API requests. Configure your credentials:
+
+```rust
+use data_streams_sdk::config::Config;
+use std::env;
+
+let api_key = env::var("API_KEY").expect("API_KEY must be set");
+let user_secret = env::var("USER_SECRET").expect("USER_SECRET must be set");
+
+let config = Config::new(
+ api_key,
+ user_secret,
+ "https://api.testnet-dataengine.chain.link".to_owned(),
+ "wss://ws.testnet-dataengine.chain.link".to_owned(),
+)
+.build()?;
+```
+
+Security best practices:
+
+- Store credentials in environment variables
+- Avoid hardcoding credentials in source code
+- Use separate credentials for development and production
+- Rotate credentials periodically
+
+## WebSocket Features
+
+### High Availability Mode
+
+```rust
+use data_streams_sdk::config::{Config, WebSocketHighAvailability};
+
+let ws_urls = "wss://ws1.dataengine.chain.link,wss://ws2.dataengine.chain.link";
+let config = Config::new(api_key, api_secret, rest_url, ws_urls)
+ // Enable WebSocket HA mode
+ .with_ws_ha(WebSocketHighAvailability::Enabled)
+ // Increase the max reconnection attempts (optional, default is 5)
+ .with_ws_max_reconnect(10)
+ .build()?;
+```
+
+- Multiple WebSocket endpoints
+- Automatic failover on connection loss
+- Parallel connections to reduce gaps in data
+
+### Connection Management
+
+The SDK allows you to:
+
+- Set `ws_max_reconnect`: The maximum number of reconnection attempts (default: 5)
+- Enable HA for multiple WebSocket endpoints
+- Optional `insecure_skip_verify` for TLS
+
+Example:
+
+```rust
+use data_streams_sdk::config::{Config, InsecureSkipVerify, WebSocketHighAvailability};
+
+let ws_urls = "wss://ws.testnet-dataengine.chain.link";
+
+let config = Config::new(api_key, api_secret, rest_url, ws_urls)
+ .with_ws_ha(WebSocketHighAvailability::Enabled)
+ .with_ws_max_reconnect(5)
+ .with_insecure_skip_verify(InsecureSkipVerify::Enabled)
+ .build()?;
+
+// Create and initialize the stream
+let mut stream = Stream::new(&config, feed_ids).await?;
+stream.listen().await?;
+```
+
+## Error Handling
+
+The SDK defines distinct error types:
+
+- `ClientError` for REST-based issues (e.g., HTTP request failures)
+- `StreamError` for WebSocket streaming issues
+- `HmacError` for authentication/HMAC generation problems
+
+Example:
+
+```rust
+use data_streams_sdk::client::Client;
+use data_streams_sdk::client::ClientError;
+
+match client.get_latest_report(feed_id).await {
+ Ok(report_response) => {
+ println!("Report: {:?}", report_response.report);
+ }
+ Err(ClientError::ApiError(e)) => {
+ eprintln!("Server returned an error: {}", e);
+ }
+ Err(e) => {
+ eprintln!("Some other request error: {}", e);
+ }
+}
+```
+
+## Examples
+
+### Step-by-Step Guides
+
+- [Fetch and decode reports using the REST API](/data-streams/tutorials/streams-direct/streams-direct-api-rust)
+- [Stream and decode reports via WebSocket](/data-streams/tutorials/streams-direct/streams-direct-ws-rust)
+
+### More Examples
+
+The [SDK repository](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/docs/examples/) includes additional examples for common use cases:
+
+- Fetching a single report, bulk reports, or paginated reports
+- Compressing report data
+- Simple WebSocket streaming
+- Multiple WebSocket endpoints (HA)
+
+## Performance Considerations
+
+- Reuse the same `Client` instance whenever possible
+- Gracefully close WebSocket `Stream` objects when not in use (`stream.close().await?`)
+- Monitor memory usage if you expect large volumes of data
+- Use timeouts or retry logic in your own application where needed
+
+## Configuration Reference
+
+Below is a detailed guide to the available builder methods for the `ConfigBuilder`. Each method is **optional** but can help you tailor the SDK’s behavior for your specific needs.
+
+```rust
+pub struct ConfigBuilder {
+ // Enables High Availability (HA) for WebSocket connections
+ pub fn with_ws_ha(mut self, WebSocketHighAvailability) -> Self;
+
+ // Sets the max number of WebSocket reconnection attempts before giving up
+ pub fn with_ws_max_reconnect(mut self, usize) -> Self;
+
+ // Allows skipping TLS certificate verification (use with caution in production)
+ pub fn with_insecure_skip_verify(mut self, InsecureSkipVerify) -> Self;
+
+ // Provides a way to inspect HTTP responses for logging or debugging (REST calls only)
+ pub fn with_inspect_http_response(mut self, fn(&Response)) -> Self;
+
+ // Finalizes and validates the config
+ pub fn build(self) -> Result;
+}
+```
+
+### `with_ws_ha(WebSocketHighAvailability)`
+
+- Purpose: Enables or disables HA mode for WebSocket streaming.
+- Values:
+ - `WebSocketHighAvailability::Enabled`: Maintains multiple WebSocket connections to different endpoints simultaneously.
+ - `WebSocketHighAvailability::Disabled`: Maintains a single connection.
+- Default: `Disabled`.
+- Example Use Case:
+
+ ```rust
+ // When you want uninterrupted streaming even if one server goes down:
+ let config = Config::new(api_key, api_secret, rest_url, "wss://ws1,...,wss://wsN")
+ .with_ws_ha(WebSocketHighAvailability::Enabled)
+ .build()?;
+ ```
+
+### `with_ws_max_reconnect(usize)`
+
+- Purpose: Sets the maximum number of reconnection attempts before the SDK stops trying.
+- Default: `5`.
+- Parameter: `usize` indicates how many times you want the SDK to attempt reconnecting after a connection failure.
+- Example Use Case:
+
+ ```rust
+ // If you want to be very persistent:
+ .with_ws_max_reconnect(20)
+ ```
+
+### `with_insecure_skip_verify(InsecureSkipVerify)`
+
+- Purpose: When set, it allows skipping TLS certificate verification.
+- Values:
+ - `InsecureSkipVerify::Enabled`: Skips verification of certificates — useful for local dev or self-signed certs.
+ - `InsecureSkipVerify::Disabled`: Normal, secure certificate handling (recommended for production).
+- Default: `Disabled`.
+- Example Use Case:
+
+ ```rust
+ // Useful in development when using self-signed certs or containers
+ .with_insecure_skip_verify(InsecureSkipVerify::Enabled)
+ ```
+
+### `with_inspect_http_response(fn(&Response))`
+
+- Purpose: Allows you to provide a callback function that inspects any HTTP `Response` received by the REST client.
+- Default: `None`. (No inspection)
+- Example:
+
+ ```rust
+ // Log every HTTP response's status code
+ .with_inspect_http_response(|response| {
+ println!("Received HTTP status: {}", response.status());
+ })
+ ```
diff --git a/src/content/data-streams/streams-direct/index.mdx b/src/content/data-streams/streams-direct/index.mdx
new file mode 100644
index 00000000000..c4d23031269
--- /dev/null
+++ b/src/content/data-streams/streams-direct/index.mdx
@@ -0,0 +1,76 @@
+---
+section: dataStreams
+title: "Streams Direct Implementation"
+date: Last Modified
+isIndex: true
+whatsnext:
+ {
+ "Learn how to fetch and decode Data Streams reports": "/data-streams/tutorials/streams-direct/streams-direct-api",
+ "Explore the Go SDK": "/data-streams/reference/streams-direct/streams-direct-go-sdk",
+ "Explore the Rust SDK": "/data-streams/reference/streams-direct/streams-direct-rust-sdk",
+ "Learn about onchain verification": "/data-streams/reference/streams-direct/streams-direct-onchain-verification",
+ }
+---
+
+import { Aside, ClickToZoom } from "@components"
+
+The Streams Direct implementation provides direct access to Chainlink Data Streams through SDKs and APIs, allowing you to build custom solutions with low-latency, high-frequency data. This implementation enables you to fetch reports or subscribe to report updates from the Data Streams Aggregation Network and verify their authenticity onchain. For instance, you can use Chainlink Data Streams with the Streams Direct implementation to display indicative pricing offchain on your front end or with your bot to settle trades onchain.
+
+
+
+## Key Features
+
+- **Direct API Access**: Fetch data directly using REST API or WebSocket connections
+- **Multiple SDK Options**: Choose between Go and Rust SDKs for seamless integration
+- **Flexible Implementation**: Build custom solutions for both offchain display and onchain settlement
+- **Onchain Verification**: Verify data authenticity when needed
+
+## Getting Started
+
+To implement Streams Direct in your application:
+
+1. Review the [Architecture Documentation](/data-streams/architecture#streams-direct-architecture) to understand the system components
+2. Choose your preferred SDK:
+ - [Go SDK Documentation](/data-streams/reference/streams-direct/streams-direct-go-sdk)
+ - [Rust SDK Documentation](/data-streams/reference/streams-direct/streams-direct-rust-sdk)
+3. Follow our [API Tutorial](/data-streams/tutorials/streams-direct/streams-direct-api) to learn how to fetch and decode reports
+4. Implement [onchain verification](/data-streams/reference/streams-direct/streams-direct-onchain-verification) for your use case
+
+## Common Use Cases
+
+Streams Direct is particularly well-suited for:
+
+- **Custom Trading Bots**: Build automated trading systems with direct access to high-frequency data
+- **Front-end Price Display**: Show real-time indicative pricing in your dApp interface
+- **Custom Settlement Logic**: Implement specialized settlement mechanisms using verified data
+- **Market Analysis Tools**: Create tools for market analysis and monitoring
+
+## Integration Options
+
+### REST API
+
+Use the REST API to fetch individual reports on demand. This is ideal for:
+
+- One-time data queries
+- Periodic updates at custom intervals
+- Integration with existing REST-based systems
+
+### WebSocket Connection
+
+Subscribe to continuous updates via WebSocket for:
+
+- Real-time price updates
+- Streaming market data
+- Immediate notification of new reports
+
+## Learn More
+
+- [API Tutorial](/data-streams/tutorials/streams-direct/streams-direct-api)
+- [Go SDK Documentation](/data-streams/reference/streams-direct/streams-direct-go-sdk)
+- [Rust SDK Documentation](/data-streams/reference/streams-direct/streams-direct-rust-sdk)
+- [Onchain Verification](/data-streams/reference/streams-direct/streams-direct-onchain-verification)
+- [Available Stream IDs](/data-streams/crypto-streams)
+- [Report Schemas](/data-streams/reference/report-schema)
diff --git a/src/content/data-streams/streams-trade/index.mdx b/src/content/data-streams/streams-trade/index.mdx
new file mode 100644
index 00000000000..8315f46a7e1
--- /dev/null
+++ b/src/content/data-streams/streams-trade/index.mdx
@@ -0,0 +1,50 @@
+---
+section: dataStreams
+title: "Streams Trade Implementation"
+date: Last Modified
+isIndex: true
+whatsnext:
+ {
+ "Learn how to get started with Streams Trade": "/data-streams/getting-started",
+ "Understand the Streams Trade architecture": "/data-streams/architecture#streams-trade-architecture",
+ "View example trading flows": "/data-streams/architecture#example-trading-flow-using-streams-trade",
+ "Check supported networks": "/chainlink-automation/overview/supported-networks",
+ }
+---
+
+import { Aside, ClickToZoom } from "@components"
+
+The Streams Trade implementation combines Chainlink Data Streams with [Chainlink Automation](/chainlink-automation) to enable automated trade execution. This implementation allows decentralized applications to automate trade execution, mitigate frontrunning, and limit bias or adverse incentives in executing non-user-triggered orders.
+
+
+
+Read more about the [Streams Trade Architecture](/data-streams/architecture#streams-trade-architecture) and an [example trading flow](/data-streams/architecture#example-trading-flow-using-streams-trade).
+
+## Getting Started
+
+To implement Streams Trade in your application:
+
+1. First, ensure Chainlink Automation is available on your desired network by checking the [Supported Networks](/chainlink-automation/overview/supported-networks) page.
+1. Review the [Architecture Documentation](/data-streams/architecture#streams-trade-architecture) to understand the system components.
+1. See an [Example Trading Flow](/data-streams/architecture#example-trading-flow-using-streams-trade) to understand how trades are executed.
+1. Follow our [Getting Started Guide](/data-streams/getting-started) to set up your first integration.
+
+## Common Use Cases
+
+Streams Trade is particularly well-suited for:
+
+- **Perpetual Futures Protocols**: Enable high-performance onchain perpetual futures that can compete with centralized exchanges
+- **Automated Market Making**: Implement sophisticated market making strategies with real-time price updates
+- **Options Protocols**: Enable precise and timely settlement of options contracts
+- **Prediction Markets**: Allow quick responses to real-time events with accurate settlement data
+
+## Learn More
+
+- [Getting Started Guide](/data-streams/getting-started)
+- [Architecture Overview](/data-streams/architecture#streams-trade-architecture)
+- [Example Trading Flows](/data-streams/architecture#example-trading-flow-using-streams-trade)
+- [Available Stream IDs](/data-streams/crypto-streams)
+- [Report Schemas](/data-streams/reference/report-schema)
diff --git a/src/content/data-streams/tutorials/streams-direct/evm-onchain-report-verification.mdx b/src/content/data-streams/tutorials/streams-direct/evm-onchain-report-verification.mdx
index 0d8ce5147f1..e677ab986e0 100644
--- a/src/content/data-streams/tutorials/streams-direct/evm-onchain-report-verification.mdx
+++ b/src/content/data-streams/tutorials/streams-direct/evm-onchain-report-verification.mdx
@@ -37,7 +37,7 @@ In this guide, you'll learn how to verify onchain the integrity of reports by co
## Before you begin
-Make sure you understand how to use the [Streams Direct](/data-streams#streams-direct-using-data-streams-with-your-own-bot) implementation of Chainlink Data Streams to fetch reports via the [REST API](/data-streams/reference/streams-direct/streams-direct-interface-api) or [WebSocket](/data-streams/reference/streams-direct/streams-direct-interface-ws) connection. Refer to the following guides for more information:
+Make sure you understand how to use the [Streams Direct](/data-streams/streams-direct) implementation of Chainlink Data Streams to fetch reports via the [REST API](/data-streams/reference/streams-direct/streams-direct-interface-api) or [WebSocket](/data-streams/reference/streams-direct/streams-direct-interface-ws) connection. Refer to the following guides for more information:
- [Fetch and decode reports via a REST API](/data-streams/tutorials/streams-direct/streams-direct-api)
- [Stream and decode reports via WebSocket](/data-streams/tutorials/streams-direct/streams-direct-ws)
diff --git a/src/content/data-streams/tutorials/streams-direct/index.mdx b/src/content/data-streams/tutorials/streams-direct/index.mdx
index ac38174bed4..fa761cfd3f0 100644
--- a/src/content/data-streams/tutorials/streams-direct/index.mdx
+++ b/src/content/data-streams/tutorials/streams-direct/index.mdx
@@ -5,7 +5,7 @@ title: "Streams Direct guides"
isIndex: true
---
-Explore several guides to learn how to use the [Streams Direct](/data-streams#streams-direct-using-data-streams-with-your-own-bot) implementation with the [Data Streams SDK](/data-streams/reference/streams-direct/streams-direct-go-sdk) for Go.
+Explore several guides to learn how to use the [Streams Direct](/data-streams/streams-direct) implementation with the [Data Streams SDK](/data-streams/reference/streams-direct/streams-direct-go-sdk) for Go.
- [Fetch and decode reports](/data-streams/tutorials/streams-direct/streams-direct-api): Learn how to fetch and decode reports from the Data Streams Aggregation Network.
- [Stream and decode reports (WebSocket)](/data-streams/tutorials/streams-direct/streams-direct-ws): Learn how to listen for real-time reports from the Data Streams Aggregation Network, decode the report data, and log their attributes.
diff --git a/src/content/data-streams/tutorials/streams-direct/streams-direct-api-go.mdx b/src/content/data-streams/tutorials/streams-direct/streams-direct-api-go.mdx
new file mode 100644
index 00000000000..a3c28ff8228
--- /dev/null
+++ b/src/content/data-streams/tutorials/streams-direct/streams-direct-api-go.mdx
@@ -0,0 +1,587 @@
+---
+section: dataStreams
+date: Last Modified
+title: "Fetch and decode V3 reports using the Go SDK"
+whatsnext:
+ {
+ "Learn how to stream and decode reports via a WebSocket connection": "/data-streams/tutorials/streams-direct/streams-direct-ws",
+ "Learn how to verify your data onchain": "/data-streams/reference/streams-direct/streams-direct-onchain-verification",
+ "Find the list of available Stream IDs": "/data-streams/crypto-streams",
+ }
+---
+
+import { CopyText, PageTabs } from "@components"
+import DataStreams from "@features/data-streams/common/DataStreams.astro"
+
+
+
+
+
+In this guide, you'll learn how to use Chainlink Data Streams with the _[Streams Direct](/data-streams/streams-direct) implementation_ and the [Data Streams SDK](/data-streams/reference/streams-direct/streams-direct-go-sdk) for Go to fetch and decode [V3 reports](/data-streams/reference/report-schema) for [Crypto streams](/data-streams/crypto-streams) from the Data Streams Aggregation Network. You'll set up your Go project, retrieve reports, decode them, and log their attributes.
+
+
+
+## Requirements
+
+- **Git**: Make sure you have Git installed. You can check your current version by running in your terminal and download the latest version from the official [Git website](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) if necessary.
+- **Go Version**: Make sure you have Go version 1.21 or higher. You can check your current version by running `go version` in your terminal and download the latest version from the official [Go website](https://go.dev/) if necessary.
+- **API Credentials**: Access to the Streams Direct implementation requires API credentials. If you haven't already, [contact us](https://chainlinkcommunity.typeform.com/datastreams?typeform-source=docs.chain.link#ref_id=docs) to request mainnet or testnet early access.
+
+## Guide
+
+You'll start with the set up of your Go project. Next, you'll fetch and decode reports for both single and multiple [crypto streams](/data-streams/crypto-streams), and log their attributes to your terminal.
+
+### Set up your Go project
+
+1. Create a new directory for your project and navigate to it:
+
+ ```bash
+ mkdir my-data-streams-project
+ cd my-data-streams-project
+ ```
+
+1. Initialize a new Go module:
+
+ ```bash
+ go mod init my-data-streams-project
+ ```
+
+1. Install the Data Streams SDK:
+
+ ```bash
+ go get github.com/smartcontractkit/data-streams-sdk/go
+ ```
+
+### Fetch and decode a report with a single stream
+
+1. Create a new Go file, `single-stream.go`, in your project directory:
+
+ ```bash
+ touch single-stream.go
+ ```
+
+1. Insert the following code example and save your `single-stream.go` file:
+
+ ```go
+ package main
+
+ import (
+ "context"
+ "fmt"
+ "os"
+ "time"
+
+ streams "github.com/smartcontractkit/data-streams-sdk/go"
+ feed "github.com/smartcontractkit/data-streams-sdk/go/feed"
+ report "github.com/smartcontractkit/data-streams-sdk/go/report"
+ v3 "github.com/smartcontractkit/data-streams-sdk/go/report/v3" // Import the v3 report schema for Crypto streams
+ )
+
+ func main() {
+ // Validate command-line arguments
+ if len(os.Args) < 2 {
+ fmt.Printf("Usage: go run main.go [FeedID]\nExample: go run main.go 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782\n")
+ os.Exit(1)
+ }
+ feedIDInput := os.Args[1]
+
+ // Get API credentials from environment variables
+ apiKey := os.Getenv("API_KEY")
+ apiSecret := os.Getenv("API_SECRET")
+ if apiKey == "" || apiSecret == "" {
+ fmt.Printf("API_KEY and API_SECRET environment variables must be set\n")
+ os.Exit(1)
+ }
+
+ // Define the configuration for the SDK client
+ cfg := streams.Config{
+ ApiKey: apiKey,
+ ApiSecret: apiSecret,
+ RestURL: "https://api.testnet-dataengine.chain.link",
+ Logger: streams.LogPrintf,
+ }
+
+ // Initialize the SDK client
+ client, err := streams.New(cfg)
+ if err != nil {
+ cfg.Logger("Failed to create client: %v\n", err)
+ os.Exit(1)
+ }
+
+ // Create context with timeout
+ ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
+ defer cancel()
+
+ // Parse the feed ID
+ var feedID feed.ID
+ if err := feedID.FromString(feedIDInput); err != nil {
+ cfg.Logger("Invalid feed ID format '%s': %v\n", feedIDInput, err)
+ os.Exit(1)
+ }
+
+ // Fetch the latest report
+ reportResponse, err := client.GetLatestReport(ctx, feedID)
+ if err != nil {
+ cfg.Logger("Failed to get latest report: %v\n", err)
+ os.Exit(1)
+ }
+
+ // Log the raw report data
+ cfg.Logger("Raw report data: %+v\n", reportResponse)
+
+ // Decode the report
+ decodedReport, err := report.Decode[v3.Data](reportResponse.FullReport)
+ if err != nil {
+ cfg.Logger("Failed to decode report: %v\n", err)
+ os.Exit(1)
+ }
+
+ // Format and display the decoded report
+ fmt.Printf("\nDecoded Report for Stream ID %s:\n"+
+ "------------------------------------------\n"+
+ "Observations Timestamp: %d\n"+
+ "Benchmark Price : %s\n"+
+ "Bid : %s\n"+
+ "Ask : %s\n"+
+ "Valid From Timestamp : %d\n"+
+ "Expires At : %d\n"+
+ "Link Fee : %s\n"+
+ "Native Fee : %s\n"+
+ "------------------------------------------\n",
+ feedIDInput,
+ decodedReport.Data.ObservationsTimestamp,
+ decodedReport.Data.BenchmarkPrice.String(),
+ decodedReport.Data.Bid.String(),
+ decodedReport.Data.Ask.String(),
+ decodedReport.Data.ValidFromTimestamp,
+ decodedReport.Data.ExpiresAt,
+ decodedReport.Data.LinkFee.String(),
+ decodedReport.Data.NativeFee.String(),
+ )
+ }
+ ```
+
+1. Download the required dependencies and update the `go.mod` and `go.sum` files:
+
+ ```bash
+ go mod tidy
+ ```
+
+1. Set up the SDK client configuration within `single-stream.go` with your API credentials and the REST endpoint:
+
+ ```go
+ cfg := streams.Config{
+ ApiKey: os.Getenv("API_KEY"),
+ ApiSecret: os.Getenv("API_SECRET"),
+ RestURL: "https://api.testnet-dataengine.chain.link",
+ Logger: streams.LogPrintf,
+ }
+ ```
+
+ - Set your API credentials as environment variables:
+
+ ```bash
+ export API_KEY=""
+ export API_SECRET=""
+ ```
+
+ Replace `` and `` with your API credentials.
+
+ - `RestURL` is the REST endpoint to poll for specific reports. See the [Streams Direct Interface](/data-streams/reference/streams-direct/streams-direct-interface-api#domains) page for more information.
+
+ See the [SDK Reference](/data-streams/reference/streams-direct/streams-direct-go-sdk#config-struct) page for more configuration options.
+
+1. For this example, you will read from the ETH/USD crypto stream. This stream ID is . See the [Stream Addresses](/data-streams/crypto-streams) page for a complete list of available crypto assets.
+
+ Execute your application:
+
+```bash
+go run single-stream.go 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782
+```
+
+Expect output similar to the following in your terminal:
+
+```bash
+Raw report data: {"fullReport":"0x0006f9b553e393ced311551efd30d1decedb63d76ad41737462e2cdbbdff1578000000000000000000000000000000000000000000000000000000004f8e8a11000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000028001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000120000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba78200000000000000000000000000000000000000000000000000000000675e0a5b00000000000000000000000000000000000000000000000000000000675e0a5b00000000000000000000000000000000000000000000000000001787ff5c6fb8000000000000000000000000000000000000000000000000000c01807477ecd000000000000000000000000000000000000000000000000000000000675f5bdb0000000000000000000000000000000000000000000000d1865f8f627c4113300000000000000000000000000000000000000000000000d18572c6cdc3b915000000000000000000000000000000000000000000000000d1879ab8e98f743ad00000000000000000000000000000000000000000000000000000000000000002f3316e5c964d118f6683eecda454985fcc696e4ba34d65edb4a71a8d0cfe970676f465618c7d01196e433cc35b6994e7ad7b8189b0462b51458e663d601fdfaa0000000000000000000000000000000000000000000000000000000000000002219a4493fdf311421d664e0c8d69efa74b776461f8e252d191eda7edb980ab9a5cce69ec0ad35ba210cf60a201ceff6771b35b44860fda859f4aaba242c476bf","feedID":"0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782","validFromTimestamp":1734216283,"observationsTimestamp":1734216283}
+
+Decoded Report for Stream ID 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782:
+------------------------------------------
+Observations Timestamp: 1734216283
+Benchmark Price : 3865052126782320350000
+Bid : 3864985478146740000000
+Ask : 3865140837060103650000
+Valid From Timestamp : 1734216283
+Expires At : 1734302683
+Link Fee : 3379350941986000
+Native Fee : 25872872271800
+------------------------------------------
+```
+
+#### Decoded report details
+
+The decoded report details include:
+
+| Attribute | Value | Description |
+| ------------------------ | -------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `Stream ID` | `0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782` | The unique identifier for the stream. In this example, the stream is for ETH/USD. |
+| `Observations Timestamp` | `1734216283` | The timestamp indicating when the data was captured. |
+| `Benchmark Price` | `3865052126782320350000` | The observed price in the report, with 18 decimals. For readability: `3,865.0521267823204` USD per ETH. |
+| `Bid` | `3864985478146740000000` | The highest price a buyer is willing to pay for an asset, with 18 decimals. For readability: `3,864.9854781467400` USD per ETH. Learn more about the [Bid price](/data-streams/concepts/liquidity-weighted-prices). |
+| `Ask` | `3865140837060103650000` | The lowest price a seller is willing to accept for an asset, with 18 decimals. For readability: `3,865.1408370601037` USD per ETH. Learn more about the [Ask price](/data-streams/concepts/liquidity-weighted-prices). |
+| `Valid From Timestamp` | `1734216283` | The start validity timestamp for the report, indicating when the data becomes relevant. |
+| `Expires At` | `1734302683` | The expiration timestamp of the report, indicating the point at which the data becomes outdated. |
+| `Link Fee` | `3379350941986000` | The fee to pay in LINK tokens for the onchain verification of the report data. With 18 decimals. For readability: `0.03379350941986` LINK. **Note:** This example fee is not indicative of actual fees. |
+| `Native Fee` | `25872872271800` | The fee to pay in the native blockchain token (e.g., ETH on Ethereum) for the onchain verification of the report data. With 18 decimals. **Note:** This example fee is not indicative of actual fees. |
+
+#### Payload for onchain verification
+
+In this guide, you log and decode the `full_report` payload to extract the report data. In a
+production environment, you should verify the data to ensure its integrity and authenticity. Refer to the
+[Verify report data onchain](/data-streams/tutorials/streams-direct/streams-direct-onchain-verification) guide.
+
+### Fetch and decode reports for multiple streams
+
+1. Create a new Go file, `multiple-streams.go`, in your project directory:
+
+ ```bash
+ touch multiple-streams.go
+ ```
+
+1. Insert the following code example in your `multiple-streams.go` file:
+
+ ```go
+ package main
+
+ import (
+ "context"
+ "fmt"
+ "os"
+ "time"
+
+ streams "github.com/smartcontractkit/data-streams-sdk/go"
+ feed "github.com/smartcontractkit/data-streams-sdk/go/feed"
+ report "github.com/smartcontractkit/data-streams-sdk/go/report"
+ v3 "github.com/smartcontractkit/data-streams-sdk/go/report/v3" // Import the v3 report schema for Crypto streams
+ )
+
+ func main() {
+ // Validate command-line arguments
+ if len(os.Args) < 3 {
+ fmt.Printf("Usage: go run multiple-streams.go [StreamID1] [StreamID2] ...\n"+
+ "Example: go run multiple-streams.go "+
+ "0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782 "+
+ "0x00036fe43f87884450b4c7e093cd5ed99cac6640d8c2000e6afc02c8838d0265\n")
+ os.Exit(1)
+ }
+
+ // Get API credentials from environment variables
+ apiKey := os.Getenv("API_KEY")
+ apiSecret := os.Getenv("API_SECRET")
+ if apiKey == "" || apiSecret == "" {
+ fmt.Printf("API_KEY and API_SECRET environment variables must be set\n")
+ os.Exit(1)
+ }
+
+ // Define the configuration for the SDK client
+ cfg := streams.Config{
+ ApiKey: apiKey,
+ ApiSecret: apiSecret,
+ RestURL: "https://api.testnet-dataengine.chain.link",
+ Logger: streams.LogPrintf,
+ }
+
+ // Initialize the SDK client
+ client, err := streams.New(cfg)
+ if err != nil {
+ cfg.Logger("Failed to create client: %v\n", err)
+ os.Exit(1)
+ }
+
+ // Create context with timeout
+ ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
+ defer cancel()
+
+ // Parse Feed IDs
+ var ids []feed.ID
+ for _, arg := range os.Args[1:] {
+ var fid feed.ID
+ if err := fid.FromString(arg); err != nil {
+ cfg.Logger("Invalid feed ID format '%s': %v\n", arg, err)
+ continue
+ }
+ ids = append(ids, fid)
+ }
+
+ if len(ids) == 0 {
+ cfg.Logger("No valid feed IDs provided\n")
+ os.Exit(1)
+ }
+
+ // Fetch reports for all streams
+ timestamp := uint64(time.Now().Unix())
+ reportResponses, err := client.GetReports(ctx, ids, timestamp)
+ if err != nil {
+ cfg.Logger("Failed to get reports: %v\n", err)
+ os.Exit(1)
+ }
+
+ // Process reports
+ for _, reportResponse := range reportResponses {
+ // Log the raw report data
+ cfg.Logger("Raw report data for Stream ID %s: %+v\n",
+ reportResponse.FeedID.String(), reportResponse)
+
+ // Decode the report
+ decodedReport, err := report.Decode[v3.Data](reportResponse.FullReport)
+ if err != nil {
+ cfg.Logger("Failed to decode report for Stream ID %s: %v\n",
+ reportResponse.FeedID.String(), err)
+ continue // Skip to next report if decoding fails
+ }
+
+ // Format and display the decoded report
+ fmt.Printf("\nDecoded Report for Stream ID %s:\n"+
+ "------------------------------------------\n"+
+ "Observations Timestamp: %d\n"+
+ "Benchmark Price : %s\n"+
+ "Bid : %s\n"+
+ "Ask : %s\n"+
+ "Valid From Timestamp : %d\n"+
+ "Expires At : %d\n"+
+ "Link Fee : %s\n"+
+ "Native Fee : %s\n"+
+ "------------------------------------------\n",
+ reportResponse.FeedID.String(),
+ decodedReport.Data.ObservationsTimestamp,
+ decodedReport.Data.BenchmarkPrice.String(),
+ decodedReport.Data.Bid.String(),
+ decodedReport.Data.Ask.String(),
+ decodedReport.Data.ValidFromTimestamp,
+ decodedReport.Data.ExpiresAt,
+ decodedReport.Data.LinkFee.String(),
+ decodedReport.Data.NativeFee.String(),
+ )
+ }
+ }
+ ```
+
+1. Before running the example, verify that your API credentials are still set in your current terminal session:
+
+ ```bash
+ echo $API_KEY
+ echo $API_SECRET
+ ```
+
+ If the commands above don't show your credentials, set them again:
+
+ ```bash
+ export API_KEY=""
+ export API_SECRET=""
+ ```
+
+1. For this example, you will read from the ETH/USD and LINK/USD Data Streams crypto streams. Run your application:
+
+ ```bash
+ go run multiple-streams.go 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782 0x00036fe43f87884450b4c7e093cd5ed99cac6640d8c2000e6afc02c8838d0265
+ ```
+
+ Expect to see the output below in your terminal:
+
+ ```bash
+ 2024-12-14T17:49:06-05:00 Raw report data for Stream ID 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782: {"fullReport":"0x0006f9b553e393ced311551efd30d1decedb63d76ad41737462e2cdbbdff1578000000000000000000000000000000000000000000000000000000004f8eb301000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000028001010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000120000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba78200000000000000000000000000000000000000000000000000000000675e0b6100000000000000000000000000000000000000000000000000000000675e0b610000000000000000000000000000000000000000000000000000178bcfba6d60000000000000000000000000000000000000000000000000000c1536af09b42c00000000000000000000000000000000000000000000000000000000675f5ce10000000000000000000000000000000000000000000000d1646f5fd0b1e6e6a00000000000000000000000000000000000000000000000d1635f8df6b0fce2600000000000000000000000000000000000000000000000d1677c13a6c9d89620000000000000000000000000000000000000000000000000000000000000000222412e1bd137097dc97def8914c72ae7305179eedc5c15e344bc119a06f1db76ef20f3e6493a97c2be2ab831199bfc00dbbf02551f2a27a70cfd55653270acac0000000000000000000000000000000000000000000000000000000000000002343957d73014b446eb0b0436072e16261a643102e502529d3b97412027c3468977bf0806e8971a37e6487b855243957a57749cde2ac92ebc2bda412d94981251","feedID":"0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782","validFromTimestamp":1734216545,"observationsTimestamp":1734216545}
+
+
+ Decoded Report for Stream ID 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782:
+ ------------------------------------------
+ Observations Timestamp: 1734216545
+ Benchmark Price : 3862606619881446500000
+ Bid : 3862530109428509500000
+ Ask : 3862826368095386900000
+ Valid From Timestamp : 1734216545
+ Expires At : 1734302945
+ Link Fee : 3401024329593900
+ Native Fee : 25889252994400
+ ------------------------------------------
+ 2024-12-14T17:49:06-05:00 Raw report data for Stream ID 0x00036fe43f87884450b4c7e093cd5ed99cac6640d8c2000e6afc02c8838d0265: {"fullReport":"0x00060a2676459d14176b64106fcf3246631d3a03734171737eb082fe79c956e0000000000000000000000000000000000000000000000000000000005437220a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002800001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012000036fe43f87884450b4c7e093cd5ed99cac6640d8c2000e6afc02c8838d026500000000000000000000000000000000000000000000000000000000675e0b6100000000000000000000000000000000000000000000000000000000675e0b610000000000000000000000000000000000000000000000000000178bc5ba4c04000000000000000000000000000000000000000000000000000c153d429e703c00000000000000000000000000000000000000000000000000000000675f5ce1000000000000000000000000000000000000000000000001980b3d7d3ec2df6000000000000000000000000000000000000000000000000197f69e569cfba588000000000000000000000000000000000000000000000001981e643ba148a6040000000000000000000000000000000000000000000000000000000000000002ae4d6d1a241622f6b9c5cc53c5ac6abc4e46759c7bda4942936e02f2fc9ba7374869e71ce1572ae581049e6e9463537056031e30b0c11f84ff44e45363e3fa9300000000000000000000000000000000000000000000000000000000000000021ab422f2202e0f59016a29b37c2795b47d78c19ba2358808794c6f0cd3b04bde7adb2f30669b051ddde1059f106c161c65c401909b78d76bd13ad593e31ab13e","feedID":"0x00036fe43f87884450b4c7e093cd5ed99cac6640d8c2000e6afc02c8838d0265","validFromTimestamp":1734216545,"observationsTimestamp":1734216545}
+
+
+ Decoded Report for Stream ID 0x00036fe43f87884450b4c7e093cd5ed99cac6640d8c2000e6afc02c8838d0265:
+ ------------------------------------------
+ Observations Timestamp: 1734216545
+ Benchmark Price : 29402662200351580000
+ Bid : 29396857712545605000
+ Ask : 29408052824047658500
+ Valid From Timestamp : 1734216545
+ Expires At : 1734302945
+ Link Fee : 3401052575395900
+ Native Fee : 25889085213700
+ ------------------------------------------
+ ```
+
+ Your application has successfully fetched and decoded data for both streams.
+
+#### Payload for onchain verification
+
+In this guide, you log and decode the `fullReport` payloads to extract the report data. In a
+production environment, you should verify the data to ensure its integrity and authenticity. Refer to the
+[Verify report data onchain](/data-streams/tutorials/streams-direct/streams-direct-onchain-verification) guide.
+
+## Explanation
+
+### Initializing the client and configuration
+
+The Data Streams client is initialized in two steps:
+
+1. Configure the client with [`streams.Config`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/go/config.go#L10):
+
+ ```go
+ cfg := streams.Config{
+ ApiKey: os.Getenv("API_KEY"),
+ ApiSecret: os.Getenv("API_SECRET"),
+ RestURL: "https://api.testnet-dataengine.chain.link",
+ Logger: streams.LogPrintf,
+ }
+ ```
+
+ The configuration requires:
+
+ - `ApiKey` and `ApiSecret` for authentication (required)
+ - `RestURL` for the API endpoint (required)
+ - `Logger` for debugging and error tracking (optional, defaults to `streams.LogPrintf`)
+
+2. Create the client with [`streams.New`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/go/client.go#L56):
+ ```go
+ client, err := streams.New(cfg)
+ ```
+ The client handles:
+ - Authentication with HMAC signatures
+ - Connection management and timeouts
+ - Error handling and retries
+
+### Fetching reports
+
+The SDK provides two main methods to fetch reports:
+
+1. Latest report for a single stream with [`GetLatestReport`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/go/client.go#L130):
+
+ ```go
+ reportResponse, err := client.GetLatestReport(ctx, feedID)
+ ```
+
+ - Takes a context and feed ID
+ - Returns a single `ReportResponse` with the most recent data
+ - No timestamp parameter needed
+ - Useful for real-time price monitoring
+
+2. Latest reports for multiple streams with [`GetReports`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/go/client.go#L208):
+
+ ```go
+ reportResponses, err := client.GetReports(ctx, ids, timestamp)
+ ```
+
+ - Takes context, feed IDs array, and Unix timestamp
+ - Returns array of `ReportResponse`, one per feed ID
+ - Timestamp determines the point in time for the reports
+ - Efficient for monitoring multiple assets simultaneously
+
+Each API request automatically:
+
+- Handles authentication with API credentials
+- Manages request timeouts via context
+- Processes responses into structured types
+
+### Decoding reports
+
+Reports are decoded in two steps:
+
+1. Report decoding with [`report.Decode`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/go/report/report.go#L30):
+
+ ```go
+ decodedReport, err := report.Decode[v3.Data](reportResponse.FullReport)
+ ```
+
+ This step:
+
+ - Takes the raw `FullReport` bytes from the response
+ - Uses `v3.Data` schema for Crypto streams (use `v4.Data` for RWA streams)
+ - Validates the format and decodes using Go generics
+ - Returns a structured report with typed data
+
+2. Data access:
+ ```go
+ data := decodedReport.Data
+ price := data.BenchmarkPrice.String() // Convert big number to string
+ bid := data.Bid.String() // All prices use 18 decimal places
+ ask := data.Ask.String()
+ validFrom := data.ValidFromTimestamp // Unix timestamp
+ expiresAt := data.ExpiresAt // Unix timestamp
+ ```
+ Provides access to:
+ - Benchmark price, bid, and ask prices (as big numbers)
+ - Fee information (LINK and native token fees)
+ - Timestamp data (validity period)
+ - All numeric values require `.String()` for display
+
+### Error handling
+
+The SDK uses Go's standard error handling patterns with some enhancements:
+
+1. Context management:
+
+ ```go
+ ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
+ defer cancel()
+ ```
+
+ - Sets request timeouts for API calls
+ - `defer cancel()` ensures cleanup of resources
+ - Same context pattern for both single and multiple reports
+
+2. Error checking:
+
+ ```go
+ if err != nil {
+ cfg.Logger("Failed to decode report: %v\n", err)
+ os.Exit(1) // Fatal errors: exit the program
+ // or
+ continue // Non-fatal errors: skip this report
+ }
+ ```
+
+ - Fatal errors (client creation, no valid feeds) use `os.Exit(1)`
+ - Non-fatal errors (single report decode) use `continue`
+ - All errors are logged before handling
+
+3. SDK logging:
+ ```go
+ cfg.Logger("Raw report data: %+v\n", reportResponse)
+ ```
+ - Uses configured logger for SDK operations
+ - `fmt.Printf` for user-facing output
+ - Debug information includes raw report data
+ - Structured error messages with context
+
+The decoded data can be used for further processing or display in your application. For production environments, you must verify the data onchain using the provided `fullReport` payload.
diff --git a/src/content/data-streams/tutorials/streams-direct/streams-direct-api-rust.mdx b/src/content/data-streams/tutorials/streams-direct/streams-direct-api-rust.mdx
new file mode 100644
index 00000000000..8b5355dd489
--- /dev/null
+++ b/src/content/data-streams/tutorials/streams-direct/streams-direct-api-rust.mdx
@@ -0,0 +1,288 @@
+---
+section: dataStreams
+date: Last Modified
+title: "Fetch and decode V3 reports using the Rust SDK"
+whatsnext:
+ {
+ "Learn how to stream and decode reports via a WebSocket connection": "/data-streams/tutorials/streams-direct/streams-direct-ws-rust",
+ "Learn how to verify your data onchain": "/data-streams/reference/streams-direct/streams-direct-onchain-verification",
+ "Find the list of available Stream IDs": "/data-streams/crypto-streams",
+ }
+---
+
+import { CopyText, PageTabs } from "@components"
+import DataStreams from "@features/data-streams/common/DataStreams.astro"
+
+
+
+
+
+In this guide, you'll learn how to use Chainlink Data Streams with the _[Streams Direct](/data-streams/streams-direct) implementation_ and the [Data Streams SDK](/data-streams/reference/streams-direct/streams-direct-rust-sdk) for Rust to fetch and decode [V3 reports](/data-streams/reference/report-schema) for [Crypto streams](/data-streams/crypto-streams) from the Data Streams Aggregation Network. You'll set up your Rust project, retrieve reports, decode them, and log their attributes.
+
+
+
+## Requirements
+
+- **Git**: Make sure you have Git installed. You can check your current version by running in your terminal and download the latest version from the official [Git website](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) if necessary.
+- **Rust**: Make sure you have Rust installed. You can install Rust by following the instructions on the official [Rust website](https://www.rust-lang.org/tools/install).
+- **API Credentials**: Access to the Streams Direct implementation requires API credentials. If you haven't already, [contact us](https://chainlinkcommunity.typeform.com/datastreams?typeform-source=docs.chain.link#ref_id=docs) to request mainnet or testnet early access.
+
+## Guide
+
+You'll start with the set up of your Rust project. Next, you'll fetch and decode reports for crypto streams and log their attributes to your terminal.
+
+### Set up your Rust project
+
+1. Create a new directory for your project and navigate to it:
+
+ ```bash
+ mkdir my-data-streams-project && cd my-data-streams-project
+ ```
+
+1. Initialize a new Rust project:
+
+ ```bash
+ cargo init
+ ```
+
+1. Add the Data Streams SDK to your `Cargo.toml`:
+
+ ```toml
+ [dependencies]
+ data-streams-sdk = { git = "https://github.com/smartcontractkit/data-streams-sdk.git", subdir = "rust/crates/sdk" }
+ data-streams-report = { git = "https://github.com/smartcontractkit/data-streams-sdk.git", subdir = "rust/crates/report" }
+ tokio = { version = "1.4", features = ["full"] }
+ hex = "0.4"
+ ```
+
+### Fetch and decode a report with a single stream
+
+1. Replace the contents of `src/main.rs` with the following code:
+
+ ```rust
+ use data_streams_report::feed_id::ID;
+ use data_streams_report::report::{decode_full_report, v3::ReportDataV3};
+ use data_streams_sdk::client::Client;
+ use data_streams_sdk::config::Config;
+ use std::env;
+ use std::error::Error;
+
+ #[tokio::main]
+ async fn main() -> Result<(), Box> {
+ // Get feed ID from command line arguments
+ let args: Vec = env::args().collect();
+ if args.len() < 2 {
+ eprintln!("Usage: cargo run [FeedID]");
+ std::process::exit(1);
+ }
+ let feed_id_input = &args[1];
+
+ // Get API credentials from environment variables
+ let api_key = env::var("API_KEY").expect("API_KEY must be set");
+ let api_secret = env::var("API_SECRET").expect("API_SECRET must be set");
+
+ // Initialize the configuration
+ let config = Config::new(
+ api_key,
+ api_secret,
+ "https://api.testnet-dataengine.chain.link".to_string(),
+ "wss://api.testnet-dataengine.chain.link/ws".to_string(),
+ )
+ .build()?;
+
+ // Initialize the client
+ let client = Client::new(config)?;
+
+ // Parse the feed ID
+ let feed_id = ID::from_hex_str(feed_id_input)?;
+
+ // Fetch the latest report
+ let response = client.get_latest_report(feed_id).await?;
+ println!("\nRaw report data: {:?}\n", response.report);
+
+ // Decode the report
+ let full_report = hex::decode(&response.report.full_report[2..])?;
+ let (_report_context, report_blob) = decode_full_report(&full_report)?;
+ let report_data = ReportDataV3::decode(&report_blob)?;
+
+ // Print decoded report details
+ println!("\nDecoded Report for Stream ID {}:", feed_id_input);
+ println!("------------------------------------------");
+ println!("Observations Timestamp: {}", response.report.observations_timestamp);
+ println!("Benchmark Price : {}", report_data.benchmark_price);
+ println!("Bid : {}", report_data.bid);
+ println!("Ask : {}", report_data.ask);
+ println!("Valid From Timestamp : {}", response.report.valid_from_timestamp);
+ println!("Expires At : {}", report_data.expires_at);
+ println!("Link Fee : {}", report_data.link_fee);
+ println!("Native Fee : {}", report_data.native_fee);
+ println!("------------------------------------------");
+
+ Ok(())
+ }
+ ```
+
+1. Set up your API credentials as environment variables:
+
+ ```bash
+ export API_KEY=""
+ export API_SECRET=""
+ ```
+
+ Replace `` and `` with your API credentials.
+
+1. For this example, you will read from the ETH/USD crypto stream. This stream ID is . See the [Stream Addresses](/data-streams/crypto-streams) page for a complete list of available crypto assets.
+
+ Build and run your application:
+
+ ```bash
+ cargo run -- 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782
+ ```
+
+ Expect output similar to the following in your terminal:
+
+ ```bash
+ Raw report data: Report { feed_id: 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782, valid_from_timestamp: 1734124400, observations_timestamp: 1734124400, full_report: "0x0006f9b553e393ced311551efd30d1decedb63d76ad41737462e2cdbbdff1578000000000000000000000000000000000000000000000000000000004f56930f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000028001010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000120000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba78200000000000000000000000000000000000000000000000000000000675ca37000000000000000000000000000000000000000000000000000000000675ca3700000000000000000000000000000000000000000000000000000174be1bd8758000000000000000000000000000000000000000000000000000cb326ce8c3ea800000000000000000000000000000000000000000000000000000000675df4f00000000000000000000000000000000000000000000000d3a30bcc15e207c0000000000000000000000000000000000000000000000000d3a1557b5e634060200000000000000000000000000000000000000000000000d3ab99a974ff10f400000000000000000000000000000000000000000000000000000000000000000292bdd75612560e46ed9b0c2437898f81eb0e18b6b902a161b9708e9177175cf3b8ef2b279f230f766fb29306250ee90856516ee349ca42b2d7fb141deb006745000000000000000000000000000000000000000000000000000000000000000221c156e80276827e1bfeb6542ab064dfa958f5be955f516fb62b1c93437472c31cc65fcaba68c9d661701190bc32025a0690af0eefe027ac218fd15c588dd4d5" }
+
+
+ Decoded Report for Stream ID 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782:
+ ------------------------------------------
+ Observations Timestamp: 1734124400
+ Benchmark Price : 3904011708000000000000
+ Bid : 3903888333211164500000
+ Ask : 3904628100124598400000
+ Valid From Timestamp : 1734124400
+ Expires At : 1734210800
+ Link Fee : 3574678975954600
+ Native Fee : 25614677280600
+ ------------------------------------------
+ ```
+
+#### Decoded report details
+
+The decoded report details include:
+
+| Attribute | Value | Description |
+| ------------------------ | -------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `Stream ID` | `0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782` | The unique identifier for the stream. In this example, the stream is for ETH/USD. |
+| `Observations Timestamp` | `1734124400` | The timestamp indicating when the data was captured. |
+| `Benchmark Price` | `3904011708000000000000` | The observed price in the report, with 18 decimals. For readability: `3,904.0117080000000` USD per ETH. |
+| `Bid` | `3903888333211164500000` | The highest price a buyer is willing to pay for an asset, with 18 decimals. For readability: `3,903.8883332111645` USD per ETH. Learn more about the [Bid price](/data-streams/concepts/liquidity-weighted-prices). |
+| `Ask` | `3904628100124598400000` | The lowest price a seller is willing to accept for an asset, with 18 decimals. For readability: `3,904.6281001245984` USD per ETH. Learn more about the [Ask price](/data-streams/concepts/liquidity-weighted-prices). |
+| `Valid From Timestamp` | `1734124400` | The start validity timestamp for the report, indicating when the data becomes relevant. |
+| `Expires At` | `1734210800` | The expiration timestamp of the report, indicating the point at which the data becomes outdated. |
+| `Link Fee` | `3574678975954600` | The fee to pay in LINK tokens for the onchain verification of the report data. With 18 decimals. For readability: `0.003574678975954600` LINK. **Note:** This example fee is not indicative of actual fees. |
+| `Native Fee` | `25614677280600` | The fee to pay in the native blockchain token (e.g., ETH on Ethereum) for the onchain verification of the report data. With 18 decimals. For readability: `0.0000256146772806000` ETH. **Note:** This example fee is not indicative of actual fees. |
+
+#### Payload for onchain verification
+
+In this guide, you log and decode the `full_report` payload to extract the report data. In a
+production environment, you should verify the data to ensure its integrity and authenticity. Refer to the
+[Verify report data onchain](/data-streams/tutorials/streams-direct/streams-direct-onchain-verification) guide.
+
+## Explanation
+
+### Initializing the API client and configuration
+
+The API client is initialized in two steps:
+
+1. [`Config::new`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/crates/sdk/src/config.rs#L131) creates a configuration with your API credentials and endpoints. This function:
+
+ - Validates your API key and secret
+ - Sets up the REST API endpoint for data retrieval
+ - Configures optional settings like TLS verification
+
+2. [`Client::new`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/crates/sdk/src/client.rs#L131) creates the HTTP client with your configuration. This client:
+ - Handles authentication automatically
+ - Manages HTTP connections
+ - Implements retry logic for failed requests
+
+### Fetching reports
+
+The SDK provides several methods to fetch reports through the REST API:
+
+1. Latest report: [`get_latest_report`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/crates/sdk/src/client.rs#L165) retrieves the most recent report for a feed:
+
+ - Takes a feed ID as input
+ - Returns a single report with the latest timestamp
+ - Useful for applications that need the most current data
+
+2. Historical report: [`get_report`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/crates/sdk/src/client.rs#L242) fetches a report at a specific timestamp:
+ - Takes both feed ID and timestamp
+ - Returns the report closest to the requested timestamp
+ - Helpful for historical analysis or verification
+
+Each API request automatically:
+
+- Generates HMAC authentication headers
+- Includes proper timestamps
+- Handles HTTP response status codes
+- Deserializes the JSON response into Rust structures
+
+### Decoding reports
+
+Reports are decoded in three stages:
+
+1. Hex decoding: The `full_report` field comes as a hex string prefixed with "0x":
+
+ ```rust
+ let full_report = hex::decode(&response.report.full_report[2..])?;
+ ```
+
+2. Report separation: [`decode_full_report`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/crates/report/src/report.rs#L77) splits the binary data:
+
+ - Extracts the report context (metadata)
+ - Isolates the report blob (actual data)
+ - Validates the report format
+
+3. Data extraction: [`ReportDataV3::decode`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/crates/report/src/report/v3.rs#L80) parses the report blob into structured data:
+ - Benchmark price (18 decimal places)
+ - Bid and ask prices for [liquidity-weighted pricing](/data-streams/concepts/liquidity-weighted-prices)
+ - Fee information for onchain verification
+ - Timestamp information
+
+### Error handling
+
+The example demonstrates Rust's robust error handling:
+
+1. Type-safe errors:
+
+ - Uses custom error types for different failure scenarios
+ - Implements the `Error` trait for proper error propagation
+ - Provides detailed error messages for debugging
+
+2. Error propagation:
+
+ - Uses the `?` operator for clean error handling
+ - Converts errors between types when needed
+ - Bubbles up errors to the main function
+
+3. Input validation:
+ - Checks command-line arguments
+ - Validates environment variables
+ - Verifies feed ID format
+
+The decoded data can be used for further processing, analysis, or display in your application. For production environments, you must verify the data onchain using the provided `full_report` payload.
diff --git a/src/content/data-streams/tutorials/streams-direct/streams-direct-api-rwa-go.mdx b/src/content/data-streams/tutorials/streams-direct/streams-direct-api-rwa-go.mdx
new file mode 100644
index 00000000000..081c8ec2b03
--- /dev/null
+++ b/src/content/data-streams/tutorials/streams-direct/streams-direct-api-rwa-go.mdx
@@ -0,0 +1,580 @@
+---
+section: dataStreams
+date: Last Modified
+title: "Fetch and decode V4 reports using the Go SDK"
+whatsnext:
+ {
+ "Learn how to stream and decode reports via a WebSocket connection": "/data-streams/tutorials/streams-direct/streams-direct-ws",
+ "Learn how to verify your data onchain": "/data-streams/reference/streams-direct/streams-direct-onchain-verification",
+ "Find the list of available Stream IDs": "/data-streams/crypto-streams",
+ }
+---
+
+import { CopyText, PageTabs } from "@components"
+import DataStreams from "@features/data-streams/common/DataStreams.astro"
+
+
+
+
+
+In this guide, you'll learn how to use Chainlink Data Streams with the _[Streams Direct](/data-streams/streams-direct) implementation_ and the [Data Streams SDK](/data-streams/reference/streams-direct/streams-direct-go-sdk) for Go to fetch and decode [V4 reports](/data-streams/reference/report-schema-v4) for [Real World Assets (RWAs) streams](/data-streams/rwa-streams) from the Data Streams Aggregation Network. You'll set up your Go project, retrieve reports, decode them, and log their attributes.
+
+
+
+## Requirements
+
+- **Git**: Make sure you have Git installed. You can check your current version by running in your terminal and download the latest version from the official [Git website](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) if necessary.
+- **Go Version**: Make sure you have Go version 1.21 or higher. You can check your current version by running `go version` in your terminal and download the latest version from the official [Go website](https://go.dev/) if necessary.
+- **API Credentials**: Access to the Streams Direct implementation requires API credentials. If you haven't already, [contact us](https://chainlinkcommunity.typeform.com/datastreams?typeform-source=docs.chain.link#ref_id=docs) to request mainnet or testnet early access.
+
+## Guide
+
+You'll start with the set up of your Go project. Next, you'll fetch and decode reports for both single and multiple [RWA streams](/data-streams/rwa-streams), and log their attributes to your terminal.
+
+### Set up your Go project
+
+1. Create a new directory for your project and navigate to it:
+
+ ```bash
+ mkdir my-data-streams-project
+ cd my-data-streams-project
+ ```
+
+1. Initialize a new Go module:
+
+ ```bash
+ go mod init my-data-streams-project
+ ```
+
+1. Install the Data Streams SDK:
+
+ ```bash
+ go get github.com/smartcontractkit/data-streams-sdk/go
+ ```
+
+### Fetch and decode a report with a single stream
+
+1. Create a new Go file, `single-stream.go`, in your project directory:
+
+ ```bash
+ touch single-stream.go
+ ```
+
+1. Insert the following code example and save your `single-stream.go` file:
+
+ ```go
+ package main
+
+ import (
+ "context"
+ "fmt"
+ "os"
+ "time"
+
+ streams "github.com/smartcontractkit/data-streams-sdk/go"
+ feed "github.com/smartcontractkit/data-streams-sdk/go/feed"
+ report "github.com/smartcontractkit/data-streams-sdk/go/report"
+ v4 "github.com/smartcontractkit/data-streams-sdk/go/report/v4" // Import the v4 report schema for RWA streams. For Crypto streams, use the v3 schema.
+ )
+
+ func main() {
+ // Validate command-line arguments
+ if len(os.Args) < 2 {
+ fmt.Printf("Usage: go run main.go [FeedID]\nExample: go run main.go 0x000434a5b30cafe7e853832a458ea1591dc2f5fb5e4cf80b9979b8248065a7ea\n")
+ os.Exit(1)
+ }
+ feedIDInput := os.Args[1]
+
+ // Get API credentials from environment variables
+ apiKey := os.Getenv("API_KEY")
+ apiSecret := os.Getenv("API_SECRET")
+ if apiKey == "" || apiSecret == "" {
+ fmt.Printf("API_KEY and API_SECRET environment variables must be set\n")
+ os.Exit(1)
+ }
+
+ // Define the configuration for the SDK client
+ cfg := streams.Config{
+ ApiKey: apiKey,
+ ApiSecret: apiSecret,
+ RestURL: "https://api.testnet-dataengine.chain.link",
+ Logger: streams.LogPrintf,
+ }
+
+ // Initialize the SDK client
+ client, err := streams.New(cfg)
+ if err != nil {
+ cfg.Logger("Failed to create client: %v\n", err)
+ os.Exit(1)
+ }
+
+ // Create context with timeout
+ ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
+ defer cancel()
+
+ // Parse the feed ID
+ var feedID feed.ID
+ if err := feedID.FromString(feedIDInput); err != nil {
+ cfg.Logger("Invalid feed ID format '%s': %v\n", feedIDInput, err)
+ os.Exit(1)
+ }
+
+ // Fetch the latest report
+ reportResponse, err := client.GetLatestReport(ctx, feedID)
+ if err != nil {
+ cfg.Logger("Failed to get latest report: %v\n", err)
+ os.Exit(1)
+ }
+
+ // Log the raw report data
+ cfg.Logger("Raw report data: %+v\n", reportResponse)
+
+ // Decode the report
+ decodedReport, err := report.Decode[v4.Data](reportResponse.FullReport)
+ if err != nil {
+ cfg.Logger("Failed to decode report: %v\n", err)
+ os.Exit(1)
+ }
+
+ // Format and display the decoded report
+ fmt.Printf("\nDecoded Report for Stream ID %s:\n"+
+ "------------------------------------------\n"+
+ "Observations Timestamp: %d\n"+
+ "Benchmark Price : %s\n"+
+ "Valid From Timestamp : %d\n"+
+ "Expires At : %d\n"+
+ "Link Fee : %s\n"+
+ "Native Fee : %s\n"+
+ "Market Status : %d\n"+
+ "------------------------------------------\n",
+ feedIDInput,
+ decodedReport.Data.ObservationsTimestamp,
+ decodedReport.Data.BenchmarkPrice.String(),
+ decodedReport.Data.ValidFromTimestamp,
+ decodedReport.Data.ExpiresAt,
+ decodedReport.Data.LinkFee.String(),
+ decodedReport.Data.NativeFee.String(),
+ decodedReport.Data.MarketStatus,
+ )
+ }
+ ```
+
+1. Download the required dependencies and update the `go.mod` and `go.sum` files:
+
+ ```bash
+ go mod tidy
+ ```
+
+1. Set up the SDK client configuration within `single-stream.go` with your API credentials and the REST endpoint:
+
+ ```go
+ cfg := streams.Config{
+ ApiKey: os.Getenv("API_KEY"),
+ ApiSecret: os.Getenv("API_SECRET"),
+ RestURL: "https://api.testnet-dataengine.chain.link",
+ Logger: streams.LogPrintf,
+ }
+ ```
+
+ - Set your API credentials as environment variables:
+
+ ```bash
+ export API_KEY=""
+ export API_SECRET=""
+ ```
+
+ Replace `` and `` with your API credentials.
+
+ - `RestURL` is the REST endpoint to poll for specific reports. See the [Streams Direct Interface](/data-streams/reference/streams-direct/streams-direct-interface-api#domains) page for more information.
+
+ See the [SDK Reference](/data-streams/reference/streams-direct/streams-direct-go-sdk#config-struct) page for more configuration options.
+
+1. For this example, you will read from the AUD/USD stream. This stream ID is . See the [Data Streams RWA streams](/data-streams/rwa-streams) page for a complete list of available Real World Assets.
+
+ Execute your application:
+
+ ```bash
+ go run single-stream.go 0x000434a5b30cafe7e853832a458ea1591dc2f5fb5e4cf80b9979b8248065a7ea
+ ```
+
+ Expect output similar to the following in your terminal:
+
+ ```bash
+ 2024-12-14T17:50:49-05:00 Raw report data: {"fullReport":"0x0006aee203ef23a892e75b579f8c3f26fd933d9ca45de95c2f8ac470f4ddcd76000000000000000000000000000000000000000000000000000000000b75880c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000026001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000434a5b30cafe7e853832a458ea1591dc2f5fb5e4cf80b9979b8248065a7ea00000000000000000000000000000000000000000000000000000000675e0bc900000000000000000000000000000000000000000000000000000000675e0bc90000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000675f5d4900000000000000000000000000000000000000000000000008d460e8b7e50000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000023f21e9d219ae8e279d13a36b09a439ed71c0d1118561a93987c665fbad13cb6e37bd3763d7ef840b05fda0671b01f26f3c073bef1f3b53fcd9429836ba25eae600000000000000000000000000000000000000000000000000000000000000026bd87b2293422e41ec242088d8feedbe126474b791a85e54450af84e21d017fd59158fbe4adf47dcabe54c11a8ca606659e060839474545eb9b13bf5e7c902df","feedID":"0x000434a5b30cafe7e853832a458ea1591dc2f5fb5e4cf80b9979b8248065a7ea","validFromTimestamp":1734216649,"observationsTimestamp":1734216649}
+
+ 2024-12-14T17:50:49-05:00
+ Decoded Report for Stream ID 0x000434a5b30cafe7e853832a458ea1591dc2f5fb5e4cf80b9979b8248065a7ea:
+ ------------------------------------------
+ Observations Timestamp: 1734216649
+ Benchmark Price : 636240000000000000
+ Valid From Timestamp : 1734216649
+ Expires At : 1734303049
+ Link Fee : 0
+ Native Fee : 0
+ Market Status : 1
+ ------------------------------------------
+ ```
+
+#### Decoded report details
+
+The decoded report details include:
+
+| Attribute | Value | Description |
+| ------------------------ | -------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `Stream ID` | `0x000434a5b30cafe7e853832a458ea1591dc2f5fb5e4cf80b9979b8248065a7ea` | The unique identifier for the stream. In this example, the stream is for AUD/USD. |
+| `Observations Timestamp` | `1734216649` | The timestamp indicating when the data was captured. |
+| `Benchmark Price` | `636240000000000000` | The observed price in the report, with 18 decimals. For readability: `0.63624` USD per AUD. |
+| `Valid From Timestamp` | `1734216649` | The start validity timestamp for the report, indicating when the data becomes relevant. |
+| `Expires At` | `1734303049` | The expiration timestamp of the report, indicating the point at which the data becomes outdated. |
+| `Link Fee` | `0` | The fee to pay in LINK tokens for the onchain verification of the report data. With 18 decimals. **Note:** This example fee is not indicative of actual fees. |
+| `Native Fee` | `0` | The fee to pay in the native blockchain token (e.g., ETH on Ethereum) for the onchain verification of the report data. With 18 decimals. **Note:** This example fee is not indicative of actual fees. |
+| `Market Status` | `1` | The DON's consensus on whether the market is currently open. Possible values: `0` (`Unknown`), `1` (`Closed`), `2` (`Open`). |
+
+#### Payload for onchain verification
+
+In this guide, you log and decode the `fullReport` payload to extract the report data. In a
+production environment, you should verify the data to ensure its integrity and authenticity. Refer to the
+[Verify report data onchain](/data-streams/tutorials/streams-direct/streams-direct-onchain-verification) guide.
+
+### Fetch and decode reports for multiple streams
+
+1. Create a new Go file, `multiple-streams.go`, in your project directory:
+
+ ```bash
+ touch multiple-streams.go
+ ```
+
+1. Insert the following code example in your `multiple-streams.go` file:
+
+ ```go
+ package main
+
+ import (
+ "context"
+ "fmt"
+ "os"
+ "time"
+
+ streams "github.com/smartcontractkit/data-streams-sdk/go"
+ feed "github.com/smartcontractkit/data-streams-sdk/go/feed"
+ report "github.com/smartcontractkit/data-streams-sdk/go/report"
+ v4 "github.com/smartcontractkit/data-streams-sdk/go/report/v4" // Import the v4 report schema for RWA streams
+ )
+
+ func main() {
+ // Validate command-line arguments
+ if len(os.Args) < 3 {
+ fmt.Printf("Usage: go run multiple-streams.go [StreamID1] [StreamID2] ...\n"+
+ "Example: go run multiple-streams.go "+
+ "0x000434a5b30cafe7e853832a458ea1591dc2f5fb5e4cf80b9979b8248065a7ea "+
+ "0x0004b9905d8337c34e00f8dbe31619428bac5c3937e73e6af75c71780f1770ce\n")
+ os.Exit(1)
+ }
+
+ // Get API credentials from environment variables
+ apiKey := os.Getenv("API_KEY")
+ apiSecret := os.Getenv("API_SECRET")
+ if apiKey == "" || apiSecret == "" {
+ fmt.Printf("API_KEY and API_SECRET environment variables must be set\n")
+ os.Exit(1)
+ }
+
+ // Define the configuration for the SDK client
+ cfg := streams.Config{
+ ApiKey: apiKey,
+ ApiSecret: apiSecret,
+ RestURL: "https://api.testnet-dataengine.chain.link",
+ Logger: streams.LogPrintf,
+ }
+
+ // Initialize the SDK client
+ client, err := streams.New(cfg)
+ if err != nil {
+ cfg.Logger("Failed to create client: %v\n", err)
+ os.Exit(1)
+ }
+
+ // Create context with timeout
+ ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
+ defer cancel()
+
+ // Parse Feed IDs
+ var ids []feed.ID
+ for _, arg := range os.Args[1:] {
+ var fid feed.ID
+ if err := fid.FromString(arg); err != nil {
+ cfg.Logger("Invalid feed ID format '%s': %v\n", arg, err)
+ continue
+ }
+ ids = append(ids, fid)
+ }
+
+ if len(ids) == 0 {
+ cfg.Logger("No valid feed IDs provided\n")
+ os.Exit(1)
+ }
+
+ // Fetch reports for all streams
+ timestamp := uint64(time.Now().Unix())
+ reportResponses, err := client.GetReports(ctx, ids, timestamp)
+ if err != nil {
+ cfg.Logger("Failed to get reports: %v\n", err)
+ os.Exit(1)
+ }
+
+ // Process reports
+ for _, reportResponse := range reportResponses {
+ // Log the raw report data
+ cfg.Logger("Raw report data for Stream ID %s: %+v\n",
+ reportResponse.FeedID.String(), reportResponse)
+
+ // Decode the report
+ decodedReport, err := report.Decode[v4.Data](reportResponse.FullReport)
+ if err != nil {
+ cfg.Logger("Failed to decode report for Stream ID %s: %v\n",
+ reportResponse.FeedID.String(), err)
+ continue // Skip to next report if decoding fails
+ }
+
+ // Format and display the decoded report
+ fmt.Printf("\nDecoded Report for Stream ID %s:\n"+
+ "------------------------------------------\n"+
+ "Observations Timestamp: %d\n"+
+ "Benchmark Price : %s\n"+
+ "Valid From Timestamp : %d\n"+
+ "Expires At : %d\n"+
+ "Link Fee : %s\n"+
+ "Native Fee : %s\n"+
+ "Market Status : %d\n"+
+ "------------------------------------------\n",
+ reportResponse.FeedID.String(),
+ decodedReport.Data.ObservationsTimestamp,
+ decodedReport.Data.BenchmarkPrice.String(),
+ decodedReport.Data.ValidFromTimestamp,
+ decodedReport.Data.ExpiresAt,
+ decodedReport.Data.LinkFee.String(),
+ decodedReport.Data.NativeFee.String(),
+ decodedReport.Data.MarketStatus,
+ )
+ }
+ }
+ ```
+
+1. Before running the example, verify that your API credentials are still set in your current terminal session:
+
+ ```bash
+ echo $API_KEY
+ echo $API_SECRET
+ ```
+
+ If the commands above don't show your credentials, set them again:
+
+ ```bash
+ export API_KEY=""
+ export API_SECRET=""
+ ```
+
+1. For this example, you will read from the AUD/USD and EUR/USD RWA streams. Run your application:
+
+ ```bash
+ go run multiple-streams.go 0x000434a5b30cafe7e853832a458ea1591dc2f5fb5e4cf80b9979b8248065a7ea 0x0004b9905d8337c34e00f8dbe31619428bac5c3937e73e6af75c71780f1770ce
+ ```
+
+ Expect to see output similar to the following in your terminal:
+
+ ```bash
+ 2024-12-14T17:53:30-05:00 Raw report data for Stream ID 0x000434a5b30cafe7e853832a458ea1591dc2f5fb5e4cf80b9979b8248065a7ea: {"fullReport":"0x0006aee203ef23a892e75b579f8c3f26fd933d9ca45de95c2f8ac470f4ddcd76000000000000000000000000000000000000000000000000000000000b75a101000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000026000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000434a5b30cafe7e853832a458ea1591dc2f5fb5e4cf80b9979b8248065a7ea00000000000000000000000000000000000000000000000000000000675e0c6900000000000000000000000000000000000000000000000000000000675e0c690000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000675f5de900000000000000000000000000000000000000000000000008d460e8b7e500000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000255d50eabaa1620b13c01d671b4b8478cbbf3c00a66c96652de0a4abd033447d4077c56723b911f683224b08615cb37103422a0c72f10930f2b2cf5d69ffa7a4100000000000000000000000000000000000000000000000000000000000000022139022d94d5ba9a5d7257866ab5ac2a892de57532a6d15f4d3bb4e0616fc89f26fcf652f60f3227466f986db7a494fdb2e71e7921eaedbfa7e6248220770373","feedID":"0x000434a5b30cafe7e853832a458ea1591dc2f5fb5e4cf80b9979b8248065a7ea","validFromTimestamp":1734216809,"observationsTimestamp":1734216809}
+
+
+ Decoded Report for Stream ID 0x000434a5b30cafe7e853832a458ea1591dc2f5fb5e4cf80b9979b8248065a7ea:
+ ------------------------------------------
+ Observations Timestamp: 1734216809
+ Benchmark Price : 636240000000000000
+ Valid From Timestamp : 1734216809
+ Expires At : 1734303209
+ Link Fee : 0
+ Native Fee : 0
+ Market Status : 1
+ ------------------------------------------
+ 2024-12-14T17:53:30-05:00 Raw report data for Stream ID 0x0004b9905d8337c34e00f8dbe31619428bac5c3937e73e6af75c71780f1770ce: {"fullReport":"0x00062f2fdc48a5bb737dad7fac44e3d35f5d0a0c43091fea90011dbcd3ca39ff000000000000000000000000000000000000000000000000000000000d25a501000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000260000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000004b9905d8337c34e00f8dbe31619428bac5c3937e73e6af75c71780f1770ce00000000000000000000000000000000000000000000000000000000675e0c6900000000000000000000000000000000000000000000000000000000675e0c690000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000675f5de90000000000000000000000000000000000000000000000000e933ccf7f5aa00000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002266357ecc8bccb8199db1d62be6b26ff251e51d821abac59095ffa3bd53f2b671ba72e1f0157b7269578f24574d75f21f4e16340e924a39966385a9204c7f5c5000000000000000000000000000000000000000000000000000000000000000258e69e20a244ec3dc6bcb309d08479656b37160e2210dd7278b6be12296456184d3871968c7511af5beec82528e6f8a9caedffd12f93ca65425850a400343299","feedID":"0x0004b9905d8337c34e00f8dbe31619428bac5c3937e73e6af75c71780f1770ce","validFromTimestamp":1734216809,"observationsTimestamp":1734216809}
+
+
+ Decoded Report for Stream ID 0x0004b9905d8337c34e00f8dbe31619428bac5c3937e73e6af75c71780f1770ce:
+ ------------------------------------------
+ Observations Timestamp: 1734216809
+ Benchmark Price : 1050250000000000000
+ Valid From Timestamp : 1734216809
+ Expires At : 1734303209
+ Link Fee : 0
+ Native Fee : 0
+ Market Status : 1
+ ------------------------------------------
+ ```
+
+ Your application has successfully fetched and decoded data for both streams.
+
+#### Payload for onchain verification
+
+In this guide, you log and decode the `fullReport` payloads to extract the report data. In a
+production environment, you should verify the data to ensure its integrity and authenticity. Refer to the
+[Verify report data onchain](/data-streams/tutorials/streams-direct/streams-direct-onchain-verification) guide.
+
+## Explanation
+
+### Initializing the client and configuration
+
+The Data Streams client is initialized in two steps:
+
+1. Configure the client with [`streams.Config`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/go/config.go#L10):
+
+ ```go
+ cfg := streams.Config{
+ ApiKey: os.Getenv("API_KEY"),
+ ApiSecret: os.Getenv("API_SECRET"),
+ RestURL: "https://api.testnet-dataengine.chain.link",
+ Logger: streams.LogPrintf,
+ }
+ ```
+
+ The configuration requires:
+
+ - `ApiKey` and `ApiSecret` for authentication (required)
+ - `RestURL` for the API endpoint (required)
+ - `Logger` for debugging and error tracking (optional, defaults to `streams.LogPrintf`)
+
+2. Create the client with [`streams.New`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/go/client.go#L56):
+ ```go
+ client, err := streams.New(cfg)
+ ```
+ The client handles:
+ - Authentication with HMAC signatures
+ - Connection management and timeouts
+ - Error handling and retries
+
+### Fetching reports
+
+The SDK provides two main methods to fetch reports:
+
+1. Latest report for a single stream with [`GetLatestReport`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/go/client.go#L130):
+
+ ```go
+ reportResponse, err := client.GetLatestReport(ctx, feedID)
+ ```
+
+ - Takes a context and feed ID
+ - Returns a single `ReportResponse` with the most recent data
+ - No timestamp parameter needed
+ - Useful for real-time price monitoring
+
+2. Latest reports for multiple streams with [`GetReports`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/go/client.go#L208):
+
+ ```go
+ reportResponses, err := client.GetReports(ctx, ids, timestamp)
+ ```
+
+ - Takes context, feed IDs array, and Unix timestamp
+ - Returns array of `ReportResponse`, one per feed ID
+ - Timestamp determines the point in time for the reports
+ - Efficient for monitoring multiple assets simultaneously
+
+Each API request automatically:
+
+- Handles authentication with API credentials
+- Manages request timeouts via context
+- Processes responses into structured types
+
+### Decoding reports
+
+Reports are decoded in two steps:
+
+1. Report decoding with [`report.Decode`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/go/report/report.go#L30):
+
+ ```go
+ decodedReport, err := report.Decode[v4.Data](reportResponse.FullReport)
+ ```
+
+ This step:
+
+ - Takes the raw `FullReport` bytes from the response
+ - Uses `v4.Data` schema for RWA streams (use `v3.Data` for Crypto streams)
+ - Validates the format and decodes using Go generics
+ - Returns a structured report with typed data
+
+2. Data access:
+ ```go
+ data := decodedReport.Data
+ price := data.BenchmarkPrice.String() // Convert big number to string
+ validFrom := data.ValidFromTimestamp // Unix timestamp
+ expiresAt := data.ExpiresAt // Unix timestamp
+ marketStatus := data.MarketStatus // Market status (0: Unknown, 1: Closed, 2: Open)
+ ```
+ Provides access to:
+ - Benchmark price (as big number)
+ - Fee information (LINK and native token fees)
+ - Timestamp data (validity period)
+ - Market status information
+ - All numeric values require `.String()` for display
+
+### Error handling
+
+The SDK uses Go's standard error handling patterns with some enhancements:
+
+1. Context management:
+
+ ```go
+ ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
+ defer cancel()
+ ```
+
+ - Sets request timeouts for API calls
+ - `defer cancel()` ensures cleanup of resources
+ - Same context pattern for both single and multiple reports
+
+2. Error checking:
+
+ ```go
+ if err != nil {
+ cfg.Logger("Failed to decode report: %v\n", err)
+ os.Exit(1) // Fatal errors: exit the program
+ // or
+ continue // Non-fatal errors: skip this report
+ }
+ ```
+
+ - Fatal errors (client creation, no valid feeds) use `os.Exit(1)`
+ - Non-fatal errors (single report decode) use `continue`
+ - All errors are logged before handling
+
+3. SDK logging:
+ ```go
+ cfg.Logger("Raw report data: %+v\n", reportResponse)
+ ```
+ - Uses configured logger for SDK operations
+ - `fmt.Printf` for user-facing output
+ - Debug information includes raw report data
+ - Structured error messages with context
+
+The decoded data can be used for further processing or display in your application. For production environments, you must verify the data onchain using the provided `fullReport` payload.
diff --git a/src/content/data-streams/tutorials/streams-direct/streams-direct-api-rwa-rust.mdx b/src/content/data-streams/tutorials/streams-direct/streams-direct-api-rwa-rust.mdx
new file mode 100644
index 00000000000..b190d3d24c0
--- /dev/null
+++ b/src/content/data-streams/tutorials/streams-direct/streams-direct-api-rwa-rust.mdx
@@ -0,0 +1,285 @@
+---
+section: dataStreams
+date: Last Modified
+title: "Fetch and decode V4 reports using the Rust SDK"
+whatsnext:
+ {
+ "Learn how to stream and decode reports via a WebSocket connection": "/data-streams/tutorials/streams-direct/streams-direct-ws-rust",
+ "Learn how to verify your data onchain": "/data-streams/reference/streams-direct/streams-direct-onchain-verification",
+ "Find the list of available Stream IDs": "/data-streams/rwa-streams",
+ }
+---
+
+import { CopyText, PageTabs } from "@components"
+import DataStreams from "@features/data-streams/common/DataStreams.astro"
+
+
+
+
+
+In this guide, you'll learn how to use Chainlink Data Streams with the _[Streams Direct](/data-streams/streams-direct) implementation_ and the [Data Streams SDK](/data-streams/reference/streams-direct/streams-direct-rust-sdk) for Rust to fetch and decode [V4 reports](/data-streams/reference/report-schema-v4) for [Real World Assets (RWAs) streams](/data-streams/rwa-streams) from the Data Streams Aggregation Network. You'll set up your Rust project, retrieve reports, decode them, and log their attributes.
+
+
+
+## Requirements
+
+- **Git**: Make sure you have Git installed. You can check your current version by running in your terminal and download the latest version from the official [Git website](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) if necessary.
+- **Rust**: Make sure you have Rust installed. You can install Rust by following the instructions on the official [Rust website](https://www.rust-lang.org/tools/install).
+- **API Credentials**: Access to the Streams Direct implementation requires API credentials. If you haven't already, [contact us](https://chainlinkcommunity.typeform.com/datastreams?typeform-source=docs.chain.link#ref_id=docs) to request mainnet or testnet early access.
+
+## Guide
+
+You'll start with the set up of your Rust project. Next, you'll fetch and decode reports for RWA streams and log their attributes to your terminal.
+
+### Set up your Rust project
+
+1. Create a new directory for your project and navigate to it:
+
+ ```bash
+ mkdir my-data-streams-project && cd my-data-streams-project
+ ```
+
+1. Initialize a new Rust project:
+
+ ```bash
+ cargo init
+ ```
+
+1. Add the Data Streams SDK to your `Cargo.toml`:
+
+ ```toml
+ [dependencies]
+ data-streams-sdk = { git = "https://github.com/smartcontractkit/data-streams-sdk.git", subdir = "rust/crates/sdk" }
+ data-streams-report = { git = "https://github.com/smartcontractkit/data-streams-sdk.git", subdir = "rust/crates/report" }
+ tokio = { version = "1.4", features = ["full"] }
+ hex = "0.4"
+ ```
+
+### Fetch and decode a report with a single stream
+
+1. Replace the contents of `src/main.rs` with the following code:
+
+ ```rust
+ use data_streams_report::feed_id::ID;
+ use data_streams_report::report::{decode_full_report, v4::ReportDataV4}; // Import the v4 report schema for RWA streams
+ use data_streams_sdk::client::Client;
+ use data_streams_sdk::config::Config;
+ use std::env;
+ use std::error::Error;
+
+ #[tokio::main]
+ async fn main() -> Result<(), Box> {
+ // Get feed ID from command line arguments
+ let args: Vec = env::args().collect();
+ if args.len() < 2 {
+ eprintln!("Usage: cargo run [FeedID]");
+ std::process::exit(1);
+ }
+ let feed_id_input = &args[1];
+
+ // Get API credentials from environment variables
+ let api_key = env::var("API_KEY").expect("API_KEY must be set");
+ let api_secret = env::var("API_SECRET").expect("API_SECRET must be set");
+
+ // Initialize the configuration
+ let config = Config::new(
+ api_key,
+ api_secret,
+ "https://api.testnet-dataengine.chain.link".to_string(),
+ "wss://api.testnet-dataengine.chain.link/ws".to_string(),
+ )
+ .build()?;
+
+ // Initialize the client
+ let client = Client::new(config)?;
+
+ // Parse the feed ID
+ let feed_id = ID::from_hex_str(feed_id_input)?;
+
+ // Fetch the latest report
+ let response = client.get_latest_report(feed_id).await?;
+ println!("\nRaw report data: {:?}\n", response.report);
+
+ // Decode the report
+ let full_report = hex::decode(&response.report.full_report[2..])?;
+ let (_report_context, report_blob) = decode_full_report(&full_report)?;
+ let report_data = ReportDataV4::decode(&report_blob)?;
+
+ // Print decoded report details
+ println!("\nDecoded Report for Stream ID {}:", feed_id_input);
+ println!("------------------------------------------");
+ println!("Observations Timestamp: {}", response.report.observations_timestamp);
+ println!("Benchmark Price : {}", report_data.price);
+ println!("Valid From Timestamp : {}", response.report.valid_from_timestamp);
+ println!("Expires At : {}", report_data.expires_at);
+ println!("Link Fee : {}", report_data.link_fee);
+ println!("Native Fee : {}", report_data.native_fee);
+ println!("Market Status : {}", report_data.market_status);
+ println!("------------------------------------------");
+
+ Ok(())
+ }
+ ```
+
+1. Set up your API credentials as environment variables:
+
+ ```bash
+ export API_KEY=""
+ export API_SECRET=""
+ ```
+
+ Replace `` and `` with your API credentials.
+
+1. For this example, you will read from the AUD/USD stream. This stream ID is . See the [Data Streams RWA streams](/data-streams/rwa-streams) page for a complete list of available Real World Assets.
+
+ Build and run your application:
+
+ ```bash
+ cargo run -- 0x000434a5b30cafe7e853832a458ea1591dc2f5fb5e4cf80b9979b8248065a7ea
+ ```
+
+ Expect output similar to the following in your terminal:
+
+ ```bash
+ Raw report data: Report { feed_id: 0x000434a5b30cafe7e853832a458ea1591dc2f5fb5e4cf80b9979b8248065a7ea, valid_from_timestamp: 1734125487, observations_timestamp: 1734125487, full_report: "0x0006aee203ef23a892e75b579f8c3f26fd933d9ca45de95c2f8ac470f4ddcd76000000000000000000000000000000000000000000000000000000000b3df40a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000434a5b30cafe7e853832a458ea1591dc2f5fb5e4cf80b9979b8248065a7ea00000000000000000000000000000000000000000000000000000000675ca7af00000000000000000000000000000000000000000000000000000000675ca7af0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000675df92f00000000000000000000000000000000000000000000000008d2f51c75fc000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002a98627fc63e8af57652d69149a23df6fe4d1bccdfcd013a4a9c0faafb4ab3830bdfb30e2d6c6d3f894b5ed7b4761f9236431548efa15f100fd5a61804cef21c0000000000000000000000000000000000000000000000000000000000000000266dc0c7d18ccc26c566df4820fd68cca5a076215d982c74abf7ae089bc24d3520716cfefdd127f522a2f98f90227926ed786479977d99ac9f91d5c99120e3cb3" }
+
+
+ Decoded Report for Stream ID 0x000434a5b30cafe7e853832a458ea1591dc2f5fb5e4cf80b9979b8248065a7ea:
+ ------------------------------------------
+ Observations Timestamp: 1734125487
+ Benchmark Price : 635840000000000000
+ Valid From Timestamp : 1734125487
+ Expires At : 1734211887
+ Link Fee : 0
+ Native Fee : 0
+ Market Status : 2
+ ------------------------------------------
+ ```
+
+#### Decoded report details
+
+The decoded report details include:
+
+| Attribute | Value | Description |
+| ------------------------ | -------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `Stream ID` | `0x000434a5b30cafe7e853832a458ea1591dc2f5fb5e4cf80b9979b8248065a7ea` | The unique identifier for the stream. In this example, the stream is for AUD/USD. |
+| `Observations Timestamp` | `1734125487` | The timestamp indicating when the data was captured. |
+| `Benchmark Price` | `635840000000000000` | The observed price in the report, with 18 decimals. For readability: `0.63584` USD per AUD. |
+| `Valid From Timestamp` | `1734125487` | The start validity timestamp for the report, indicating when the data becomes relevant. |
+| `Expires At` | `1734211887` | The expiration timestamp of the report, indicating the point at which the data becomes outdated. |
+| `Link Fee` | `0` | The fee to pay in LINK tokens for the onchain verification of the report data. With 18 decimals. **Note:** This example fee is not indicative of actual fees. |
+| `Native Fee` | `0` | The fee to pay in the native blockchain token (e.g., ETH on Ethereum) for the onchain verification of the report data. With 18 decimals. **Note:** This example fee is not indicative of actual fees. |
+| `Market Status` | `2` | The DON's consensus on whether the market is currently open. Possible values: `0` (`Unknown`), `1` (`Closed`), `2` (`Open`). |
+
+#### Payload for onchain verification
+
+In this guide, you log and decode the `full_report` payload to extract the report data. In a
+production environment, you should verify the data to ensure its integrity and authenticity. Refer to the
+[Verify report data onchain](/data-streams/tutorials/streams-direct/streams-direct-onchain-verification) guide.
+
+## Explanation
+
+### Initializing the API client and configuration
+
+The API client is initialized in two steps:
+
+1. [`Config::new`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/crates/sdk/src/config.rs#L131) creates a configuration with your API credentials and endpoints. This function:
+
+ - Validates your API key and secret
+ - Sets up the REST API endpoint for data retrieval
+ - Configures optional settings like TLS verification
+
+2. [`Client::new`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/crates/sdk/src/client.rs#L131) creates the HTTP client with your configuration. This client:
+ - Handles authentication automatically
+ - Manages HTTP connections efficiently
+ - Implements retry logic for failed requests
+
+### Fetching reports
+
+The SDK provides several methods to fetch reports through the REST API:
+
+1. Latest report: [`get_latest_report`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/crates/sdk/src/client.rs#L165) retrieves the most recent report for a feed:
+
+ - Takes a feed ID as input
+ - Returns a single report with the latest timestamp
+ - Useful for applications that need the most current data
+
+2. Historical report: [`get_report`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/crates/sdk/src/client.rs#L242) fetches a report at a specific timestamp:
+ - Takes both feed ID and timestamp
+ - Returns the report closest to the requested timestamp
+ - Helpful for historical analysis or verification
+
+Each API request automatically:
+
+- Generates HMAC authentication headers
+- Includes proper timestamps
+- Handles HTTP response status codes
+- Deserializes the JSON response into Rust structures
+
+### Decoding reports
+
+Reports are decoded in three stages:
+
+1. Hex decoding: The `full_report` field comes as a hex string prefixed with "0x":
+
+ ```rust
+ let full_report = hex::decode(&response.report.full_report[2..])?;
+ ```
+
+2. Report separation: [`decode_full_report`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/crates/report/src/report.rs#L77) splits the binary data:
+
+ - Extracts the report context (metadata)
+ - Isolates the report blob (actual data)
+ - Validates the report format
+
+3. Data extraction: [`ReportDataV4::decode`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/crates/report/src/report/v4.rs#L57) parses the report blob into structured data:
+ - Price (18 decimal places)
+ - Market status (Open, Closed, or Unknown)
+ - Fee information for onchain verification
+ - Timestamp information
+
+### Error handling
+
+The example demonstrates Rust's robust error handling:
+
+1. Type-safe errors:
+
+ - Uses custom error types for different failure scenarios
+ - Implements the `Error` trait for proper error propagation
+ - Provides detailed error messages for debugging
+
+2. Error propagation:
+
+ - Uses the `?` operator for clean error handling
+ - Converts errors between types when needed
+ - Bubbles up errors to the main function
+
+3. Input validation:
+ - Checks command-line arguments
+ - Validates environment variables
+ - Verifies feed ID format
+
+The decoded data can be used for further processing, analysis, or display in your application. For production environments, you must verify the data onchain using the provided `full_report` payload.
diff --git a/src/content/data-streams/tutorials/streams-direct/streams-direct-api-rwa.mdx b/src/content/data-streams/tutorials/streams-direct/streams-direct-api-rwa.mdx
deleted file mode 100644
index b0a1f3c1b6f..00000000000
--- a/src/content/data-streams/tutorials/streams-direct/streams-direct-api-rwa.mdx
+++ /dev/null
@@ -1,417 +0,0 @@
----
-section: dataStreams
-date: Last Modified
-title: "Fetch and decode reports using the SDK (RWA Streams)"
-whatsnext:
- {
- "Learn how to stream and decode reports via a WebSocket connection": "/data-streams/tutorials/streams-direct/streams-direct-ws",
- "Learn how to verify your data onchain": "/data-streams/reference/streams-direct/streams-direct-onchain-verification",
- "Find the list of available Stream IDs": "/data-streams/crypto-streams",
- }
----
-
-import { CopyText, PageTabs } from "@components"
-import DataStreams from "@features/data-streams/common/DataStreams.astro"
-
-
-
-
-
-In this guide, you'll learn how to use Chainlink Data Streams with the _[Streams Direct](/data-streams#streams-direct-using-data-streams-with-your-own-bot) implementation_ and the [Data Streams SDK](/data-streams/reference/streams-direct/streams-direct-go-sdk) for Go to fetch and decode [V4 reports](/data-streams/reference/report-schema-v4) for [Real World Assets (RWAs) streams](/data-streams/rwa-streams) from the Data Streams Aggregation Network. You'll set up your Go project, retrieve reports, decode them, and log their attributes.
-
-
-
-## Requirements
-
-- **Git**: Make sure you have Git installed. You can check your current version by running in your terminal and download the latest version from the official [Git website](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) if necessary.
-- **Go Version**: Make sure you have Go version 1.21 or higher. You can check your current version by running `go version` in your terminal and download the latest version from the official [Go website](https://go.dev/) if necessary.
-- **API Credentials**: Access to the Streams Direct implementation requires API credentials. If you haven't already, [contact us](https://chainlinkcommunity.typeform.com/datastreams?typeform-source=docs.chain.link#ref_id=docs) to request mainnet or testnet early access.
-
-## Guide
-
-You'll start with the set up of your Go project. Next, you'll fetch and decode reports for both single and multiple [RWA streams](/data-streams/rwa-streams), and log their attributes to your terminal.
-
-### Set up your Go project
-
-1. Create a new directory for your project and navigate to it:
-
- ```bash
- mkdir my-data-streams-project
- cd my-data-streams-project
- ```
-
-1. Initialize a new Go module:
-
- ```bash
- go mod init my-data-streams-project
- ```
-
-1. Install the Data Streams SDK:
-
- ```bash
- go get github.com/smartcontractkit/data-streams-sdk/go
- ```
-
-### Fetch and decode a report with a single stream
-
-1. Create a new Go file, `single-stream.go`, in your project directory:
-
- ```bash
- touch single-stream.go
- ```
-
-1. Insert the following code example and save your `single-stream.go` file:
-
- ```go
- package main
-
- import (
- "context"
- "fmt"
- "os"
- "time"
-
- streams "github.com/smartcontractkit/data-streams-sdk/go"
- feed "github.com/smartcontractkit/data-streams-sdk/go/feed"
- report "github.com/smartcontractkit/data-streams-sdk/go/report"
- v4 "github.com/smartcontractkit/data-streams-sdk/go/report/v4" // Import the v4 report schema for RWA streams. For Crypto streams, use the v3 schema.
- )
-
- func main() {
- if len(os.Args) < 2 {
- fmt.Printf("Usage: go run main.go [FeedID]\n")
- os.Exit(1)
- }
- feedIDInput := os.Args[1]
-
- // Define the configuration for the SDK client.
- cfg := streams.Config{
- ApiKey: os.Getenv("API_KEY"),
- ApiSecret: os.Getenv("API_SECRET"),
- RestURL: "https://api.testnet-dataengine.chain.link",
- Logger: streams.LogPrintf,
- }
-
- // Initialize the SDK client.
- client, err := streams.New(cfg)
- if err != nil {
- cfg.Logger("Failed to create client: %v\n", err)
- os.Exit(1)
- }
-
- // Create context for timeout.
- ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
- defer cancel()
-
- // Define the FeedID from user input.
- var FeedID feed.ID
- if err := FeedID.FromString(feedIDInput); err != nil {
- cfg.Logger("Failed to parse stream ID: %v\n", err)
- os.Exit(1)
- }
-
- // Fetch the latest report for the given FeedID.
- reportResponse, err := client.GetLatestReport(ctx, FeedID)
- if err != nil {
- cfg.Logger("Failed to get latest report: %v\n", err)
- os.Exit(1)
- }
-
- // Log the contents of the report before decoding
- cfg.Logger("Raw report data: %+v\n", reportResponse)
-
- // Decode the report.
- decodedReport, err := report.Decode[v4.Data](reportResponse.FullReport)
- if err != nil {
- cfg.Logger("Failed to decode report: %v\n", err)
- os.Exit(1)
- }
-
- // Log the decoded report
- cfg.Logger("\nDecoded Report for Stream ID %s:\n------------------------------------------\n"+
- "Observations Timestamp: %d\n"+
- "Benchmark Price : %s\n"+
- "Valid From Timestamp : %d\n"+
- "Expires At : %d\n"+
- "Link Fee : %s\n"+
- "Native Fee : %s\n"+
- "Market Status : %d\n"+
- "------------------------------------------\n",
- feedIDInput,
- decodedReport.Data.ObservationsTimestamp,
- decodedReport.Data.BenchmarkPrice.String(),
- decodedReport.Data.ValidFromTimestamp,
- decodedReport.Data.ExpiresAt,
- decodedReport.Data.LinkFee.String(),
- decodedReport.Data.NativeFee.String(),
- decodedReport.Data.MarketStatus,
- )
- }
- ```
-
-1. Download the required dependencies and update the `go.mod` and `go.sum` files:
-
- ```bash
- go mod tidy
- ```
-
-1. Set up the SDK client configuration within `single-stream.go` with your API credentials and the REST endpoint:
-
- ```go
- cfg := streams.Config{
- ApiKey: os.Getenv("API_KEY"),
- ApiSecret: os.Getenv("API_SECRET"),
- RestURL: "https://api.testnet-dataengine.chain.link",
- Logger: streams.LogPrintf,
- }
- ```
-
- - Set your API credentials as environment variables:
-
- ```bash
- export API_KEY=""
- export API_SECRET=""
- ```
-
- Replace `` and `` with your API credentials.
-
- - `RestURL` is the REST endpoint to poll for specific reports. See the [Streams Direct Interface](/data-streams/reference/streams-direct/streams-direct-interface-api#domains) page for more information.
-
- See the [SDK Reference](/data-streams/reference/streams-direct/streams-direct-go-sdk#config-struct) page for more configuration options.
-
-1. For this example, you will read from the AUD/USD stream. This stream ID is . See the [Data Streams RWA streams](/data-streams/rwa-streams) page for a complete list of available Real World Assets.
-
- Execute your application:
-
- ```bash
- go run single-stream.go 0x000434a5b30cafe7e853832a458ea1591dc2f5fb5e4cf80b9979b8248065a7ea
- ```
-
- Expect output similar to the following in your terminal:
-
- ```bash
- 2024-10-24T12:29:17-05:00 Raw report data: {"fullReport":"0x0006aee203ef23a892e75b579f8c3f26fd933d9ca45de95c2f8ac470f4ddcd7600000000000000000000000000000000000000000000000000000000015d0313000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000026001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000434a5b30cafe7e853832a458ea1591dc2f5fb5e4cf80b9979b8248065a7ea00000000000000000000000000000000000000000000000000000000671a83ec00000000000000000000000000000000000000000000000000000000671a83ec0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000671bd56c0000000000000000000000000000000000000000000000000937d6369661b00000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002b0b4627e06e3f597f0ff27c8f16ef94ac1ff6d3668899e68383571508e579ab5fb266fe087a8a45b948627b214440f7c8cc5a45f5b94b69d351af4c1e22ed319000000000000000000000000000000000000000000000000000000000000000278f7b0eded2afe5e17553776cf8ab37899a5fc39858e5ad7a0b537c30be28ca51e05bbd08d4ff766d76b7a5a64b9437947ecbe68a3cb7d7b3fe3f151ea56a248","feedID":"0x000434a5b30cafe7e853832a458ea1591dc2f5fb5e4cf80b9979b8248065a7ea","validFromTimestamp":1729790956,"observationsTimestamp":1729790956}
-
- 2024-10-24T12:29:17-05:00
- Decoded Report for Stream ID 0x000434a5b30cafe7e853832a458ea1591dc2f5fb5e4cf80b9979b8248065a7ea:
- ------------------------------------------
- Observations Timestamp: 1729790956
- Benchmark Price : 664235000000000000
- Valid From Timestamp : 1729790956
- Expires At : 1729877356
- Link Fee : 0
- Native Fee : 0
- Market Status : 2
- ------------------------------------------
- ```
-
-#### Decoded report details
-
-The decoded report details include:
-
-| Attribute | Value | Description |
-| ------------------------ | -------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `Stream ID` | `0x000434a5b30cafe7e853832a458ea1591dc2f5fb5e4cf80b9979b8248065a7ea` | The unique identifier for the stream. In this example, the stream is for AUD/USD. |
-| `Observations Timestamp` | `1729790956` | The timestamp indicating when the data was captured. |
-| `Benchmark Price` | `664235000000000000` | The observed price in the report, with 18 decimals. For readability: `0.664235` USD per AUD. |
-| `Valid From Timestamp` | `1729790956` | The start validity timestamp for the report, indicating when the data becomes relevant. |
-| `Expires At` | `1729877356` | The expiration timestamp of the report, indicating the point at which the data becomes outdated. |
-| `Link Fee` | `0` | The fee to pay in LINK tokens for the onchain verification of the report data. With 18 decimals. **Note:** This example fee is not indicative of actual fees. |
-| `Native Fee` | `0` | The fee to pay in the native blockchain token (e.g., ETH on Ethereum) for the onchain verification of the report data. With 18 decimals. **Note:** This example fee is not indicative of actual fees. |
-| `Market Status` | `2` | The DON's consensus on whether the market is currently open. Possible values: `0` (`Unknown`), `1` (`Closed`), `2` (`Open`). |
-
-#### Payload for onchain verification
-
-In this guide, you log and decode the `fullReport` payload to extract the report data. In a
-production environment, you should verify the data onchain to ensure its integrity and authenticity. Refer to the
-[Verify report data onchain](/data-streams/tutorials/streams-direct/streams-direct-onchain-verification) guide.
-
-### Fetch and decode reports for multiple streams
-
-1. Create a new Go file, `multiple-streams.go`, in your project directory:
-
- ```bash
- touch multiple-streams.go
- ```
-
-1. Insert the following code example in your `multiple-streams.go` file:
-
- ```go
- package main
-
- import (
- "context"
- "fmt"
- "os"
- "time"
-
- streams "github.com/smartcontractkit/data-streams-sdk/go"
- feed "github.com/smartcontractkit/data-streams-sdk/go/feed"
- report "github.com/smartcontractkit/data-streams-sdk/go/report"
- v4 "github.com/smartcontractkit/data-streams-sdk/go/report/v4" // Import the v4 report schema for RWA streams. For Crypto streams, use the v3 schema.
- )
-
- func main() {
- if len(os.Args) < 3 { // Ensure there are at least two stream IDs provided
- fmt.Printf("Usage: go run multiple-streams.go [StreamID1] [StreamID2] ...\n")
- os.Exit(1)
- }
-
- // Define the configuration for the SDK client.
- cfg := streams.Config{
- ApiKey: os.Getenv("API_KEY"),
- ApiSecret: os.Getenv("API_SECRET"),
- RestURL: "https://api.testnet-dataengine.chain.link",
- Logger: streams.LogPrintf,
- }
-
- // Initialize the SDK client
- client, err := streams.New(cfg)
- if err != nil {
- cfg.Logger("Failed to create client: %v\n", err)
- os.Exit(1)
- }
-
- // Create context for timeout
- ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
- defer cancel()
-
- // Parse Feed IDs from command line arguments
- var ids []feed.ID
- for _, arg := range os.Args[1:] {
- var fid feed.ID
- if err := fid.FromString(arg); err != nil {
- cfg.Logger("Failed to parse stream ID %s: %v\n", arg, err)
- os.Exit(1)
- }
- ids = append(ids, fid)
- }
-
- // Fetch reports for the given feed IDs
- reportResponses, err := client.GetReports(ctx, ids, uint64(time.Now().Unix())) // Using current time as an example timestamp
- if err != nil {
- cfg.Logger("Failed to get reports: %v\n", err)
- os.Exit(1)
- }
-
- for _, reportResponse := range reportResponses {
- // Log the contents of the report before decoding
- cfg.Logger("Raw report data for Stream ID %s: %+v\n", reportResponse.FeedID.String(), reportResponse)
-
- // Decode the report
- decodedReport, err := report.Decode[v4.Data](reportResponse.FullReport)
- if err != nil {
- cfg.Logger("Failed to decode report for Stream ID %s: %v\n", reportResponse.FeedID, err)
- continue // Skip to next report if decoding fails
- }
-
- // Log the decoded report
- cfg.Logger("\nDecoded Report for Stream ID %s:\n------------------------------------------\n"+
- "Observations Timestamp: %d\n"+
- "Benchmark Price : %s\n"+
- "Valid From Timestamp : %d\n"+
- "Expires At : %d\n"+
- "Link Fee : %s\n"+
- "Native Fee : %s\n"+
- "Market Status : %d\n"+
- "------------------------------------------\n",
- reportResponse.FeedID.String(),
- decodedReport.Data.ObservationsTimestamp,
- decodedReport.Data.BenchmarkPrice.String(),
- decodedReport.Data.ValidFromTimestamp,
- decodedReport.Data.ExpiresAt,
- decodedReport.Data.LinkFee.String(),
- decodedReport.Data.NativeFee.String(),
- decodedReport.Data.MarketStatus,
- )
- }
- }
- ```
-
-1. Set your API credentials as environment variables if you haven't already:
-
- ```bash
- export API_KEY=""
- export API_SECRET=""
- ```
-
- Replace `` and `` with your API credentials.
-
-1. For this example, you will read from the AUD/USD and the USD/JPY RWA streams. Run your application:
-
- ```bash
- go run multiple-streams.go 0x000434a5b30cafe7e853832a458ea1591dc2f5fb5e4cf80b9979b8248065a7ea 0x00046ab03823e37bebe5f228d923ce27110e554b12d7fd476a4ae652f5bf7788
- ```
-
- Expect to see the output below in your terminal:
-
- ```bash
- 2024-10-24T12:38:46-05:00 Raw report data for Stream ID 0x000434a5b30cafe7e853832a458ea1591dc2f5fb5e4cf80b9979b8248065a7ea: {"fullReport":"0x0006aee203ef23a892e75b579f8c3f26fd933d9ca45de95c2f8ac470f4ddcd7600000000000000000000000000000000000000000000000000000000015d5a0d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000026001010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000434a5b30cafe7e853832a458ea1591dc2f5fb5e4cf80b9979b8248065a7ea00000000000000000000000000000000000000000000000000000000671a862600000000000000000000000000000000000000000000000000000000671a86260000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000671bd7a6000000000000000000000000000000000000000000000000093850feb96d200000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002b66c644a48c683c603863006dc6ab3a46fb9b7d6a40436b5c7f74f9a446034d6b6968bff3195c5c68105246ea7f50d9dd852f69f67a98b9fc685ad302e4426bf00000000000000000000000000000000000000000000000000000000000000027eca79b9559bae4b904ea7c40055d7f4f4d5c11f07cd0dfca0672c489e8801952063471d66c984d240edd3f3b8e43f7d9ed3eaa7ddbe1a51c6bcd52cfc91f9d4","feedID":"0x000434a5b30cafe7e853832a458ea1591dc2f5fb5e4cf80b9979b8248065a7ea","validFromTimestamp":1729791526,"observationsTimestamp":1729791526}
-
- 2024-10-24T12:38:46-05:00
- Decoded Report for Stream ID 0x000434a5b30cafe7e853832a458ea1591dc2f5fb5e4cf80b9979b8248065a7ea:
- ------------------------------------------
- Observations Timestamp: 1729791526
- Benchmark Price : 664370000000000000
- Valid From Timestamp : 1729791526
- Expires At : 1729877926
- Link Fee : 0
- Native Fee : 0
- Market Status : 2
- ------------------------------------------
-
- 2024-10-24T12:38:46-05:00 Raw report data for Stream ID 0x00046ab03823e37bebe5f228d923ce27110e554b12d7fd476a4ae652f5bf7788: {"fullReport":"0x000692e617d2f6b01349da9090017ba25738b084f88878fa8ac1974a72f8b774000000000000000000000000000000000000000000000000000000000156e219000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000046ab03823e37bebe5f228d923ce27110e554b12d7fd476a4ae652f5bf778800000000000000000000000000000000000000000000000000000000671a862600000000000000000000000000000000000000000000000000000000671a86260000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000671bd7a6000000000000000000000000000000000000000000000008376a2776afa18000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000029d9c488b9746dee5dd698b0cf82a3c02a4efa782348a996c62593457c7a3287e5cd34a79e9a1e31eb38e0b0d0a5c2271d725c243694171b1f29c4e45fc2f2545000000000000000000000000000000000000000000000000000000000000000252f67cb0f8fac3e67ce1919b5837f90681c4f48106548071906955addcbf57297736be3904a7eac1ef188ade6f9d65f5408e52786f5d06c8cf02e9b682b5586c","feedID":"0x00046ab03823e37bebe5f228d923ce27110e554b12d7fd476a4ae652f5bf7788","validFromTimestamp":1729791526,"observationsTimestamp":1729791526}
-
- 2024-10-24T12:38:46-05:00
- Decoded Report for Stream ID 0x00046ab03823e37bebe5f228d923ce27110e554b12d7fd476a4ae652f5bf7788:
- ------------------------------------------
- Observations Timestamp: 1729791526
- Benchmark Price : 151567000000000000000
- Valid From Timestamp : 1729791526
- Expires At : 1729877926
- Link Fee : 0
- Native Fee : 0
- Market Status : 2
- ------------------------------------------
- ```
-
- Your application has successfully fetched and decoded data for both streams.
-
-#### Payload for onchain verification
-
-In this guide, you log and decode the `fullReport` payloads to extract the report data. In a
-production environment, you should verify the data onchain to ensure its integrity and authenticity. Refer to the
-[Verify report data onchain](/data-streams/tutorials/streams-direct/streams-direct-onchain-verification) guide.
-
-## Explanation
-
-### Fetching reports
-
-Your application uses the [Data Streams SDK](/data-streams/reference/streams-direct/streams-direct-go-sdk) to fetch reports from the Data Streams Aggregation Network. Different functions from the SDK are invoked based on whether a single stream or multiple streams are queried:
-
-- Single Stream: The application calls the [`GetLatestReport`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/go/client.go#L121) function from the SDK's `streams` package to fetch a single stream report. This function sends an API request to retrieve the latest available report for a specified stream ID. The response includes the report's data in a structured format suitable for further processing and analysis.
-
-- Multiple Streams: The [`GetReports`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/go/client.go#L199) function is used for multiple streams. This function allows you to fetch reports for multiple stream IDs simultaneously, specifying a timestamp to retrieve reports valid at a particular point in time.
-
-The responses include a `fullReport` blob containing the encoded report's context and observations.
-
-### Decoding reports
-
-After retrieving the report data, the application decodes it using the [`Decode`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/go/report/report.go#L30) function available in the `report` package of the SDK. This function is designed to handle different data formats by specifying the version of the data structure as a type parameter (e.g., `v4.Data` for Real World Asset streams).
-
-The `Decode` function unpacks the encoded report blob into a usable data structure (`Report[v4.Data]` for [RWA streams](/data-streams/rwa-streams)). It extracts information such as observation timestamps, benchmark prices, and the market status from the report data.
-
-### Handling the decoded data
-
-The application logs the report data to the terminal. However, this data can be used for further processing, analysis, or display in your own application.
diff --git a/src/content/data-streams/tutorials/streams-direct/streams-direct-api.mdx b/src/content/data-streams/tutorials/streams-direct/streams-direct-api.mdx
deleted file mode 100644
index 2a2705dc1a2..00000000000
--- a/src/content/data-streams/tutorials/streams-direct/streams-direct-api.mdx
+++ /dev/null
@@ -1,424 +0,0 @@
----
-section: dataStreams
-date: Last Modified
-title: "Fetch and decode reports using the SDK (Crypto Streams)"
-whatsnext:
- {
- "Learn how to stream and decode reports via a WebSocket connection": "/data-streams/tutorials/streams-direct/streams-direct-ws",
- "Learn how to verify your data onchain": "/data-streams/reference/streams-direct/streams-direct-onchain-verification",
- "Find the list of available Stream IDs": "/data-streams/crypto-streams",
- }
----
-
-import { CopyText, PageTabs } from "@components"
-import DataStreams from "@features/data-streams/common/DataStreams.astro"
-
-
-
-
-
-In this guide, you'll learn how to use Chainlink Data Streams with the _[Streams Direct](/data-streams#streams-direct-using-data-streams-with-your-own-bot) implementation_ and the [Data Streams SDK](/data-streams/reference/streams-direct/streams-direct-go-sdk) for Go to fetch and decode [V3 reports](/data-streams/reference/report-schema) for [Crypto streams](/data-streams/crypto-streams) from the Data Streams Aggregation Network. You'll set up your Go project, retrieve reports, decode them, and log their attributes.
-
-
-
-## Requirements
-
-- **Git**: Make sure you have Git installed. You can check your current version by running in your terminal and download the latest version from the official [Git website](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) if necessary.
-- **Go Version**: Make sure you have Go version 1.21 or higher. You can check your current version by running `go version` in your terminal and download the latest version from the official [Go website](https://go.dev/) if necessary.
-- **API Credentials**: Access to the Streams Direct implementation requires API credentials. If you haven't already, [contact us](https://chainlinkcommunity.typeform.com/datastreams?typeform-source=docs.chain.link#ref_id=docs) to request mainnet or testnet early access.
-
-## Guide
-
-You'll start with the set up of your Go project. Next, you'll fetch and decode reports for both single and multiple [crypto streams](/data-streams/crypto-streams), and log their attributes to your terminal.
-
-### Set up your Go project
-
-1. Create a new directory for your project and navigate to it:
-
- ```bash
- mkdir my-data-streams-project
- cd my-data-streams-project
- ```
-
-1. Initialize a new Go module:
-
- ```bash
- go mod init my-data-streams-project
- ```
-
-1. Install the Data Streams SDK:
-
- ```bash
- go get github.com/smartcontractkit/data-streams-sdk/go
- ```
-
-### Fetch and decode a report with a single stream
-
-1. Create a new Go file, `single-stream.go`, in your project directory:
-
- ```bash
- touch single-stream.go
- ```
-
-1. Insert the following code example and save your `single-stream.go` file:
-
- ```go
- package main
-
- import (
- "context"
- "fmt"
- "os"
- "time"
-
- streams "github.com/smartcontractkit/data-streams-sdk/go"
- feed "github.com/smartcontractkit/data-streams-sdk/go/feed"
- report "github.com/smartcontractkit/data-streams-sdk/go/report"
- v3 "github.com/smartcontractkit/data-streams-sdk/go/report/v3" // Import the v3 report schema for Crypto streams. For RWA streams, use the v4 schema.
- )
-
- func main() {
- if len(os.Args) < 2 {
- fmt.Printf("Usage: go run main.go [FeedID]\n")
- os.Exit(1)
- }
- feedIDInput := os.Args[1]
-
- // Define the configuration for the SDK client.
- cfg := streams.Config{
- ApiKey: os.Getenv("API_KEY"),
- ApiSecret: os.Getenv("API_SECRET"),
- RestURL: "https://api.testnet-dataengine.chain.link",
- Logger: streams.LogPrintf,
- }
-
- // Initialize the SDK client.
- client, err := streams.New(cfg)
- if err != nil {
- cfg.Logger("Failed to create client: %v\n", err)
- os.Exit(1)
- }
-
- // Create context for timeout.
- ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
- defer cancel()
-
- // Define the feedID from user input.
- var FeedID feed.ID
- if err := FeedID.FromString(feedIDInput); err != nil {
- cfg.Logger("Failed to parse stream ID: %v\n", err)
- os.Exit(1)
- }
-
- // Fetch the latest report for the given FeedID.
- reportResponse, err := client.GetLatestReport(ctx, FeedID)
- if err != nil {
- cfg.Logger("Failed to get latest report: %v\n", err)
- os.Exit(1)
- }
-
- // Log the contents of the report before decoding
- cfg.Logger("Raw report data: %+v\n", reportResponse)
-
- // Decode the report.
- decodedReport, err := report.Decode[v3.Data](reportResponse.FullReport)
- if err != nil {
- cfg.Logger("Failed to decode report: %v\n", err)
- os.Exit(1)
- }
-
- // Log the decoded report
- cfg.Logger("\nDecoded Report for Stream ID %s:\n------------------------------------------\n"+
- "Observations Timestamp: %d\n"+
- "Benchmark Price : %s\n"+
- "Bid : %s\n"+
- "Ask : %s\n"+
- "Valid From Timestamp : %d\n"+
- "Expires At : %d\n"+
- "Link Fee : %s\n"+
- "Native Fee : %s\n"+
- "------------------------------------------\n",
- feedIDInput,
- decodedReport.Data.ObservationsTimestamp,
- decodedReport.Data.BenchmarkPrice.String(),
- decodedReport.Data.Bid.String(),
- decodedReport.Data.Ask.String(),
- decodedReport.Data.ValidFromTimestamp,
- decodedReport.Data.ExpiresAt,
- decodedReport.Data.LinkFee.String(),
- decodedReport.Data.NativeFee.String(),
- )
- }
- ```
-
-1. Download the required dependencies and update the `go.mod` and `go.sum` files:
-
- ```bash
- go mod tidy
- ```
-
-1. Set up the SDK client configuration within `single-stream.go` with your API credentials and the REST endpoint:
-
- ```go
- cfg := streams.Config{
- ApiKey: os.Getenv("API_KEY"),
- ApiSecret: os.Getenv("API_SECRET"),
- RestURL: "https://api.testnet-dataengine.chain.link",
- Logger: streams.LogPrintf,
- }
- ```
-
- - Set your API credentials as environment variables:
-
- ```bash
- export API_KEY=""
- export API_SECRET=""
- ```
-
- Replace `` and `` with your API credentials.
-
- - `RestURL` is the REST endpoint to poll for specific reports. See the [Streams Direct Interface](/data-streams/reference/streams-direct/streams-direct-interface-api#domains) page for more information.
-
- See the [SDK Reference](/data-streams/reference/streams-direct/streams-direct-go-sdk#config-struct) page for more configuration options.
-
-1. For this example, you will read from the ETH/USD crypto stream. This stream ID is . See the [Stream Addresses](/data-streams/crypto-streams) page for a complete list of available crypto assets.
-
- Execute your application:
-
- ```bash
- go run single-stream.go 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782
- ```
-
- Expect output similar to the following in your terminal:
-
- ```bash
- Raw report data: {"fullReport":"0x0006f9b553e393ced311551efd30d1decedb63d76ad41737462e2cdbbdff157800000000000000000000000000000000000000000000000000000000351f200b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000028000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000120000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba7820000000000000000000000000000000000000000000000000000000066aa78ab0000000000000000000000000000000000000000000000000000000066aa78ab00000000000000000000000000000000000000000000000000001b6732178a04000000000000000000000000000000000000000000000000001b1e8f8f0dc6880000000000000000000000000000000000000000000000000000000066abca2b0000000000000000000000000000000000000000000000b3eba5491849628aa00000000000000000000000000000000000000000000000b3eaf356fc42b6f6c00000000000000000000000000000000000000000000000b3ecd20810b9d1c000000000000000000000000000000000000000000000000000000000000000000203f40222dca8f8531b2a9db61f105630118383062c0efdb04e5b42c5dd9db79b3e845b0b930cc8a11c94b0cc81917863687ff846cd7f841f70c284cf5e9d089b000000000000000000000000000000000000000000000000000000000000000266cdaf55fce51c53781597978e732de7f81991de4aaf703486fd65e48daf625477abe65ad40ae4a408b78edb9de621094a86517911d9fa188b95fc622ed727d1","feedID":"0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782","validFromTimestamp":1722448043,"observationsTimestamp":1722448043}
-
- Decoded Report for Stream ID 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782:
- ------------------------------------------
- Observations Timestamp: 1722448043
- Benchmark Price : 3318947247532739300000
- Bid : 3318897160259676600000
- Ask : 3319031900000000000000
- Valid From Timestamp : 1722448043
- Expires At : 1722534443
- Link Fee : 7633426300389000
- Native Fee : 30130035984900
- ------------------------------------------
- ```
-
-#### Decoded report details
-
-The decoded report details include:
-
-| Attribute | Value | Description |
-| ------------------------ | -------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `Stream ID` | `0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782` | The unique identifier for the stream. In this example, the stream is for ETH/USD. |
-| `Observations Timestamp` | `1722448043` | The timestamp indicating when the data was captured. |
-| `Benchmark Price` | `3318947247532739300000` | The observed price in the report, with 18 decimals. For readability: `3,318.9472475327393` USD per ETH. |
-| `Bid` | `3318897160259676600000` | The highest price a buyer is willing to pay for an asset, with 18 decimals. For readability: `3,318.8971602596766` USD per ETH. Learn more about the [Bid price](/data-streams/concepts/liquidity-weighted-prices). |
-| `Ask` | `3319031900000000000000` | The lowest price a seller is willing to accept for an asset, with 18 decimals. For readability: `3,319.0319000000000` USD per ETH. Learn more about the [Ask price](/data-streams/concepts/liquidity-weighted-prices). |
-| `Valid From Timestamp` | `1722448043` | The start validity timestamp for the report, indicating when the data becomes relevant. |
-| `Expires At` | `1722534443` | The expiration timestamp of the report, indicating the point at which the data becomes outdated. |
-| `Link Fee` | `7633426300389000` | The fee to pay in LINK tokens for the onchain verification of the report data. With 18 decimals. For readability: `0.007633426300389` LINK. |
-| `Native Fee` | `30130035984900` | The fee to pay in the native blockchain token (e.g., ETH on Ethereum) for the onchain verification of the report data. With 18 decimals. **Note:** This example fee is not indicative of actual fees. |
-
-#### Payload for onchain verification
-
-In this guide, you log and decode the `fullReport` payload to extract the report data. In a
-production environment, you should verify the data onchain to ensure its integrity and authenticity. Refer to the
-[Verify report data onchain](/data-streams/tutorials/streams-direct/streams-direct-onchain-verification) guide.
-
-### Fetch and decode reports for multiple streams
-
-1. Create a new Go file, `multiple-streams.go`, in your project directory:
-
- ```bash
- touch multiple-streams.go
- ```
-
-1. Insert the following code example in your `multiple-streams.go` file:
-
- ```go
- package main
-
- import (
- "context"
- "fmt"
- "os"
- "time"
-
- streams "github.com/smartcontractkit/data-streams-sdk/go"
- feed "github.com/smartcontractkit/data-streams-sdk/go/feed"
- report "github.com/smartcontractkit/data-streams-sdk/go/report"
- v3 "github.com/smartcontractkit/data-streams-sdk/go/report/v3" // Import the v3 report schema for Crypto streams. For RWA streams, use the v4 schema.
- )
-
- func main() {
- if len(os.Args) < 3 { // Ensure there are at least two Stream IDs provided
- fmt.Printf("Usage: go run multiple-streams.go [StreamID1] [StreamID2] ...\n")
- os.Exit(1)
- }
-
- // Define the configuration for the SDK client
- cfg := streams.Config{
- ApiKey: "YOUR_API_KEY",
- ApiSecret: "YOUR_API_SECRET",
- RestURL: "https://api.testnet-dataengine.chain.link",
- Logger: streams.LogPrintf,
- }
-
- // Initialize the SDK client
- client, err := streams.New(cfg)
- if err != nil {
- cfg.Logger("Failed to create client: %v\n", err)
- os.Exit(1)
- }
-
- // Create context for timeout
- ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
- defer cancel()
-
- // Parse Feed IDs from command line arguments
- var ids []feed.ID
- for _, arg := range os.Args[1:] {
- var fid feed.ID
- if err := fid.FromString(arg); err != nil {
- cfg.Logger("Failed to parse stream ID %s: %v\n", arg, err)
- os.Exit(1)
- }
- ids = append(ids, fid)
- }
-
- // Fetch reports for the given stream IDs
- reportResponses, err := client.GetReports(ctx, ids, uint64(time.Now().Unix())) // Using current time as an example timestamp
- if err != nil {
- cfg.Logger("Failed to get reports: %v\n", err)
- os.Exit(1)
- }
-
- for _, reportResponse := range reportResponses {
- // Log the contents of the report before decoding
- cfg.Logger("Raw report data for Stream ID %s: %+v\n", reportResponse.FeedID.String(), reportResponse)
-
- // Decode the report
- decodedReport, err := report.Decode[v3.Data](reportResponse.FullReport)
- if err != nil {
- cfg.Logger("Failed to decode report for Stream ID %s: %v\n", reportResponse.FeedID, err)
- continue // Skip to next report if decoding fails
- }
-
- // Log the decoded report
- cfg.Logger("\nDecoded Report for Stream ID %s:\n------------------------------------------\n"+
- "Observations Timestamp: %d\n"+
- "Benchmark Price : %s\n"+
- "Bid : %s\n"+
- "Ask : %s\n"+
- "Valid From Timestamp : %d\n"+
- "Expires At : %d\n"+
- "Link Fee : %s\n"+
- "Native Fee : %s\n"+
- "------------------------------------------\n",
- reportResponse.FeedID.String(),
- decodedReport.Data.ObservationsTimestamp,
- decodedReport.Data.BenchmarkPrice.String(),
- decodedReport.Data.Bid.String(),
- decodedReport.Data.Ask.String(),
- decodedReport.Data.ValidFromTimestamp,
- decodedReport.Data.ExpiresAt,
- decodedReport.Data.LinkFee.String(),
- decodedReport.Data.NativeFee.String(),
- )
- }
- }
- ```
-
-1. Replace `ApiKey` and `ApiSecret` with your API credentials in the SDK client configuration:
-
- ```go
- cfg := streams.Config{
- ApiKey: "YOUR_API_KEY",
- ApiSecret: "YOUR_API_SECRET",
- RestURL: "https://api.testnet-dataengine.chain.link",
- Logger: streams.LogPrintf,
- }
- ```
-
-1. For this example, you will read from the ETH/USD and LINK/USD Data Streams crypto streams. Run your application:
-
- ```bash
- go run multiple-streams.go 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782 0x00036fe43f87884450b4c7e093cd5ed99cac6640d8c2000e6afc02c8838d0265
- ```
-
- Expect to see the output below in your terminal:
-
- ```bash
- Raw report data for Stream ID 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782: {"fullReport":"0x0006f9b553e393ced311551efd30d1decedb63d76ad41737462e2cdbbdff157800000000000000000000000000000000000000000000000000000000351fae0f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000028001010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000120000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba7820000000000000000000000000000000000000000000000000000000066aa7c460000000000000000000000000000000000000000000000000000000066aa7c4600000000000000000000000000000000000000000000000000001b792816df70000000000000000000000000000000000000000000000000001b3ce720f89cb00000000000000000000000000000000000000000000000000000000066abcdc60000000000000000000000000000000000000000000000b37605534e2f2b24600000000000000000000000000000000000000000000000b3757e1b6805f45da00000000000000000000000000000000000000000000000b3768c8b345860648000000000000000000000000000000000000000000000000000000000000000021bf16c540e0eed976ae7cbfb1bc3d81e1f9bdba6ea2491c93b4abe16c7139325ab8a49f61ebe2231210dbcdd3cd4b42f303635fff1f2e325d21de9eec7875a9200000000000000000000000000000000000000000000000000000000000000026786234d10e05d5d42e3aca8fe96becd84cf8f8c46e658d578f09e3aa5165b394e13a87a7f48aeed6e13d9a7de90ef764a961494a6192c935fde0cad9c2fa660","feedID":"0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782","validFromTimestamp":1722448966,"observationsTimestamp":1722448966}
-
- Decoded Report for Stream ID 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782:
- ------------------------------------------
- Observations Timestamp: 1722448966
- Benchmark Price : 3310471484260632700000
- Bid : 3310433423677103300000
- Ask : 3310509544844162000000
- Valid From Timestamp : 1722448966
- Expires At : 1722535366
- Link Fee : 7666787759463600
- Native Fee : 30207177580400
- ------------------------------------------
-
- Raw report data for Stream ID 0x00036fe43f87884450b4c7e093cd5ed99cac6640d8c2000e6afc02c8838d0265: {"fullReport":"0x00060a2676459d14176b64106fcf3246631d3a03734171737eb082fe79c956e00000000000000000000000000000000000000000000000000000000039c6a415000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012000036fe43f87884450b4c7e093cd5ed99cac6640d8c2000e6afc02c8838d02650000000000000000000000000000000000000000000000000000000066aa7c460000000000000000000000000000000000000000000000000000000066aa7c4600000000000000000000000000000000000000000000000000001b791a5f6bcc000000000000000000000000000000000000000000000000001b3a3d53e3d5600000000000000000000000000000000000000000000000000000000066abcdc6000000000000000000000000000000000000000000000000b514b7b30a5c0000000000000000000000000000000000000000000000000000b506137dd1137388000000000000000000000000000000000000000000000000b51d9c2a243b700000000000000000000000000000000000000000000000000000000000000000028ebed5590f7967d24acbdc3efbbd0089f2b58a4664312f7a824556c2fa72a94f1c2acf3d5932cfbfa09671c23c652bbb787ba85bb9e64c68b70d0d542772912e000000000000000000000000000000000000000000000000000000000000000262e5902da042903df35a5f726f468e123883c6622f216fb0f313fc84c2a0de4c755f7eb4a4a57cd91a23b1ac76bfb39b533e3cbc3b39b90b239c792906639ed8","feedID":"0x00036fe43f87884450b4c7e093cd5ed99cac6640d8c2000e6afc02c8838d0265","validFromTimestamp":1722448966,"observationsTimestamp":1722448966}
-
- Decoded Report for Stream ID 0x00036fe43f87884450b4c7e093cd5ed99cac6640d8c2000e6afc02c8838d0265:
- ------------------------------------------
- Observations Timestamp: 1722448966
- Benchmark Price : 13048256000000000000
- Bid : 13044134801824773000
- Ask : 13050759000000000000
- Valid From Timestamp : 1722448966
- Expires At : 1722535366
- Link Fee : 7663859446044000
- Native Fee : 30206947453900
- ------------------------------------------
- ```
-
- Your application has successfully fetched and decoded data for both streams.
-
-#### Payload for onchain verification
-
-In this guide, you log and decode the `fullReport` payloads to extract the report data. In a
-production environment, you should verify the data onchain to ensure its integrity and authenticity. Refer to the
-[Verify report data onchain](/data-streams/tutorials/streams-direct/streams-direct-onchain-verification) guide.
-
-## Explanation
-
-### Fetching reports
-
-Your application uses the [Data Streams SDK](/data-streams/reference/streams-direct/streams-direct-go-sdk) to fetch reports from the Data Streams Aggregation Network. Different functions from the SDK are invoked based on whether a single stream or multiple streams are queried:
-
-- Single Stream: The application calls the [`GetLatestReport`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/go/client.go#L121) function from the SDK's `streams` package to fetch a single stream report. This function sends an API request to retrieve the latest available report for a specified stream ID. The response includes the report's data in a structured format suitable for further processing and analysis.
-
-- Multiple Streams: The [`GetReports`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/go/client.go#L199) function is used for multiple streams. This function allows you to fetch reports for multiple stream IDs simultaneously, specifying a timestamp to retrieve reports valid at a particular point in time.
-
-The responses include a `fullReport` blob containing the encoded report's context and observations.
-
-### Decoding reports
-
-After retrieving the report data, the application decodes it using the [`Decode`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/go/report/report.go#L30) function available in the `report` package of the SDK. This function is designed to handle different data formats by specifying the version of the data structure as a type parameter (e.g., `v3.Data` for crypto streams).
-
-The `Decode` function unpacks the encoded report blob into a usable data structure (`Report[v3.Data]` for [crypto streams](/data-streams/crypto-streams)). It extracts information such as observation timestamps, benchmark prices, [bid and ask prices](/data-streams/concepts/liquidity-weighted-prices) from the report data.
-
-### Handling the decoded data
-
-The application logs the report data to the terminal. However, this data can be used for further processing, analysis, or display in your own application.
diff --git a/src/content/data-streams/tutorials/streams-direct/streams-direct-ws.mdx b/src/content/data-streams/tutorials/streams-direct/streams-direct-ws-go.mdx
similarity index 93%
rename from src/content/data-streams/tutorials/streams-direct/streams-direct-ws.mdx
rename to src/content/data-streams/tutorials/streams-direct/streams-direct-ws-go.mdx
index 3e7bdf2c333..512b13b9eb7 100644
--- a/src/content/data-streams/tutorials/streams-direct/streams-direct-ws.mdx
+++ b/src/content/data-streams/tutorials/streams-direct/streams-direct-ws-go.mdx
@@ -1,7 +1,7 @@
---
section: dataStreams
date: Last Modified
-title: "Stream and decode reports via WebSocket using the SDK (Crypto Streams)"
+title: "Stream and decode V3 reports via WebSocket using the Go SDK"
whatsnext:
{
"Learn how to verify your data onchain": "/data-streams/reference/streams-direct/streams-direct-onchain-verification",
@@ -17,17 +17,29 @@ import DataStreams from "@features/data-streams/common/DataStreams.astro"
-In this guide, you'll learn how to use Chainlink Data Streams with the _[Streams Direct](/data-streams#streams-direct-using-data-streams-with-your-own-bot)_ implementation and the [Data Streams SDK](/data-streams/reference/streams-direct/streams-direct-go-sdk) for Go to subscribe to real-time [V3 reports](/data-streams/reference/report-schema) for [Crypto streams](/data-streams/crypto-streams) via a [WebSocket connection](/data-streams/reference/streams-direct/streams-direct-interface-ws). You'll set up your Go project, listen for real-time reports from the Data Streams Aggregation Network, decode the report data, and log their attributes to your terminal.
+In this guide, you'll learn how to use Chainlink Data Streams with the _[Streams Direct](/data-streams/streams-direct)_ implementation and the [Data Streams SDK](/data-streams/reference/streams-direct/streams-direct-go-sdk) for Go to subscribe to real-time [V3 reports](/data-streams/reference/report-schema) for [Crypto streams](/data-streams/crypto-streams) via a [WebSocket connection](/data-streams/reference/streams-direct/streams-direct-interface-ws). You'll set up your Go project, listen for real-time reports from the Data Streams Aggregation Network, decode the report data, and log their attributes to your terminal.
@@ -300,7 +312,7 @@ The decoded report details include:
#### Payload for onchain verification
In this guide, you log and decode the `fullReport` payload to extract the report data. In a
-production environment, you should verify the data onchain to ensure its integrity and authenticity. Refer to the
+production environment, you should verify the data to ensure its integrity and authenticity. Refer to the
[Verify report data onchain](/data-streams/tutorials/streams-direct/streams-direct-onchain-verification) guide.
## Explanation
diff --git a/src/content/data-streams/tutorials/streams-direct/streams-direct-ws-rust.mdx b/src/content/data-streams/tutorials/streams-direct/streams-direct-ws-rust.mdx
new file mode 100644
index 00000000000..16596bac48e
--- /dev/null
+++ b/src/content/data-streams/tutorials/streams-direct/streams-direct-ws-rust.mdx
@@ -0,0 +1,384 @@
+---
+section: dataStreams
+date: Last Modified
+title: "Stream and decode V3 reports via WebSocket using the Rust SDK"
+whatsnext:
+ {
+ "Learn how to verify your data onchain": "/data-streams/reference/streams-direct/streams-direct-onchain-verification",
+ "Find the list of available Stream IDs": "/data-streams/crypto-streams",
+ }
+---
+
+import { CopyText, PageTabs } from "@components"
+import DataStreams from "@features/data-streams/common/DataStreams.astro"
+
+
+
+
+
+In this guide, you'll learn how to use Chainlink Data Streams with the _[Streams Direct](/data-streams/streams-direct)_ implementation and the [Data Streams SDK](/data-streams/reference/streams-direct/streams-direct-rust-sdk) for Rust to subscribe to real-time [V3 reports](/data-streams/reference/report-schema) for [Crypto streams](/data-streams/crypto-streams) via a [WebSocket connection](/data-streams/reference/streams-direct/streams-direct-interface-ws). You'll set up your Rust project, listen for real-time reports from the Data Streams Aggregation Network, decode the report data, and log their attributes to your terminal.
+
+
+
+## Requirements
+
+- **Git**: Make sure you have Git installed. You can check your current version by running in your terminal and download the latest version from the official [Git website](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) if necessary.
+- **Rust**: Make sure you have Rust installed. You can install Rust by following the instructions on the official [Rust website](https://www.rust-lang.org/tools/install).
+- **API Credentials**: Access to the Streams Direct implementation requires API credentials. If you haven't already, [contact us](https://chainlinkcommunity.typeform.com/datastreams?typeform-source=docs.chain.link#ref_id=docs) to request mainnet or testnet early access.
+
+## Guide
+
+### Set up your Rust project
+
+1. Create a new directory for your project and navigate to it:
+
+ ```bash
+ mkdir my-data-streams-project && cd my-data-streams-project
+ ```
+
+1. Initialize a new Rust project:
+
+ ```bash
+ cargo init
+ ```
+
+1. Add the Data Streams SDK to your `Cargo.toml`:
+
+ ```toml
+ [dependencies]
+ data-streams-sdk = { git = "https://github.com/smartcontractkit/data-streams-sdk.git", subdir = "rust/crates/sdk", features = ["tracing"] }
+ data-streams-report = { git = "https://github.com/smartcontractkit/data-streams-sdk.git", subdir = "rust/crates/report" }
+ tokio = { version = "1.4", features = ["full"] }
+ hex = "0.4"
+ tracing = "0.1"
+ tracing-subscriber = { version = "0.3", features = ["time"] }
+ ```
+
+ Note: The `tracing` feature is required for logging functionality.
+
+### Establish a WebSocket connection and listen for real-time reports
+
+1. Replace the contents of `src/main.rs` with the following code:
+
+ ```rust
+ use data_streams_report::feed_id::ID;
+ use data_streams_report::report::{decode_full_report, v3::ReportDataV3}; // Import the v3 report schema for Crypto streams
+ use data_streams_sdk::config::Config;
+ use data_streams_sdk::stream::Stream;
+ use std::env;
+ use std::error::Error;
+ use tracing::{info, warn};
+ use tracing_subscriber::fmt::time::UtcTime;
+
+ #[tokio::main]
+ async fn main() -> Result<(), Box> {
+ // Initialize logging with UTC timestamps
+ tracing_subscriber::fmt()
+ .with_timer(UtcTime::rfc_3339())
+ .with_max_level(tracing::Level::INFO)
+ .init();
+
+ // Get feed IDs from command line arguments
+ let args: Vec = env::args().collect();
+ if args.len() < 2 {
+ eprintln!("Usage: cargo run [StreamID1] [StreamID2] ...");
+ std::process::exit(1);
+ }
+
+ // Get API credentials from environment variables
+ let api_key = env::var("API_KEY").expect("API_KEY must be set");
+ let api_secret = env::var("API_SECRET").expect("API_SECRET must be set");
+
+ // Parse feed IDs from command line arguments
+ let mut feed_ids = Vec::new();
+ for arg in args.iter().skip(1) {
+ let feed_id = ID::from_hex_str(arg)?;
+ feed_ids.push(feed_id);
+ }
+
+ // Initialize the configuration
+ let config = Config::new(
+ api_key,
+ api_secret,
+ "https://api.testnet-dataengine.chain.link".to_string(),
+ "wss://ws.testnet-dataengine.chain.link".to_string(),
+ )
+ .build()?;
+
+ // Create and initialize the stream
+ let mut stream = Stream::new(&config, feed_ids).await?;
+ stream.listen().await?;
+
+ info!("WebSocket connection established. Listening for reports...");
+
+ // Process incoming reports
+ loop {
+ match stream.read().await {
+ Ok(response) => {
+ info!("\nRaw report data: {:?}\n", response.report);
+
+ // Decode the report
+ let full_report = hex::decode(&response.report.full_report[2..])?;
+ let (_report_context, report_blob) = decode_full_report(&full_report)?;
+ let report_data = ReportDataV3::decode(&report_blob)?;
+
+ // Print decoded report details
+ info!(
+ "\n--- Report Stream ID: {} ---\n\
+ ------------------------------------------\n\
+ Observations Timestamp : {}\n\
+ Price : {}\n\
+ Bid : {}\n\
+ Ask : {}\n\
+ Valid From Timestamp : {}\n\
+ Expires At : {}\n\
+ Link Fee : {}\n\
+ Native Fee : {}\n\
+ ------------------------------------------",
+ response.report.feed_id.to_hex_string(),
+ response.report.observations_timestamp,
+ report_data.benchmark_price,
+ report_data.bid,
+ report_data.ask,
+ response.report.valid_from_timestamp,
+ report_data.expires_at,
+ report_data.link_fee,
+ report_data.native_fee,
+ );
+
+ // Print stream stats
+ info!(
+ "\n--- Stream Stats ---\n{:#?}\n\
+ --------------------------------------------------------------------------------------------------------------------------------------------",
+ stream.get_stats()
+ );
+ }
+ Err(e) => {
+ warn!("Error reading from stream: {:?}", e);
+ }
+ }
+ }
+
+ // Note: In a production environment, you should implement proper cleanup
+ // by calling stream.close() when the application is terminated.
+ // For example:
+ //
+ // tokio::select! {
+ // _ = tokio::signal::ctrl_c() => {
+ // info!("Received shutdown signal");
+ // stream.close().await?;
+ // }
+ // result = stream.read() => {
+ // // Process result
+ // }
+ // }
+ }
+ ```
+
+1. Set up your API credentials as environment variables:
+
+ ```bash
+ export API_KEY=""
+ export API_SECRET=""
+ ```
+
+ Replace `` and `` with your API credentials.
+
+1. For this example, you'll subscribe to the ETH/USD Data Streams crypto stream. This stream ID is . See the [Crypto Streams](/data-streams/crypto-streams) page for a complete list of available crypto assets.
+
+ Build and run your application:
+
+ ```bash
+ cargo run -- 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782
+ ```
+
+ Expect output similar to the following in your terminal:
+
+ ```bash
+ 2024-12-13T23:07:56.463719Z INFO my_data_streams_project: WebSocket connection established. Listening for reports...
+ 2024-12-13T23:07:56.463824Z INFO data_streams_sdk::stream::monitor_connection: Received ping: [49]
+ 2024-12-13T23:07:56.463868Z INFO data_streams_sdk::stream::monitor_connection: Responding with pong: [49]
+ 2024-12-13T23:07:57.060504Z INFO data_streams_sdk::stream::monitor_connection: Received new report from Data Streams Endpoint.
+ 2024-12-13T23:07:57.061078Z INFO my_data_streams_project:
+ Raw report data: Report { feed_id: 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782, valid_from_timestamp: 1734131277, observations_timestamp: 1734131277, full_report: "0x0006f9b553e393ced311551efd30d1decedb63d76ad41737462e2cdbbdff1578000000000000000000000000000000000000000000000000000000004f5ac90d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000028001010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000120000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba78200000000000000000000000000000000000000000000000000000000675cbe4d00000000000000000000000000000000000000000000000000000000675cbe4d000000000000000000000000000000000000000000000000000017489b06e8fc000000000000000000000000000000000000000000000000000c7badb615bd1400000000000000000000000000000000000000000000000000000000675e0fcd0000000000000000000000000000000000000000000000d3c0d34ca0d14d85600000000000000000000000000000000000000000000000d3bda64c97c9f3a3a00000000000000000000000000000000000000000000000d3c1a08e0cffd77690000000000000000000000000000000000000000000000000000000000000000238102110cad488ecf151a17276fcfad6ef1f05593edfe80f6823b729416f826972ba32d085525b1d7ab79e6ae8188928c86051a4fc75f500bffabda2acd1d1f900000000000000000000000000000000000000000000000000000000000000024dddbc660abf75c30cb3c2aa375c87d228b2ee8735e339f59c5214897c0b89af39a7602df754364cce029f6eb7699ee02ffded96d0c46b5919e81ee4f650d1cb" }
+
+ 2024-12-13T23:07:57.062344Z INFO my_data_streams_project:
+ --- Report Stream ID: 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782 ---
+ ------------------------------------------
+ Observations Timestamp : 1734131277
+ Price : 3906157533081673500000
+ Bid : 3905928693886829700000
+ Ask : 3906215307384792250000
+ Valid From Timestamp : 1734131277
+ Expires At : 1734217677
+ Link Fee : 3513685734964500
+ Native Fee : 25600606005500
+ ------------------------------------------
+ 2024-12-13T23:07:57.062489Z INFO my_data_streams_project:
+ --- Stream Stats ---
+ StatsSnapshot {
+ accepted: 1,
+ deduplicated: 0,
+ total_received: 1,
+ partial_reconnects: 0,
+ full_reconnects: 0,
+ configured_connections: 1,
+ active_connections: 1,
+ }
+ --------------------------------------------------------------------------------------------------------------------------------------------
+ 2024-12-13T23:07:58.065686Z INFO data_streams_sdk::stream::monitor_connection: Received new report from Data Streams Endpoint.
+ 2024-12-13T23:07:58.066315Z INFO my_data_streams_project:
+ Raw report data: Report { feed_id: 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782, valid_from_timestamp: 1734131278, observations_timestamp: 1734131278, full_report: "0x0006f9b553e393ced311551efd30d1decedb63d76ad41737462e2cdbbdff1578000000000000000000000000000000000000000000000000000000004f5ac911000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000028000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000120000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba78200000000000000000000000000000000000000000000000000000000675cbe4e00000000000000000000000000000000000000000000000000000000675cbe4e00000000000000000000000000000000000000000000000000001748ee300af4000000000000000000000000000000000000000000000000000c7b8b51304fbc00000000000000000000000000000000000000000000000000000000675e0fce0000000000000000000000000000000000000000000000d3bddf08d0b10a28e00000000000000000000000000000000000000000000000d3bb84af9f92f963c00000000000000000000000000000000000000000000000d3bf1d6bf14e501fc000000000000000000000000000000000000000000000000000000000000000021402b6b82c20826315384d74b3235b95f136ac65bba8c9e97c24d786e499894f298b51ae4aeba55cce0f85f2463e49e0a5e001b9a66f5b7b91e8be37d81d6cc5000000000000000000000000000000000000000000000000000000000000000217895cb599abc88d7b695edafed5ca5a5fc970f079b48bc2218888eec1fcccb0430c1ba2aa13b0d10f6c6b19a43cdb770029f4fb5804b0e2ef5ba3e73ca710f8" }
+
+ 2024-12-13T23:07:58.067395Z INFO my_data_streams_project:
+ --- Report Stream ID: 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782 ---
+ ------------------------------------------
+ Observations Timestamp : 1734131278
+ Price : 3905944663438106700000
+ Bid : 3905775117434634200000
+ Ask : 3906034281472429400000
+ Valid From Timestamp : 1734131278
+ Expires At : 1734217678
+ Link Fee : 3513538013319100
+ Native Fee : 25602001210100
+ ------------------------------------------
+ 2024-12-13T23:07:58.067633Z INFO my_data_streams_project:
+ --- Stream Stats ---
+ StatsSnapshot {
+ accepted: 2,
+ deduplicated: 0,
+ total_received: 2,
+ partial_reconnects: 0,
+ full_reconnects: 0,
+ configured_connections: 1,
+ active_connections: 1,
+ }
+
+ [...]
+ ```
+
+The example above demonstrates streaming data from a single crypto stream. For production environments, especially when subscribing to multiple streams, it's recommended to enable [High Availability (HA) mode](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/docs/examples/wss_multiple.md). This can be achieved by:
+
+1. Adding multiple WebSocket endpoints in the configuration:
+
+ ```rust
+ "wss://ws.testnet-dataengine.chain.link,wss://ws.testnet-dataengine.chain.link"
+ ```
+
+1. Enabling HA mode in the configuration:
+ ```rust
+ use data_streams_sdk::config::WebSocketHighAvailability;
+ // ...
+ .with_ws_ha(WebSocketHighAvailability::Enabled)
+ ```
+
+When HA mode is enabled and multiple WebSocket origins are provided, the Stream will maintain concurrent connections to different instances. This ensures high availability, fault tolerance, and minimizes the risk of report gaps.
+
+You can subscribe to multiple streams by providing additional stream IDs as command-line arguments:
+
+```bash
+cargo run -- \
+ 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782 \
+ 0x00037da06d56d083fe599397a4769a042d63aa73dc4ef57709d31e9971a5b439
+```
+
+This will subscribe to both ETH/USD and BTC/USD streams.
+
+#### Decoded report details
+
+The decoded report details include:
+
+| Attribute | Value | Description |
+| ------------------------ | -------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| `Stream ID` | `0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782` | The unique identifier for the stream. In this example, the stream is for ETH/USD. |
+| `Observations Timestamp` | `1734131277` | The timestamp indicating when the data was captured. |
+| `Price` | `3906157533081673500000` | The observed price in the report, with 18 decimals. For readability: `3,906.1575330816735` USD per ETH. |
+| `Bid` | `3905928693886829700000` | The highest price a buyer is willing to pay for an asset, with 18 decimals. For readability: `3,905.9286938868297` USD per ETH. Learn more about the [Bid price](/data-streams/concepts/liquidity-weighted-prices). |
+| `Ask` | `3906215307384792250000` | The lowest price a seller is willing to accept for an asset, with 18 decimals. For readability: `3,906.2153073847923` USD per ETH. Learn more about the [Ask price](/data-streams/concepts/liquidity-weighted-prices). |
+| `Valid From Timestamp` | `1734131277` | The start validity timestamp for the report, indicating when the data becomes relevant. |
+| `Expires At` | `1734217677` | The expiration timestamp of the report, indicating the point at which the data becomes outdated. |
+| `Link Fee` | `3513685734964500` | The fee to pay in LINK tokens for the onchain verification of the report data. With 18 decimals. For readability: `0.0035136857349645` LINK. **Note:** This example fee is not indicative of actual fees. |
+| `Native Fee` | `25600606005500` | The fee to pay in the native blockchain token (e.g., ETH on Ethereum) for the onchain verification of the report data. With 18 decimals. For readability: `0.0000256006060055` ETH. **Note:** This example fee is not indicative of actual fees. |
+
+#### Payload for onchain verification
+
+In this guide, you log and decode the `full_report` payload to extract the report data. In a
+production environment, you should verify the data to ensure its integrity and authenticity. Refer to the
+[Verify report data onchain](/data-streams/tutorials/streams-direct/streams-direct-onchain-verification) guide.
+
+## Explanation
+
+### Establishing a WebSocket connection and listening for reports
+
+The WebSocket connection is established in two steps:
+
+1. [`Stream::new`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/crates/sdk/src/stream.rs#L131) initializes a new stream instance with your configuration and feed IDs. This function prepares the connection parameters but doesn't establish the connection yet.
+
+2. [`stream.listen()`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/crates/sdk/src/stream.rs#L162) establishes the actual WebSocket connection and starts the background tasks that maintain the connection. These tasks handle:
+ - Automatic reconnection if the connection is lost
+ - Ping/pong messages to keep the connection alive
+ - Message queueing and delivery
+
+### Decoding a report
+
+As data reports arrive via the WebSocket connection, they are processed in real-time through several steps:
+
+1. Reading streams: The [`read`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/crates/sdk/src/stream.rs#L218) method on the Stream object is called within a loop. This asynchronous method:
+
+ - Awaits the next report from the WebSocket connection
+ - Handles backpressure automatically
+ - Returns a [`WebSocketReport`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/crates/sdk/src/stream.rs#L43) containing the report data
+
+2. Decoding reports: Each report is decoded in two stages:
+ - [`decode_full_report`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/crates/report/src/report.rs#L77) parses the raw hexadecimal data, separating the report context (containing metadata) from the report blob
+ - [`ReportDataV3::decode`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/crates/report/src/report/v3.rs#L80) transforms the report blob into a structured format containing:
+ - The benchmark price (with 18 decimal places)
+ - Bid and ask prices for [liquidity-weighted pricing](/data-streams/concepts/liquidity-weighted-prices)
+ - Fee information for onchain verification
+ - Timestamp information
+
+### Handling the decoded data
+
+The example demonstrates several best practices for handling the decoded data:
+
+1. Logging:
+
+ - Uses the [`tracing`](https://github.com/tokio-rs/tracing) crate for structured logging
+ - Configures UTC timestamps for consistent time representation
+ - Includes both raw report data and decoded fields for debugging
+
+2. Error handling:
+
+ - Uses Rust's `Result` type for robust error handling
+ - Implements the `?` operator for clean error propagation
+ - Logs errors with appropriate context using `warn!` macro
+
+3. Stream monitoring:
+ - Tracks stream statistics through [`get_stats()`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/crates/sdk/src/stream.rs#L253)
+ - Monitors connection status and reconnection attempts
+ - Reports message acceptance and deduplication counts
+
+The decoded data can be used for further processing, analysis, or display in your application. For production environments, it's recommended to verify the data onchain using the provided `full_report` payload.
diff --git a/src/content/data-streams/tutorials/streams-direct/streams-direct-ws-rwa.mdx b/src/content/data-streams/tutorials/streams-direct/streams-direct-ws-rwa-go.mdx
similarity index 93%
rename from src/content/data-streams/tutorials/streams-direct/streams-direct-ws-rwa.mdx
rename to src/content/data-streams/tutorials/streams-direct/streams-direct-ws-rwa-go.mdx
index 1729730e5aa..95112c89090 100644
--- a/src/content/data-streams/tutorials/streams-direct/streams-direct-ws-rwa.mdx
+++ b/src/content/data-streams/tutorials/streams-direct/streams-direct-ws-rwa-go.mdx
@@ -1,7 +1,7 @@
---
section: dataStreams
date: Last Modified
-title: "Stream and decode reports via WebSocket using the SDK (RWA Streams)"
+title: "Stream and decode V4 reports via WebSocket using the Go SDK"
whatsnext:
{
"Learn how to verify your data onchain": "/data-streams/reference/streams-direct/streams-direct-onchain-verification",
@@ -17,17 +17,29 @@ import DataStreams from "@features/data-streams/common/DataStreams.astro"
-In this guide, you'll learn how to use Chainlink Data Streams with the _[Streams Direct](/data-streams#streams-direct-using-data-streams-with-your-own-bot)_ implementation and the [Data Streams SDK](/data-streams/reference/streams-direct/streams-direct-go-sdk) for Go to subscribe to real-time [V4 reports](/data-streams/reference/report-schema-v4) for [Real World Assets (RWAs) streams](/data-streams/rwa-streams) via a [WebSocket connection](/data-streams/reference/streams-direct/streams-direct-interface-ws). You'll set up your Go project, listen for real-time reports from the Data Streams Aggregation Network, decode the report data, and log their attributes to your terminal.
+In this guide, you'll learn how to use Chainlink Data Streams with the _[Streams Direct](/data-streams/streams-direct)_ implementation and the [Data Streams SDK](/data-streams/reference/streams-direct/streams-direct-go-sdk) for Go to subscribe to real-time [V4 reports](/data-streams/reference/report-schema-v4) for [Real World Assets (RWAs) streams](/data-streams/rwa-streams) via a [WebSocket connection](/data-streams/reference/streams-direct/streams-direct-interface-ws). You'll set up your Go project, listen for real-time reports from the Data Streams Aggregation Network, decode the report data, and log their attributes to your terminal.
@@ -294,7 +306,7 @@ The decoded report details include:
#### Payload for onchain verification
In this guide, you log and decode the `fullReport` payload to extract the report data. In a
-production environment, you should verify the data onchain to ensure its integrity and authenticity. Refer to the
+production environment, you should verify the data to ensure its integrity and authenticity. Refer to the
[Verify report data onchain](/data-streams/tutorials/streams-direct/streams-direct-onchain-verification) guide.
## Explanation
diff --git a/src/content/data-streams/tutorials/streams-direct/streams-direct-ws-rwa-rust.mdx b/src/content/data-streams/tutorials/streams-direct/streams-direct-ws-rwa-rust.mdx
new file mode 100644
index 00000000000..faac19d78e0
--- /dev/null
+++ b/src/content/data-streams/tutorials/streams-direct/streams-direct-ws-rwa-rust.mdx
@@ -0,0 +1,363 @@
+---
+section: dataStreams
+date: Last Modified
+title: "Stream and decode V4 reports via WebSocket using the Rust SDK"
+whatsnext:
+ {
+ "Learn how to verify your data onchain": "/data-streams/reference/streams-direct/streams-direct-onchain-verification",
+ "Find the list of available Stream IDs": "/data-streams/rwa-streams",
+ }
+---
+
+import { CopyText, PageTabs } from "@components"
+import DataStreams from "@features/data-streams/common/DataStreams.astro"
+
+
+
+
+
+In this guide, you'll learn how to use Chainlink Data Streams with the _[Streams Direct](/data-streams/streams-direct)_ implementation and the [Data Streams SDK](/data-streams/reference/streams-direct/streams-direct-rust-sdk) for Rust to subscribe to real-time [V4 reports](/data-streams/reference/report-schema-v4) for [Real World Assets (RWA) streams](/data-streams/rwa-streams) via a [WebSocket connection](/data-streams/reference/streams-direct/streams-direct-interface-ws). You'll set up your Rust project, listen for real-time reports from the Data Streams Aggregation Network, decode the report data, and log their attributes to your terminal.
+
+
+
+## Requirements
+
+- **Git**: Make sure you have Git installed. You can check your current version by running in your terminal and download the latest version from the official [Git website](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) if necessary.
+- **Rust**: Make sure you have Rust installed. You can install Rust by following the instructions on the official [Rust website](https://www.rust-lang.org/tools/install).
+- **API Credentials**: Access to the Streams Direct implementation requires API credentials. If you haven't already, [contact us](https://chainlinkcommunity.typeform.com/datastreams?typeform-source=docs.chain.link#ref_id=docs) to request mainnet or testnet early access.
+
+## Guide
+
+### Set up your Rust project
+
+1. Create a new directory for your project and navigate to it:
+
+ ```bash
+ mkdir my-data-streams-project && cd my-data-streams-project
+ ```
+
+1. Initialize a new Rust project:
+
+ ```bash
+ cargo init
+ ```
+
+1. Add the Data Streams SDK to your `Cargo.toml`:
+
+ ```toml
+ [dependencies]
+ data-streams-sdk = { git = "https://github.com/smartcontractkit/data-streams-sdk.git", subdir = "rust/crates/sdk" }
+ data-streams-report = { git = "https://github.com/smartcontractkit/data-streams-sdk.git", subdir = "rust/crates/report" }
+ tokio = { version = "1.4", features = ["full"] }
+ hex = "0.4"
+ tracing = "0.1"
+ tracing-subscriber = { version = "0.3", features = ["time"] }
+ ```
+
+### Establish a WebSocket connection and listen for real-time reports
+
+1. Replace the contents of `src/main.rs` with the following code:
+
+ ```rust
+ use data_streams_report::feed_id::ID;
+ use data_streams_report::report::{decode_full_report, v4::ReportDataV4}; // Import the v4 report schema for RWA streams
+ use data_streams_sdk::config::Config;
+ use data_streams_sdk::stream::Stream;
+ use std::env;
+ use std::error::Error;
+ use tracing::{info, warn};
+ use tracing_subscriber::fmt::time::UtcTime;
+
+ #[tokio::main]
+ async fn main() -> Result<(), Box> {
+ // Initialize logging with UTC timestamps
+ tracing_subscriber::fmt()
+ .with_timer(UtcTime::rfc_3339())
+ .with_max_level(tracing::Level::INFO)
+ .init();
+
+ // Get feed IDs from command line arguments
+ let args: Vec = env::args().collect();
+ if args.len() < 2 {
+ eprintln!("Usage: cargo run [StreamID1] [StreamID2] ...");
+ std::process::exit(1);
+ }
+
+ // Get API credentials from environment variables
+ let api_key = env::var("API_KEY").expect("API_KEY must be set");
+ let api_secret = env::var("API_SECRET").expect("API_SECRET must be set");
+
+ // Parse feed IDs from command line arguments
+ let mut feed_ids = Vec::new();
+ for arg in args.iter().skip(1) {
+ let feed_id = ID::from_hex_str(arg)?;
+ feed_ids.push(feed_id);
+ }
+
+ // Initialize the configuration
+ let config = Config::new(
+ api_key,
+ api_secret,
+ "https://api.testnet-dataengine.chain.link".to_string(),
+ "wss://ws.testnet-dataengine.chain.link".to_string(),
+ )
+ .build()?;
+
+ // Create and initialize the stream
+ let mut stream = Stream::new(&config, feed_ids).await?;
+ stream.listen().await?;
+
+ info!("WebSocket connection established. Listening for reports...");
+
+ // Process incoming reports
+ loop {
+ match stream.read().await {
+ Ok(response) => {
+ info!("\nRaw report data: {:?}\n", response.report);
+
+ // Decode the report
+ let full_report = hex::decode(&response.report.full_report[2..])?;
+ let (_report_context, report_blob) = decode_full_report(&full_report)?;
+ let report_data = ReportDataV4::decode(&report_blob)?;
+
+ // Print decoded report details
+ info!(
+ "\n--- Report Stream ID: {} ---\n\
+ ------------------------------------------\n\
+ Observations Timestamp : {}\n\
+ Benchmark Price : {}\n\
+ Valid From Timestamp : {}\n\
+ Expires At : {}\n\
+ Link Fee : {}\n\
+ Native Fee : {}\n\
+ Market Status : {}\n\
+ ------------------------------------------",
+ response.report.feed_id.to_hex_string(),
+ response.report.observations_timestamp,
+ report_data.price,
+ response.report.valid_from_timestamp,
+ report_data.expires_at,
+ report_data.link_fee,
+ report_data.native_fee,
+ report_data.market_status
+ );
+
+ // Print stream stats
+ info!(
+ "\n--- Stream Stats ---\n{:#?}\n\
+ --------------------------------------------------------------------------------------------------------------------------------------------",
+ stream.get_stats()
+ );
+ }
+ Err(e) => {
+ warn!("Error reading from stream: {:?}", e);
+ }
+ }
+ }
+ }
+ ```
+
+1. Set up your API credentials as environment variables:
+
+ ```bash
+ export API_KEY=""
+ export API_SECRET=""
+ ```
+
+ Replace `` and `` with your API credentials.
+
+1. For this example, you'll subscribe to the AUD/USD Data Streams RWA stream. This stream ID is . See the [RWA Streams](/data-streams/rwa-streams) page for a complete list of available real-world assets.
+
+ Build and run your application:
+
+ ```bash
+ cargo run -- 0x000434a5b30cafe7e853832a458ea1591dc2f5fb5e4cf80b9979b8248065a7ea
+ ```
+
+ Expect output similar to the following in your terminal:
+
+ ```bash
+ 2024-12-13T23:37:17.054816Z INFO my_data_streams_project: WebSocket connection established. Listening for reports...
+ 2024-12-13T23:37:17.054876Z INFO data_streams_sdk::stream::monitor_connection: Received ping: [49]
+ 2024-12-13T23:37:17.054896Z INFO data_streams_sdk::stream::monitor_connection: Responding with pong: [49]
+ 2024-12-13T23:37:17.199112Z INFO data_streams_sdk::stream::monitor_connection: Received new report from Data Streams Endpoint.
+ 2024-12-13T23:37:17.199304Z INFO my_data_streams_project:
+ Raw report data: Report { feed_id: 0x000434a5b30cafe7e853832a458ea1591dc2f5fb5e4cf80b9979b8248065a7ea, valid_from_timestamp: 1734133037, observations_timestamp: 1734133037, full_report: "0x0006aee203ef23a892e75b579f8c3f26fd933d9ca45de95c2f8ac470f4ddcd76000000000000000000000000000000000000000000000000000000000b42b108000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000434a5b30cafe7e853832a458ea1591dc2f5fb5e4cf80b9979b8248065a7ea00000000000000000000000000000000000000000000000000000000675cc52d00000000000000000000000000000000000000000000000000000000675cc52d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000675e16ad00000000000000000000000000000000000000000000000008d4182644500000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000021521eae32097ed41bc3dad69f365da1979d155b574cc84e4dfb9e7970821d6bc40fac4c300b09b7cfae106f1008b4bec83edd27f20c5a3ad6b2c736e0765ecc500000000000000000000000000000000000000000000000000000000000000024941c68ad5a7d69e92fc927633634cd6cf478f7c11e3c3408341b462dac292ce66cc18bf09c30ad1df589dbfc0a19172a4719bb51efe83450ce14d959bccf541" }
+
+ 2024-12-13T23:37:17.199585Z INFO my_data_streams_project:
+ --- Report Stream ID: 0x000434a5b30cafe7e853832a458ea1591dc2f5fb5e4cf80b9979b8248065a7ea ---
+ ------------------------------------------
+ Observations Timestamp : 1734133037
+ Benchmark Price : 636160000000000000
+ Valid From Timestamp : 1734133037
+ Expires At : 1734219437
+ Link Fee : 0
+ Native Fee : 0
+ Market Status : 1
+ ------------------------------------------
+ 2024-12-13T23:37:17.199633Z INFO my_data_streams_project:
+ --- Stream Stats ---
+ StatsSnapshot {
+ accepted: 1,
+ deduplicated: 0,
+ total_received: 1,
+ partial_reconnects: 0,
+ full_reconnects: 0,
+ configured_connections: 1,
+ active_connections: 1,
+ }
+ --------------------------------------------------------------------------------------------------------------------------------------------
+ 2024-12-13T23:37:18.215222Z INFO data_streams_sdk::stream::monitor_connection: Received new report from Data Streams Endpoint.
+ 2024-12-13T23:37:18.21587Z INFO my_data_streams_project:
+ Raw report data: Report { feed_id: 0x000434a5b30cafe7e853832a458ea1591dc2f5fb5e4cf80b9979b8248065a7ea, valid_from_timestamp: 1734133038, observations_timestamp: 1734133038, full_report: "0x0006aee203ef23a892e75b579f8c3f26fd933d9ca45de95c2f8ac470f4ddcd76000000000000000000000000000000000000000000000000000000000b42b10c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000434a5b30cafe7e853832a458ea1591dc2f5fb5e4cf80b9979b8248065a7ea00000000000000000000000000000000000000000000000000000000675cc52e00000000000000000000000000000000000000000000000000000000675cc52e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000675e16ae00000000000000000000000000000000000000000000000008d4182644500000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000026a76e4abe53b8f3f7f0ca1628335a0da840d28502ea2c44e67951b17b8cc74da781aa786d5503c09043c29d0db71db2b0de3b5b5302a9050b7acdf93fdf4a36f00000000000000000000000000000000000000000000000000000000000000027d06597171eceea257fc1eaa222d4b47a0b5d227e8bf746031e9061806e55b2778fa8c6e10a574d7f9a4e192090f71769468eb3e626b3354e6cdaadff120e170" }
+
+ 2024-12-13T23:37:18.216946Z INFO my_data_streams_project:
+ --- Report Stream ID: 0x000434a5b30cafe7e853832a458ea1591dc2f5fb5e4cf80b9979b8248065a7ea ---
+ ------------------------------------------
+ Observations Timestamp : 1734133038
+ Benchmark Price : 636160000000000000
+ Valid From Timestamp : 1734133038
+ Expires At : 1734219438
+ Link Fee : 0
+ Native Fee : 0
+ Market Status : 1
+ ------------------------------------------
+ 2024-12-13T23:37:18.21714Z INFO my_data_streams_project:
+ --- Stream Stats ---
+ StatsSnapshot {
+ accepted: 2,
+ deduplicated: 0,
+ total_received: 2,
+ partial_reconnects: 0,
+ full_reconnects: 0,
+ configured_connections: 1,
+ active_connections: 1,
+ }
+
+ [...]
+ ```
+
+The example above demonstrates streaming data from a single RWA stream. For production environments, especially when subscribing to multiple streams, it's recommended to enable [High Availability (HA) mode](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/docs/examples/wss_multiple.md). This can be achieved by:
+
+1. Adding multiple WebSocket endpoints in the configuration:
+
+ ```rust
+ "wss://ws.testnet-dataengine.chain.link,wss://ws.testnet-dataengine.chain.link"
+ ```
+
+2. Enabling HA mode in the configuration:
+ ```rust
+ use data_streams_sdk::config::WebSocketHighAvailability;
+ // ...
+ .with_ws_ha(WebSocketHighAvailability::Enabled)
+ ```
+
+When HA mode is enabled and multiple WebSocket origins are provided, the Stream will maintain concurrent connections to different instances. This ensures high availability, fault tolerance, and minimizes the risk of report gaps.
+
+You can subscribe to multiple streams by providing additional stream IDs as command-line arguments:
+
+```bash
+cargo run -- \
+ 0x000434a5b30cafe7e853832a458ea1591dc2f5fb5e4cf80b9979b8248065a7ea \
+ 0x0004f41f3d47d2c15f817309d905d4508e809c98b1eafc7b6cdc2a6c8ec23f3f
+```
+
+This will subscribe to both AUD/USD and EUR/USD streams.
+
+#### Decoded report details
+
+The decoded report details include:
+
+| Attribute | Value | Description |
+| ------------------------ | -------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `Stream ID` | `0x000434a5b30cafe7e853832a458ea1591dc2f5fb5e4cf80b9979b8248065a7ea` | The unique identifier for the stream. In this example, the stream is for AUD/USD. |
+| `Observations Timestamp` | `1734133037` | The timestamp indicating when the data was captured. |
+| `Benchmark Price` | `636160000000000000` | The observed price in the report, with 18 decimals. For readability: `0.63616` USD per AUD. |
+| `Valid From Timestamp` | `1734133037` | The start validity timestamp for the report, indicating when the data becomes relevant. |
+| `Expires At` | `1734219437` | The expiration timestamp of the report, indicating the point at which the data becomes outdated. |
+| `Link Fee` | `0` | The fee to pay in LINK tokens for the onchain verification of the report data. With 18 decimals. **Note:** This example fee is not indicative of actual fees. |
+| `Native Fee` | `0` | The fee to pay in the native blockchain token (e.g., ETH on Ethereum) for the onchain verification of the report data. With 18 decimals. **Note:** This example fee is not indicative of actual fees. |
+| `Market Status` | `1` | The DON's consensus on whether the market is currently open. Possible values: `0` (`Unknown`), `1` (`Closed`), `2` (`Open`). In this case, the market is closed. |
+
+#### Payload for onchain verification
+
+In this guide, you log and decode the `full_report` payload to extract the report data. In a
+production environment, you should verify the data onchain to ensure its integrity and authenticity. Refer to the
+[Verify report data onchain](/data-streams/tutorials/streams-direct/streams-direct-onchain-verification) guide.
+
+## Explanation
+
+### Establishing a WebSocket connection and listening for reports
+
+The WebSocket connection is established in two steps:
+
+1. [`Stream::new`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/crates/sdk/src/stream.rs#L131) initializes a new stream instance with your configuration and feed IDs. This function prepares the connection parameters but doesn't establish the connection yet.
+
+2. [`stream.listen()`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/crates/sdk/src/stream.rs#L162) establishes the actual WebSocket connection and starts the background tasks that maintain the connection. These tasks handle:
+ - Automatic reconnection if the connection is lost
+ - Ping/pong messages to keep the connection alive
+ - Message queueing and delivery
+
+### Decoding a report
+
+As data reports arrive via the WebSocket connection, they are processed in real-time through several steps:
+
+1. Reading streams: The [`read`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/crates/sdk/src/stream.rs#L218) method on the Stream object is called within a loop. This asynchronous method:
+
+ - Awaits the next report from the WebSocket connection
+ - Handles backpressure automatically
+ - Returns a `WebSocketReport` containing the report data
+
+2. Decoding reports: Each report is decoded in two stages:
+ - [`decode_full_report`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/crates/report/src/report.rs#L77) parses the raw hexadecimal data, separating the report context (containing metadata) from the report blob
+ - [`ReportDataV4::decode`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/crates/report/src/report/v4.rs#L57) transforms the report blob into a structured format containing:
+ - The benchmark price (with 18 decimal places)
+ - Market status (indicating if the market is open, closed, or unknown)
+ - Fee information for onchain verification
+ - Timestamp information
+
+### Handling the decoded data
+
+The example demonstrates several best practices for handling the decoded data:
+
+1. Logging:
+
+ - Uses the [`tracing`](https://github.com/tokio-rs/tracing) crate for structured logging
+ - Configures UTC timestamps for consistent time representation
+ - Includes both raw report data and decoded fields for debugging
+
+2. Error handling:
+
+ - Uses Rust's `Result` type for robust error handling
+ - Implements the `?` operator for clean error propagation
+ - Logs errors with appropriate context using `warn!` macro
+
+3. Stream monitoring:
+ - Tracks stream statistics through [`get_stats()`](https://github.com/smartcontractkit/data-streams-sdk/blob/main/rust/crates/sdk/src/stream.rs#L253)
+ - Monitors connection status and reconnection attempts
+ - Reports message acceptance and deduplication counts
+
+The decoded data can be used for further processing, analysis, or display in your application. For production environments, it's recommended to verify the data onchain using the provided `full_report` payload.
diff --git a/src/content/data-streams/tutorials/streams-trade/index.mdx b/src/content/data-streams/tutorials/streams-trade/index.mdx
index 5dad1317ccd..c4c6874cd3a 100644
--- a/src/content/data-streams/tutorials/streams-trade/index.mdx
+++ b/src/content/data-streams/tutorials/streams-trade/index.mdx
@@ -5,7 +5,7 @@ title: "Streams Trade guides"
isIndex: true
---
-Explore several guides to learn how to use the [Streams Trade](/data-streams#streams-trade-using-data-streams-with-chainlink-automation) implementation of Data Streams.
+Explore several guides to learn how to use the [Streams Trade](/data-streams/streams-trade) implementation of Data Streams.
- [Getting Started](/data-streams/getting-started): Learn how to read data from a Data Streams stream, verify the answer onchain, and store it.
- [Handle StreamsLookup errors](/data-streams/tutorials/streams-trade/streams-trade-lookup-error-handler): Learn how to handle potential errors or edge cases in StreamsLookup upkeeps.
diff --git a/src/features/data-streams/common/gettingStarted.mdx b/src/features/data-streams/common/gettingStarted.mdx
index 2ed8f6c3d3e..55059ef9d0e 100644
--- a/src/features/data-streams/common/gettingStarted.mdx
+++ b/src/features/data-streams/common/gettingStarted.mdx
@@ -3,9 +3,9 @@ import DataStreams from "@features/data-streams/common/DataStreams.astro"
This guide shows you how to read data from a Data Streams stream, verify the answer onchain, and store it.
-This example uses the _[Streams Trade](/data-streams#streams-trade-using-data-streams-with-chainlink-automation) implementation_, with a [Chainlink Automation Log Trigger](/chainlink-automation/guides/log-trigger) to check for events that require data. For this example, the log trigger comes from a simple emitter contract. Chainlink Automation then uses `StreamsLookup` to retrieve a signed report from the Data Streams Aggregation Network, return the data in a callback, and run the [`performUpkeep` function](/chainlink-automation/reference/automation-interfaces#performupkeep-function-for-log-triggers) on your registered upkeep contract. The `performUpkeep` function calls the `verify` function on the verifier contract.
+This example uses the _[Streams Trade](/data-streams/streams-trade) implementation_, with a [Chainlink Automation Log Trigger](/chainlink-automation/guides/log-trigger) to check for events that require data. For this example, the log trigger comes from a simple emitter contract. Chainlink Automation then uses `StreamsLookup` to retrieve a signed report from the Data Streams Aggregation Network, return the data in a callback, and run the [`performUpkeep` function](/chainlink-automation/reference/automation-interfaces#performupkeep-function-for-log-triggers) on your registered upkeep contract. The `performUpkeep` function calls the `verify` function on the verifier contract.
-Note: To learn how to use the _[Streams Direct](/data-streams#streams-direct-using-data-streams-with-your-own-bot) implementation_ of Data Streams, see the [Fetch and decode reports via a REST API](/data-streams/tutorials/streams-direct/streams-direct-api) guide or the [Stream and decode reports via WebSocket](/data-streams/tutorials/streams-direct/streams-direct-ws) guide.
+Note: To learn how to use the _[Streams Direct](/data-streams/streams-direct) implementation_ of Data Streams, see the [Fetch and decode reports via a REST API](/data-streams/tutorials/streams-direct/streams-direct-api) guide or the [Stream and decode reports via WebSocket](/data-streams/tutorials/streams-direct/streams-direct-ws) guide.
diff --git a/src/features/data-streams/common/gettingStartedHardhat.mdx b/src/features/data-streams/common/gettingStartedHardhat.mdx
index 358945847dd..80665c030ec 100644
--- a/src/features/data-streams/common/gettingStartedHardhat.mdx
+++ b/src/features/data-streams/common/gettingStartedHardhat.mdx
@@ -3,9 +3,9 @@ import DataStreams from "@features/data-streams/common/DataStreams.astro"
This guide shows you how to read data from a Data Streams stream, verify the answer onchain, and store it.
-This example uses the _[Streams Trade](/data-streams#streams-trade-using-data-streams-with-chainlink-automation) implementation_, with a [Chainlink Automation Log Trigger](/chainlink-automation/guides/log-trigger) to check for events that require data. For this example, the log trigger comes from a simple emitter contract. Chainlink Automation then uses `StreamsLookup` to retrieve a signed report from the Data Streams Aggregation Network, return the data in a callback, and run the [`performUpkeep` function](/chainlink-automation/reference/automation-interfaces#performupkeep-function-for-log-triggers) on your registered upkeep contract. The `performUpkeep` function calls the `verify` function on the verifier contract.
+This example uses the _[Streams Trade](/data-streams/streams-trade) implementation_, with a [Chainlink Automation Log Trigger](/chainlink-automation/guides/log-trigger) to check for events that require data. For this example, the log trigger comes from a simple emitter contract. Chainlink Automation then uses `StreamsLookup` to retrieve a signed report from the Data Streams Aggregation Network, return the data in a callback, and run the [`performUpkeep` function](/chainlink-automation/reference/automation-interfaces#performupkeep-function-for-log-triggers) on your registered upkeep contract. The `performUpkeep` function calls the `verify` function on the verifier contract.
-Note: To learn how to use the _[Streams Direct](/data-streams#streams-direct-using-data-streams-with-your-own-bot) implementation_ of Data Streams, see the [Fetch and decode reports via a REST API](/data-streams/tutorials/streams-direct/streams-direct-api) guide or the [Stream and decode reports via WebSocket](/data-streams/tutorials/streams-direct/streams-direct-ws) guide.
+Note: To learn how to use the _[Streams Direct](/data-streams/streams-direct) implementation_ of Data Streams, see the [Fetch and decode reports via a REST API](/data-streams/tutorials/streams-direct/streams-direct-api) guide or the [Stream and decode reports via WebSocket](/data-streams/tutorials/streams-direct/streams-direct-ws) guide.
diff --git a/src/features/redirects/redirects.json b/src/features/redirects/redirects.json
index baf4779fb36..54c77209962 100644
--- a/src/features/redirects/redirects.json
+++ b/src/features/redirects/redirects.json
@@ -1989,6 +1989,26 @@
"source": "data-streams/tutorials/streams-direct/streams-direct-onchain-verification",
"destination": "data-streams/tutorials/streams-direct/evm-onchain-report-verification",
"statuscode": 301
+ },
+ {
+ "source": "data-streams/tutorials/streams-direct/streams-direct-api",
+ "destination": "data-streams/tutorials/streams-direct/streams-direct-api-go",
+ "statuscode": 301
+ },
+ {
+ "source": "data-streams/tutorials/streams-direct/streams-direct-api-rwa",
+ "destination": "data-streams/tutorials/streams-direct/streams-direct-api-rwa-go",
+ "statuscode": 301
+ },
+ {
+ "source": "data-streams/tutorials/streams-direct/streams-direct-ws",
+ "destination": "data-streams/tutorials/streams-direct/streams-direct-ws-go",
+ "statuscode": 301
+ },
+ {
+ "source": "data-streams/tutorials/streams-direct/streams-direct-ws-rwa",
+ "destination": "data-streams/tutorials/streams-direct/streams-direct-ws-rwa-go",
+ "statuscode": 301
}
]
}
diff --git a/vercel.json b/vercel.json
index a2620fb0e30..0e117eeaab5 100644
--- a/vercel.json
+++ b/vercel.json
@@ -436,6 +436,26 @@
"source": "data-streams/tutorials/streams-direct/streams-direct-onchain-verification",
"destination": "data-streams/tutorials/streams-direct/evm-onchain-report-verification",
"statusCode": 301
+ },
+ {
+ "source": "data-streams/tutorials/streams-direct/streams-direct-api",
+ "destination": "data-streams/tutorials/streams-direct/streams-direct-api-go",
+ "statusCode": 301
+ },
+ {
+ "source": "data-streams/tutorials/streams-direct/streams-direct-api-rwa",
+ "destination": "data-streams/tutorials/streams-direct/streams-direct-api-rwa-go",
+ "statusCode": 301
+ },
+ {
+ "source": "data-streams/tutorials/streams-direct/streams-direct-ws",
+ "destination": "data-streams/tutorials/streams-direct/streams-direct-ws-go",
+ "statusCode": 301
+ },
+ {
+ "source": "data-streams/tutorials/streams-direct/streams-direct-ws-rwa",
+ "destination": "data-streams/tutorials/streams-direct/streams-direct-ws-rwa-go",
+ "statusCode": 301
}
]
}
\ No newline at end of file