diff --git a/public/images/data-streams/data-streams-high-level-architecture.webp b/public/images/data-streams/data-streams-high-level-architecture.webp
new file mode 100644
index 00000000000..fcf0f3ec758
Binary files /dev/null and b/public/images/data-streams/data-streams-high-level-architecture.webp differ
diff --git a/src/components/ClickToZoom.astro b/src/components/ClickToZoom.astro
index affb6101c30..b3068bb8380 100644
--- a/src/components/ClickToZoom.astro
+++ b/src/components/ClickToZoom.astro
@@ -3,27 +3,46 @@ export type Props = {
src: string
alt?: string
style?: string
+ caption?: string
}
-const { src, alt, style } = Astro.props as Props
+const { src, alt, style, caption } = Astro.props as Props
/**
* This component adds the classNames required by the scripts/click-to-zoom.ts script.
*/
---
-
+
+
+ {caption &&
{caption}
}
+
diff --git a/src/components/CopyText.tsx b/src/components/CopyText.tsx
index c901b299409..a190e22bd7e 100644
--- a/src/components/CopyText.tsx
+++ b/src/components/CopyText.tsx
@@ -60,6 +60,7 @@ const CopyContainer = ({ text, code, format, formatType, eventName, additionalIn
text-overflow: ellipsis;
word-break: break-all;
margin-top: 0;
+ margin-bottom: 0 !important;
}
.copyBtn {
diff --git a/src/config/sidebar.ts b/src/config/sidebar.ts
index c284ba7838f..615b70eaa87 100644
--- a/src/config/sidebar.ts
+++ b/src/config/sidebar.ts
@@ -342,56 +342,38 @@ export const SIDEBAR: Partial> = {
],
},
{
- section: "Streams Trade",
- contents: [
- {
- 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",
+ section: "Tutorials",
contents: [
{
title: "Overview",
- url: "data-streams/streams-direct",
+ url: "data-streams/tutorials/overview",
},
{
title: "Fetch and decode reports",
- url: "data-streams/tutorials/streams-direct/streams-direct-api-go",
+ url: "data-streams/tutorials/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",
+ "data-streams/tutorials/api-rust",
+ "data-streams/tutorials/api-rwa-go",
+ "data-streams/tutorials/api-rwa-rust",
],
},
{
title: "Stream and decode reports (WebSocket)",
- url: "data-streams/tutorials/streams-direct/streams-direct-ws-go",
+ url: "data-streams/tutorials/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",
+ "data-streams/tutorials/ws-rust",
+ "data-streams/tutorials/ws-rwa-go",
+ "data-streams/tutorials/ws-rwa-rust",
],
},
{
title: "Verify report data (EVM)",
- url: "data-streams/tutorials/streams-direct/evm-onchain-report-verification",
+ url: "data-streams/tutorials/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"],
+ url: "data-streams/tutorials/solana-onchain-report-verification",
+ highlightAsCurrent: ["data-streams/tutorials/solana-offchain-report-verification"],
},
],
},
@@ -412,32 +394,70 @@ export const SIDEBAR: Partial> = {
section: "Reference",
contents: [
{
- title: "Streams Trade",
- url: "data-streams/reference/streams-trade-interface",
+ title: "Overview",
+ url: "data-streams/reference/overview",
+ },
+ {
+ title: "REST API",
+ url: "data-streams/reference/interface-api",
+ },
+ {
+ title: "WebSocket",
+ url: "data-streams/reference/interface-ws",
},
{
- title: "Streams Direct",
- url: "data-streams/reference/streams-direct",
+ title: "Authentication",
+ url: "data-streams/reference/authentication",
children: [
{
- title: "REST API",
- url: "data-streams/reference/streams-direct/streams-direct-interface-api",
+ title: "JavaScript examples",
+ url: "data-streams/reference/authentication/javascript-examples",
},
{
- title: "WebSocket",
- url: "data-streams/reference/streams-direct/streams-direct-interface-ws",
+ title: "TypeScript examples",
+ url: "data-streams/reference/authentication/typescript-examples",
},
{
- title: "SDK References",
- url: "data-streams/reference/streams-direct/streams-direct-go-sdk",
- highlightAsCurrent: ["data-streams/reference/streams-direct/streams-direct-rust-sdk"],
+ title: "Go examples",
+ url: "data-streams/reference/authentication/go-examples",
},
{
- title: "Onchain report verification (EVM chains)",
- url: "data-streams/reference/streams-direct/streams-direct-onchain-verification",
+ title: "Rust examples",
+ url: "data-streams/reference/authentication/rust-examples",
},
],
},
+ {
+ title: "SDK References",
+ url: "data-streams/reference/go-sdk",
+ highlightAsCurrent: ["data-streams/reference/rust-sdk"],
+ },
+ {
+ title: "Onchain report verification (EVM chains)",
+ url: "data-streams/reference/onchain-verification",
+ },
+ ],
+ },
+ {
+ section: "Streams Trade",
+ contents: [
+ {
+ title: "Overview",
+ url: "data-streams/streams-trade",
+ },
+ {
+ title: "Getting Started",
+ url: "data-streams/tutorials/streams-trade/getting-started",
+ highlightAsCurrent: ["data-streams/tutorials/streams-trade/getting-started-hardhat"],
+ },
+ {
+ title: "Handle StreamsLookup errors",
+ url: "data-streams/tutorials/streams-trade/streams-trade-lookup-error-handler",
+ },
+ {
+ title: "Reference (Interfaces)",
+ url: "data-streams/streams-trade/interfaces",
+ },
],
},
{
diff --git a/src/content/chainlink-automation/concepts/best-practice.mdx b/src/content/chainlink-automation/concepts/best-practice.mdx
index 7c7079c7323..9d4476c2560 100644
--- a/src/content/chainlink-automation/concepts/best-practice.mdx
+++ b/src/content/chainlink-automation/concepts/best-practice.mdx
@@ -36,7 +36,7 @@ If your upkeep performs **sensitive** functions in your protocol, consider using
### Verify Data Streams reports fetched with StreamsLookup
-If your upkeep uses [StreamsLookup](/chainlink-automation/reference/automation-interfaces#streamslookupcompatibleinterface), ensure you use the [verification interface](/data-streams/reference/interfaces) to verify your reports onchain.
+If your upkeep uses [StreamsLookup](/chainlink-automation/reference/automation-interfaces#streamslookupcompatibleinterface), ensure you use the [verification interface](/data-streams/streams-trade/interfaces) to verify your reports onchain.
### Avoid "flickering" custom logic upkeeps
diff --git a/src/content/data-streams/architecture.mdx b/src/content/data-streams/architecture.mdx
index abaa2d0b9b2..0e897432341 100644
--- a/src/content/data-streams/architecture.mdx
+++ b/src/content/data-streams/architecture.mdx
@@ -1,10 +1,16 @@
---
section: dataStreams
title: "Data Streams Architecture"
+metadata:
+ title: "Chainlink Data Streams Architecture | System Components and Data Flow"
+ description: "Learn about the architecture of Chainlink Data Streams, including its components, data flow, and the differences between standard API and Streams Trade implementations."
+ keywords: ["Data Streams", "Architecture", "Oracle Network", "DON", "Verification", "API", "Streams Trade"]
whatsnext:
{
- "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",
+ "Learn more about the Standard API Implementation": "/data-streams/tutorials/api-go",
+ "Learn more about the Streams Trade Implementation": "/data-streams/streams-trade",
+ "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",
}
---
@@ -13,21 +19,70 @@ import DataStreams from "@features/data-streams/common/DataStreams.astro"
+Chainlink Data Streams delivers low-latency market data offchain that you can verify onchain. This architecture uses a pull-based design, preserving trust-minimization with cryptographic verification while offering greater flexibility compared to traditional push-based oracle designs.
+
+Data Streams offers two implementation approaches to meet different needs:
+
+1. **Standard API Implementation**: The default implementation where applications directly retrieve report data through REST APIs or WebSocket connections and can verify this data onchain when needed.
+
+1. **Streams Trade Implementation**: An alternative implementation that combines Data Streams with Chainlink Automation for automated data retrieval and execution with frontrunning mitigation.
+
## High Level Architecture
Chainlink Data Streams has the following core components:
-- **A Chainlink Decentralized Oracle Network (DON):** This DON operates similarly to the DONs that power [Chainlink Data Feeds](/data-feeds), but the key difference is that it signs and delivers reports to the Chainlink Data Streams Aggregation Network rather than delivering answers onchain directly. This allows the Data Streams DON to deliver reports more frequently for time-sensitive applications. Nodes in the DON retrieve data from many different data providers, reach a consensus about the median price of an asset, sign a report including that data, and deliver the report to the Data Streams Aggregation Network.
-- **The Chainlink Data Streams Aggregation Network:** The Data Streams Aggregation Network stores the signed reports and makes them available for retrieval. The network uses an [active-active multi-site deployment](/data-streams/architecture#active-active-multi-site-deployment) to ensure high availability and robust fault tolerance by operating multiple active sites in parallel. The network delivers these reports to Chainlink Automation upon request ([Streams Trade](/data-streams/architecture#streams-trade-architecture)) or provide direct access via the API ([Streams Direct](/data-streams/architecture#streams-direct-architecture)).
+
+
+- **A Chainlink Decentralized Oracle Network (DON):** This DON operates similarly to the DONs that power [Chainlink Data Feeds](/data-feeds), but the key difference is that it signs and delivers reports to the Chainlink Data Streams Aggregation Network rather than delivering answers onchain directly. This allows the Data Streams DON to deliver reports more frequently for time-sensitive applications. Nodes in the DON retrieve data from many different data providers, reach a consensus about the data, sign a report including that data, and deliver the report to the Data Streams Aggregation Network.
+- **The Chainlink Data Streams Aggregation Network:** The Data Streams Aggregation Network stores the signed reports and makes them available for retrieval. The network uses an [active-active multi-site deployment](/data-streams/architecture#active-active-multi-site-deployment) to ensure high availability and robust fault tolerance by operating multiple active sites in parallel. The network delivers these reports directly via API for standard implementations or to Chainlink Automation upon request for [Streams Trade](/data-streams/architecture#streams-trade-architecture) implementations.
- **The Chainlink Verifier Contract:** This contract verifies the signature from the DON to cryptographically guarantee that the report has not been altered from the time that the DON reached consensus to the point where you use the data in your application.
+## Standard API Implementation Architecture
+
+The Standard API Implementation is the default way to access Chainlink Data Streams. It provides direct access to report data through REST APIs and WebSocket connections, giving you maximum flexibility in how and when you access market data.
+
+### Example of offchain price updates
+
+Data Streams enables seamless offchain price updates through a mechanism designed for real-time data delivery. Here is an example of how your Client will benefit from low-latency market data directly from the Data Streams Aggregation Network:
+
+1. The Client opens a WebSocket connection to the Data Streams Aggregation Network to subscribe to new reports with low latency.
+
+1. The Data Streams Aggregation Network streams price reports via WebSocket, which gives the Client instant access to updated market data.
+
+1. The Client stores the price reports in a cache for quick access and use, which preserves data integrity over time.
+
+1. The Client regularly queries the Data Streams Aggregation Network for any missed reports to ensure data completeness.
+
+1. The Aggregation Network sends back an array of reports to the Client.
+
+1. The Client updates its cache to backfill any missing reports, ensuring the data set remains complete and current.
+
+
+
+### Key benefits of the Standard API Implementation
+
+- **Maximum Flexibility**: Access data only when you need it, on your own terms
+- **Direct Integration**: Integrate directly with your systems using our SDKs or APIs
+- **Customized Usage**: Control exactly when and how data verification happens onchain
+- **Reduced Gas Costs**: Only pay for verification when absolutely necessary
+- **Real-time Access**: Get sub-second data latency through WebSocket subscriptions
+
## Streams Trade Architecture
-Using Chainlink Automation with Data Streams automates trade execution and mitigates frontrunning by executing the transaction before the data is recorded onchain. Chainlink Automation requests data from the Data Streams Aggregation Network. It executes transactions only in response to the data and the verified report, so the transaction is executed correctly and independently from the decentralized application itself.
+Streams Trade is an alternative implementation that combines Chainlink Data Streams with [Chainlink Automation](/chainlink-automation) to deliver automated trade execution with frontrunning mitigation. Using Chainlink Automation with Data Streams automates trade execution and mitigates frontrunning by executing the transaction before the data is recorded onchain. Chainlink Automation requests data from the Data Streams Aggregation Network. It executes transactions only in response to the data and the verified report, so the transaction is executed correctly and independently from the decentralized application itself.
### Example trading flow using Streams Trade
@@ -37,6 +92,7 @@ One example of how to use Data Streams with Automation is in a decentralized exc
1. A user initiates a trade by confirming an `initiateTrade` transaction in their wallet.
@@ -51,40 +107,22 @@ One example of how to use Data Streams with Automation is in a decentralized exc
This is one example of how you can combine Data Streams and Automation, but the systems are highly configurable. You can write your own log triggers or [custom logic triggers](/chainlink-automation/guides/register-upkeep) to initiate Automation upkeeps for a various array of events. You can configure the `StreamsLookup` to retrieve multiple reports. You can configure the `performUpkeep` function to perform a wide variety of actions using the report.
-Read the [Getting Started](/data-streams/getting-started) guide to learn how to build your own smart contract that retrieves reports from Data Streams using the Streams Trade implementation.
-
-**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).
-
-## Streams Direct Architecture
+### Key benefits of the Streams Trade Implementation
-
-
-### Example of offchain price updates with Streams Direct
-
-Streams Direct enables seamless offchain price updates through a mechanism designed for real-time data delivery. Here is an example of how your Client will benefit from low-latency market data directly from the Data Streams Aggregation Network.
-
-1. The Client opens a WebSocket connection to the Data Streams Aggregation Network to subscribe to new reports with low latency.
-
-1. The Data Streams Aggregation Network streams price reports via WebSocket, which gives the Client instant access to updated market data.
+- **Automated Execution**: No need to build execution logic - Automation handles it
+- **Frontrunning Protection**: Transaction data and price data revealed atomically onchain
+- **Trustless Design**: Fully decentralized solution with no centralized execution components
+- **Ease of Integration**: Built-in support for standard DeFi operations
-1. The Client stores the price reports in a cache for quick access and use, which preserves data integrity over time.
-
-1. The Client regularly queries the Data Streams Aggregation Network for any missed reports to ensure data completeness.
-
-1. The Aggregation Network sends back an array of reports to the Client.
-
-1. The Client updates its cache to backfill any missing reports, ensuring the data set remains complete and current.
+Read the [Getting Started](/data-streams/getting-started) guide to learn how to build your own smart contract that retrieves reports from Data Streams using the Streams Trade implementation.
-
+**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).
## Active-Active Multi-Site Deployment
Active-active is a system configuration strategy where redundant systems remain active simultaneously to serve requests. Incoming requests are distributed across all active resources and load-balanced to provide high availability, scalability, and fault tolerance. This strategy is the opposite of active-passive where a secondary system remains inactive until the primary system fails.
-The Data Streams API services use an active-active 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. This configuration applies to both the [REST API](/data-streams/reference/streams-direct/streams-direct-interface-api) and the [WebSocket API](/data-streams/reference/streams-direct/streams-direct-interface-ws). A global load balancer seamlessly manages the system to provide automated and transparent failovers. For advanced use cases, the service publishes available origins using HTTP headers, which enables you to interact directly with specific origin locations if necessary.
+The Data Streams API services use an active-active 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. This configuration applies to both the [REST API](/data-streams/reference/interface-api) and the [WebSocket API](/data-streams/reference/interface-ws). A global load balancer seamlessly manages the system to provide automated and transparent failovers. For advanced use cases, the service publishes available origins using HTTP headers, which enables you to interact directly with specific origin locations if necessary.
### Active-Active Setup
diff --git a/src/content/data-streams/billing.mdx b/src/content/data-streams/billing.mdx
index 9683e6b25db..644ccad29d8 100644
--- a/src/content/data-streams/billing.mdx
+++ b/src/content/data-streams/billing.mdx
@@ -2,6 +2,10 @@
section: dataStreams
title: "Data Streams Billing"
isIndex: false
+metadata:
+ title: "Chainlink Data Streams Billing | Pricing and Payment Options"
+ description: "Learn about Chainlink Data Streams billing models, including pay-per-report verification and subscription options, with payment support for LINK and alternative assets."
+ keywords: ["Data Streams", "Billing", "Pricing", "Oracle Payment", "Verification Fee"]
whatsnext:
{
"Learn the basics about how to retrieve Data Streams reports in the Getting Started guide.": "/data-streams/getting-started",
diff --git a/src/content/data-streams/concepts/liquidity-weighted-prices.mdx b/src/content/data-streams/concepts/liquidity-weighted-prices.mdx
index 7c8243e0465..8723ab080b1 100644
--- a/src/content/data-streams/concepts/liquidity-weighted-prices.mdx
+++ b/src/content/data-streams/concepts/liquidity-weighted-prices.mdx
@@ -1,6 +1,10 @@
---
section: dataStreams
title: "Data Streams Liquidity-Weighted Bid-Ask Prices (LWBA)"
+metadata:
+ title: "Liquidity-Weighted Bid-Ask Prices (LWBA) | Chainlink Data Streams"
+ description: "Learn how Liquidity-Weighted Bid-Ask (LWBA) prices work in Chainlink Data Streams and how they provide deeper market insights compared to standard mid prices."
+ keywords: ["LWBA", "Liquidity-Weighted", "Bid-Ask", "Price Spread", "Market Depth", "Order Book", "Data Streams"]
whatsnext:
{
"Find the list of available Stream IDs.": "/data-streams/crypto-streams",
diff --git a/src/content/data-streams/developer-responsibilities.mdx b/src/content/data-streams/developer-responsibilities.mdx
index ac5b7027609..109e1d94644 100644
--- a/src/content/data-streams/developer-responsibilities.mdx
+++ b/src/content/data-streams/developer-responsibilities.mdx
@@ -1,12 +1,16 @@
---
section: dataStreams
title: "Developer Responsibilities: Market Integrity and Application Code Risks"
+metadata:
+ title: "Developer Responsibilities for Chainlink Data Streams | Risk Management"
+ description: "Learn about developer responsibilities when integrating Chainlink Data Streams, including managing market integrity risks and application code safety."
+ keywords: ["Developer Responsibilities", "Market Integrity", "Risk Management", "Data Streams", "Integration Safety"]
whatsnext:
{
"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",
"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 fetch and decode Data Streams reports using the Data Streams API": "/data-streams/tutorials/api-go",
}
---
@@ -79,9 +83,9 @@ Developers implementing Chainlink Data Streams are solely responsible for instit
- **Code and application audits:** Developers are responsible for auditing their code and applications before deploying to production. Developers must determine the quality of any audits and ensure that they meet the requirements for their application.
- **Code dependencies and imports:** Developers are responsible for ensuring the quality, reliability, and security of any dependencies or imported packages that they use with Chainlink Data Streams, and review and audit these dependencies and packages.
- **Implementing Contingency Logic:** In extreme circumstances, including situations beyond the control of Chainlink node operators, Chainlink Data Streams may experience periods of unavailability or performance degradation. When a WebSocket connection is dropped, user systems must manage reconnections effectively. Developers are responsible for creating contingency plans tailored to their specific application needs, such as:
- - Implementing the [Streams Direct Architecture](/data-streams/architecture#streams-direct-architecture),
- - Adopting an [active-active](/data-streams/architecture#active-active-multi-site-deployment) deployment strategy and [configuring the SDK](/data-streams/reference/streams-direct/streams-direct-go-sdk#config-struct) to support multiple concurrent WebSocket connections,
- - Retrieving any potentially missing reports via the [REST API](/data-streams/reference/streams-direct/streams-direct-interface-api).
+ - Implementing the [Data Streams Architecture](/data-streams/architecture),
+ - Adopting an [active-active](/data-streams/architecture#active-active-multi-site-deployment) deployment strategy and [configuring the SDK](/data-streams/reference/go-sdk#config-struct) to support multiple concurrent WebSocket connections,
+ - Retrieving any potentially missing reports via the [REST API](/data-streams/reference/interface-api).
### Additional Considerations on Data Usage and Verification
diff --git a/src/content/data-streams/index.mdx b/src/content/data-streams/index.mdx
index 17143a5474e..89392d9487f 100644
--- a/src/content/data-streams/index.mdx
+++ b/src/content/data-streams/index.mdx
@@ -2,10 +2,13 @@
section: dataStreams
title: "Chainlink Data Streams"
isIndex: true
+metadata:
+ title: "Chainlink Data Streams | Low-Latency, High-Frequency Market Data"
+ description: "Access high-frequency, low-latency market data offchain that can be cryptographically verified onchain for decentralized applications and DeFi protocols."
+ keywords: ["Chainlink", "Data Streams", "Oracle", "DeFi", "Market Data", "Low Latency", "High Frequency"]
whatsnext:
{
- "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",
+ "Learn how to fetch and decode Data Streams reports with the API": "/data-streams/tutorials/api-go",
"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",
}
@@ -22,7 +25,7 @@ Traditional push-based oracles update onchain data at set intervals or when cert
## 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.
+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 onchain.
## Comparison to push-based oracles
@@ -31,6 +34,7 @@ Chainlink's push-based oracles regularly publish price data onchain. By contrast
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.
@@ -43,7 +47,7 @@ Chainlink Data Streams offers price points such as mid prices and [Liquidity-Wei
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
+## Example use cases
Access to low-latency, high-frequency data enables a variety of onchain applications:
@@ -51,16 +55,44 @@ Access to low-latency, high-frequency data enables a variety of onchain applicat
- **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
+## Key capabilities
-### Streams Trade
+- **Sub-second Latency:** Pull data on-demand with minimal delay
+- **Cryptographic Verification:** Verify data authenticity onchain when needed
+- **Multiple Access Methods:** REST API, WebSocket, or SDK integration
+- **Comprehensive Market Data:** Mid prices, LWBA prices, volatility, and liquidity metrics
+- **High Availability:** Multi-site deployment ensures 99.9%+ uptime
-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.
+## How to use Data Streams
-[Learn more about Streams Trade](/data-streams/streams-trade)
+You can access Chainlink Data Streams through SDKs and APIs, allowing you to build custom solutions with low-latency, high-frequency data. Fetch reports or subscribe to report updates from the Data Streams Aggregation Network and verify their authenticity onchain.
-### Streams Direct
+
+
+### Integration options
+
+Access data directly through REST APIs or WebSocket connections using our SDKs:
+
+- **[Go SDK](/data-streams/reference/go-sdk)** - Full-featured SDK with comprehensive examples
+- **[Rust SDK](/data-streams/reference/rust-sdk)** - High-performance SDK for Rust applications
+- **[REST API](/data-streams/reference/interface-api)** or **[WebSocket](/data-streams/reference/interface-ws)** - Direct access to Data Streams endpoints
+
+### Getting started
+
+1. Understand the Architecture: Review the [system components and data flow](/data-streams/architecture) to understand how Data Streams works.
+
+1. Explore Available Data: Browse [available Stream IDs](/data-streams/crypto-streams) and [report schemas](/data-streams/reference/report-schema) to see what data is available.
+
+1. Try the API: Follow our [hands-on tutorial](/data-streams/tutorials/api-go) to fetch and decode your first report.
+
+1. Implement Verification: Add [onchain verification](/data-streams/reference/onchain-verification) to ensure data authenticity in your smart contracts.
+
+### Streams Trade: An alternative implementation
-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.
+For applications that require automated data retrieval and execution, Streams Trade combines Chainlink Data Streams with [Chainlink Automation](/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.
-[Learn more about Streams Direct](/data-streams/streams-direct)
+[Learn more about Streams Trade](/data-streams/streams-trade).
diff --git a/src/content/data-streams/market-hours.mdx b/src/content/data-streams/market-hours.mdx
index 60873ef3aa3..d09b8759d20 100644
--- a/src/content/data-streams/market-hours.mdx
+++ b/src/content/data-streams/market-hours.mdx
@@ -2,6 +2,10 @@
section: dataStreams
date: Last Modified
title: "Data Streams Market Hours"
+metadata:
+ title: "Chainlink Data Streams Market Hours | Trading Hours by Asset Class"
+ description: "Learn about trading hours for different asset classes in Chainlink Data Streams including cryptocurrency, forex, and precious metals market schedules."
+ keywords: ["Market Hours", "Trading Hours", "Crypto", "Forex", "Precious Metals", "Data Streams"]
whatsnext:
{
"Find the list of available Crypto streams": "/data-streams/crypto-streams",
diff --git a/src/content/data-streams/reference/authentication/go-examples.mdx b/src/content/data-streams/reference/authentication/go-examples.mdx
new file mode 100644
index 00000000000..13b9b6a54de
--- /dev/null
+++ b/src/content/data-streams/reference/authentication/go-examples.mdx
@@ -0,0 +1,511 @@
+---
+section: dataStreams
+date: Last Modified
+title: "API Authentication - Go examples"
+metadata:
+ title: "Data Streams API Authentication - Go examples"
+ description: "Learn how to authenticate with the Data Streams API using Go"
+ keywords: ["Data Streams", "API", "Authentication", "Go"]
+---
+
+import { Aside, CopyText } from "@components"
+import DataStreams from "@features/data-streams/common/DataStreams.astro"
+
+
+
+Below are complete examples for authenticating with the Data Streams API in Go. Each example shows how to properly generate the required headers and make a request.
+
+To learn more about the Data Streams API authentication, see the [Data Streams Authentication](/data-streams/reference/authentication) page.
+
+**Note**: The Data Streams SDKs handle authentication automatically. If you're using the [Go SDK](/data-streams/reference/go-sdk) or [Rust SDK](/data-streams/reference/rust-sdk), you don't need to implement the authentication logic manually.
+
+## API Authentication Example
+
+
+
+### Requirements
+
+- [Go](https://go.dev/doc/install) (v1.18 or later recommended)
+- API credentials from Chainlink Data Streams
+
+### Running the Example
+
+1. Create a file named with the example code shown below
+1. Set your API credentials as environment variables:
+ ```bash
+ export STREAMS_API_KEY="your-api-key"
+ export STREAMS_API_SECRET="your-api-secret"
+ ```
+1. Run with
+
+**Example code**:
+
+```go
+package main
+
+import (
+ "context"
+ "crypto/hmac"
+ "crypto/sha256"
+ "encoding/hex"
+ "encoding/json"
+ "fmt"
+ "io"
+ "log"
+ "net/http"
+ "net/url"
+ "os"
+ "strconv"
+ "time"
+)
+
+// SingleReport represents a data feed report structure
+type SingleReport struct {
+ FeedID string `json:"feedID"`
+ ValidFromTimestamp uint32 `json:"validFromTimestamp"`
+ ObservationsTimestamp uint32 `json:"observationsTimestamp"`
+ FullReport string `json:"fullReport"`
+}
+
+// SingleReportResponse is the response structure for a single report
+type SingleReportResponse struct {
+ Report SingleReport `json:"report"`
+}
+
+// GenerateHMAC creates the signature for authentication
+func GenerateHMAC(method string, path string, body []byte, apiKey string, apiSecret string) (string, int64) {
+ // Generate timestamp (milliseconds since Unix epoch)
+ timestamp := time.Now().UTC().UnixMilli()
+
+ // Generate body hash
+ serverBodyHash := sha256.New()
+ serverBodyHash.Write(body)
+ bodyHashString := hex.EncodeToString(serverBodyHash.Sum(nil))
+
+ // Create string to sign
+ stringToSign := fmt.Sprintf("%s %s %s %s %d",
+ method,
+ path,
+ bodyHashString,
+ apiKey,
+ timestamp)
+
+ // Generate HMAC-SHA256 signature
+ signedMessage := hmac.New(sha256.New, []byte(apiSecret))
+ signedMessage.Write([]byte(stringToSign))
+ signature := hex.EncodeToString(signedMessage.Sum(nil))
+
+ return signature, timestamp
+}
+
+// GenerateAuthHeaders creates HTTP headers with authentication information
+func GenerateAuthHeaders(method string, pathWithParams string, apiKey string, apiSecret string) http.Header {
+ header := http.Header{}
+ signature, timestamp := GenerateHMAC(method, pathWithParams, []byte(""), apiKey, apiSecret)
+
+ header.Add("Authorization", apiKey)
+ header.Add("X-Authorization-Timestamp", strconv.FormatInt(timestamp, 10))
+ header.Add("X-Authorization-Signature-SHA256", signature)
+
+ return header
+}
+
+// FetchSingleReport retrieves a single report for a specific feed
+func FetchSingleReport(ctx context.Context, feedID string) (*SingleReport, error) {
+ // Get API credentials from environment variables
+ apiKey := os.Getenv("STREAMS_API_KEY")
+ apiSecret := os.Getenv("STREAMS_API_SECRET")
+
+ // Validate credentials
+ if apiKey == "" || apiSecret == "" {
+ return nil, fmt.Errorf("API credentials not set. Please set STREAMS_API_KEY and STREAMS_API_SECRET environment variables")
+ }
+
+ // API connection details
+ host := "api.testnet-dataengine.chain.link"
+ path := "/api/v1/reports/latest"
+
+ // Build query parameters
+ params := url.Values{
+ "feedID": {feedID},
+ }
+
+ // Create the request URL
+ reqURL := &url.URL{
+ Scheme: "https",
+ Host: host,
+ Path: path,
+ RawQuery: params.Encode(),
+ }
+
+ // Create the HTTP request
+ req, err := http.NewRequestWithContext(ctx, http.MethodGet, reqURL.String(), nil)
+ if err != nil {
+ return nil, fmt.Errorf("error creating request: %w", err)
+ }
+
+ // Add authentication headers
+ req.Header = GenerateAuthHeaders(req.Method, req.URL.RequestURI(), apiKey, apiSecret)
+
+ // Execute the request
+ client := &http.Client{}
+ resp, err := client.Do(req)
+ if err != nil {
+ return nil, fmt.Errorf("error sending request: %w", err)
+ }
+ defer resp.Body.Close()
+
+ // Read the response body
+ body, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return nil, fmt.Errorf("error reading response: %w", err)
+ }
+
+ // Check for non-success status code
+ if resp.StatusCode != http.StatusOK {
+ return nil, fmt.Errorf("API error (status code %d): %s", resp.StatusCode, string(body))
+ }
+
+ // Parse the response
+ var reportResp SingleReportResponse
+ if err := json.Unmarshal(body, &reportResp); err != nil {
+ return nil, fmt.Errorf("error parsing response: %w", err)
+ }
+
+ return &reportResp.Report, nil
+}
+
+func main() {
+ // Create a context with cancellation
+ ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
+ defer cancel()
+
+ // Example feed ID (ETH/USD)
+ feedID := "0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782"
+
+ fmt.Printf("Fetching latest report for feed ID: %s\n", feedID)
+
+ // Fetch the report
+ report, err := FetchSingleReport(ctx, feedID)
+ if err != nil {
+ log.Fatalf("Error: %v", err)
+ }
+
+ // Display the report
+ fmt.Println("Successfully retrieved report:")
+ fmt.Printf(" Feed ID: %s\n", report.FeedID)
+ fmt.Printf(" Valid From: %d\n", report.ValidFromTimestamp)
+ fmt.Printf(" Observations Timestamp: %d\n", report.ObservationsTimestamp)
+ fmt.Printf(" Full Report: %s\n", report.FullReport)
+}
+```
+
+**Expected output**:
+
+```bash
+Fetching latest report for feed ID: 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782
+Successfully retrieved report:
+ Feed ID: 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782
+ Valid From: 1747921357
+ Observations Timestamp: 1747921357
+ Full Report: 0x00090d9e8d96765a0c49e03a6ae05c[...]bffd8feddabf120e14bf
+```
+
+### Production Considerations
+
+While this example demonstrates the authentication mechanism, production applications should consider:
+
+- **HTTP client reuse**: Create a single `http.Client` with timeout settings and reuse it
+- **Retry logic**: Implement exponential backoff for transient failures
+- **Structured logging**: Use a logging library like `zap` or `logrus` instead of `fmt.Printf`
+- **Configuration**: Use a configuration library like `viper` for managing settings
+- **Metrics**: Add instrumentation for monitoring API call performance
+- **Error types**: Define custom error types for better error handling
+- **Testing**: Add unit tests for HMAC generation and integration tests
+
+For production use, consider using the [Go SDK](/data-streams/reference/go-sdk) which handles authentication automatically and provides built-in fault tolerance.
+
+## WebSocket Authentication Example
+
+
+
+### Requirements
+
+- [Go](https://go.dev/doc/install) (v1.18 or later recommended)
+- API credentials from Chainlink Data Streams
+
+### Running the Example
+
+1. Create a new directory for the example:
+
+ ```bash
+ mkdir ws-go-example && cd ws-go-example
+ ```
+
+1. Initialize a Go module:
+
+ ```bash
+ go mod init ws-example
+ ```
+
+1. Create a file named with the example code shown below
+
+1. Set your API credentials as environment variables:
+ ```bash
+ export STREAMS_API_KEY="your-api-key"
+ export STREAMS_API_SECRET="your-api-secret"
+ ```
+1. Install the required dependencies:
+
+ ```bash
+ go mod tidy
+ ```
+
+1. Run the example
+
+ ```bash
+ go run ws-auth-example.go
+ ```
+
+1. Press Ctrl+C to stop the WebSocket stream when you're done
+
+**Example code**:
+
+```go
+package main
+
+import (
+ "context"
+ "crypto/hmac"
+ "crypto/sha256"
+ "encoding/hex"
+ "encoding/json"
+ "fmt"
+ "log"
+ "net/http"
+ "os"
+ "os/signal"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/gorilla/websocket"
+)
+
+// Constants for ping interval, pong timeout, and write timeout
+const (
+ pingInterval = 5 * time.Second
+ pongTimeout = 10 * time.Second
+ writeTimeout = 5 * time.Second
+)
+
+// FeedReport represents the data structure received from the WebSocket
+type FeedReport struct {
+ Report struct {
+ FeedID string `json:"feedID"`
+ FullReport string `json:"fullReport"`
+ } `json:"report"`
+}
+
+// GenerateHMAC creates the signature for authentication
+func GenerateHMAC(method, path string, apiKey string, apiSecret string) (string, int64) {
+ // Generate timestamp (milliseconds since Unix epoch)
+ timestamp := time.Now().UTC().UnixMilli()
+
+ // Generate body hash (empty for this connection)
+ serverBodyHash := sha256.New()
+ bodyHashString := hex.EncodeToString(serverBodyHash.Sum(nil))
+
+ // Create string to sign
+ stringToSign := fmt.Sprintf("%s %s %s %s %d",
+ method,
+ path,
+ bodyHashString,
+ apiKey,
+ timestamp)
+
+ // Generate HMAC-SHA256 signature
+ signedMessage := hmac.New(sha256.New, []byte(apiSecret))
+ signedMessage.Write([]byte(stringToSign))
+ signature := hex.EncodeToString(signedMessage.Sum(nil))
+
+ return signature, timestamp
+}
+
+// pingLoop sends periodic pings to keep the connection alive
+func pingLoop(ctx context.Context, conn *websocket.Conn) {
+ ticker := time.NewTicker(pingInterval)
+ defer ticker.Stop()
+
+ for {
+ select {
+ case <-ctx.Done():
+ return
+ case <-ticker.C:
+ log.Println("Sending ping to keep connection alive...")
+ if err := conn.WriteControl(websocket.PingMessage, []byte{}, time.Now().Add(writeTimeout)); err != nil {
+ log.Printf("Error sending ping: %v", err)
+ return
+ }
+ }
+ }
+}
+
+func main() {
+ // Get API credentials from environment variables
+ apiKey := os.Getenv("STREAMS_API_KEY")
+ apiSecret := os.Getenv("STREAMS_API_SECRET")
+
+ // Validate credentials
+ if apiKey == "" || apiSecret == "" {
+ log.Fatal("API credentials not set. Please set STREAMS_API_KEY and STREAMS_API_SECRET environment variables")
+ }
+
+ // WebSocket connection details
+ host := "ws.testnet-dataengine.chain.link"
+ path := "/api/v1/ws"
+ feedIDs := []string{"0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782"} // ETH/USD
+
+ // Validate feed IDs
+ if len(feedIDs) == 0 {
+ log.Fatal("No feed ID(s) provided")
+ }
+
+ queryParams := fmt.Sprintf("feedIDs=%s", strings.Join(feedIDs, ","))
+ fullPath := fmt.Sprintf("%s?%s", path, queryParams)
+
+ // Generate authentication signature and timestamp
+ signature, timestamp := GenerateHMAC("GET", fullPath, apiKey, apiSecret)
+
+ // Create HTTP header for WebSocket connection
+ header := http.Header{}
+ header.Add("Authorization", apiKey)
+ header.Add("X-Authorization-Timestamp", strconv.FormatInt(timestamp, 10))
+ header.Add("X-Authorization-Signature-SHA256", signature)
+
+ // Create WebSocket URL
+ wsURL := fmt.Sprintf("wss://%s%s?%s", host, path, queryParams)
+ fmt.Println("Connecting to:", wsURL)
+
+ // Create context for handling cancellation
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+
+ // Set up channel to handle interrupt signal
+ interrupt := make(chan os.Signal, 1)
+ signal.Notify(interrupt, os.Interrupt)
+
+ // Connect to WebSocket server
+ conn, resp, err := websocket.DefaultDialer.DialContext(ctx, wsURL, header)
+ if err != nil {
+ if resp != nil {
+ log.Fatalf("WebSocket connection error (HTTP %d): %v", resp.StatusCode, err)
+ } else {
+ log.Fatalf("WebSocket connection error: %v", err)
+ }
+ }
+ defer conn.Close()
+
+ // Add pong handler to reset read deadline when pong is received
+ conn.SetPongHandler(func(string) error {
+ log.Println("Received pong from server")
+ return conn.SetReadDeadline(time.Now().Add(pongTimeout))
+ })
+
+ // Start the ping loop in a separate goroutine
+ go pingLoop(ctx, conn)
+
+ // Set initial read deadline
+ err = conn.SetReadDeadline(time.Now().Add(pongTimeout))
+ if err != nil {
+ log.Fatalf("Error setting read deadline: %v", err)
+ }
+
+ fmt.Println("WebSocket connection established")
+
+ // Create channel for done signal
+ done := make(chan struct{})
+
+ // Handle incoming messages in a separate goroutine
+ go func() {
+ defer close(done)
+
+ for {
+ _, message, err := conn.ReadMessage()
+ if err != nil {
+ log.Printf("WebSocket read error: %v", err)
+ return
+ }
+
+ // Parse the message
+ var report FeedReport
+ if err := json.Unmarshal(message, &report); err != nil {
+ log.Printf("Error parsing message: %v", err)
+ fmt.Println("Raw message:", string(message))
+ continue
+ }
+
+ fmt.Printf("Received report for Feed ID: %s\n", report.Report.FeedID)
+ }
+ }()
+
+ // Wait for interrupt signal or error
+ for {
+ select {
+ case <-done:
+ return
+ case <-interrupt:
+ fmt.Println("\nInterrupt signal received, closing connection...")
+
+ // Close the WebSocket connection gracefully
+ err := conn.WriteControl(
+ websocket.CloseMessage,
+ websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""),
+ time.Now().Add(time.Second),
+ )
+ if err != nil {
+ log.Printf("Error sending close message: %v", err)
+ }
+
+ // Wait for message handling to complete or timeout
+ select {
+ case <-done:
+ case <-time.After(time.Second):
+ }
+ return
+ }
+ }
+}
+```
+
+**Expected output**:
+
+```bash
+Connecting to: wss://ws.testnet-dataengine.chain.link/api/v1/ws?feedIDs=0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782
+WebSocket connection established
+Received report for Feed ID: 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782
+Received report for Feed ID: 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782
+Received report for Feed ID: 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782
+Received report for Feed ID: 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782
+Received report for Feed ID: 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782
+Received report for Feed ID: 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782
+2025/05/22 08:34:20 Sending ping to keep connection alive...
+2025/05/22 08:34:20 Received pong from server
+Received report for Feed ID: 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782
+Received report for Feed ID: 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782
+```
+
+### Production Considerations
+
+While this example already includes many production-ready features (keepalive, timeouts, graceful shutdown), production applications should additionally consider:
+
+- **Automatic reconnection**: Implement exponential backoff reconnection logic for network disruptions
+- **Message buffering**: Queue outgoing messages during reconnection attempts
+- **Structured logging**: Use `zap` or `logrus` with log levels instead of `log.Printf`
+- **Metrics collection**: Track connection status, message rates, and latency
+- **Configuration management**: Make timeouts and intervals configurable via environment or config files
+- **Error categorization**: Define custom error types to distinguish between retriable and fatal errors
+- **Health checks**: Expose WebSocket connection status for monitoring systems
+- **Testing**: Add unit tests for HMAC generation and mock WebSocket server for integration tests
+
+For production use, consider using the [Go SDK](/data-streams/reference/go-sdk) which handles authentication automatically and provides built-in fault tolerance for streaming connections.
diff --git a/src/content/data-streams/reference/authentication/index.mdx b/src/content/data-streams/reference/authentication/index.mdx
new file mode 100644
index 00000000000..dbc96df440d
--- /dev/null
+++ b/src/content/data-streams/reference/authentication/index.mdx
@@ -0,0 +1,160 @@
+---
+section: dataStreams
+date: Last Modified
+title: "Data Streams Authentication"
+metadata:
+ title: "Data Streams Authentication Guide | Chainlink Documentation"
+ description: "Learn how to authenticate with Chainlink Data Streams APIs using HMAC signatures for both REST API and WebSocket connections with examples in multiple languages."
+ keywords: ["Authentication", "HMAC", "API Key", "API Secret", "Signature", "Security", "Data Streams"]
+whatsnext:
+ {
+ "Learn about the REST API Interface": "/data-streams/reference/interface-api",
+ "Learn about the WebSocket Interface": "/data-streams/reference/interface-ws",
+ "Explore the Go SDK": "/data-streams/reference/go-sdk",
+ "Explore the Rust SDK": "/data-streams/reference/rust-sdk",
+ }
+isIndex: true
+---
+
+import { Aside, CopyText } from "@components"
+import DataStreams from "@features/data-streams/common/DataStreams.astro"
+import { Tabs } from "@components/Tabs"
+
+
+
+This page explains how to authenticate with the Chainlink Data Streams API, covering both REST API and WebSocket connections. It includes detailed information about the required authentication headers, how to generate an HMAC signature, and examples in multiple programming languages.
+
+
+
+## Authentication Requirements
+
+All requests to the Data Streams API (both REST and WebSocket) require three authentication headers:
+
+| Header | Description |
+| ---------------------------------- | -------------------------------------------- |
+| `Authorization` | Your API key (UUID format) |
+| `X-Authorization-Timestamp` | Current timestamp with millisecond precision |
+| `X-Authorization-Signature-SHA256` | HMAC signature generated using SHA-256 |
+
+These headers authenticate your request and ensure data integrity.
+
+### Authorization Header
+
+The `Authorization` header contains your API key, which is provided to you when you sign up for Chainlink Data Streams access. It follows this format:
+
+```
+Authorization: YOUR_API_KEY
+```
+
+Your API key is a UUID string that identifies your account. Keep it secure and do not share it publicly.
+
+### X-Authorization-Timestamp Header
+
+The `X-Authorization-Timestamp` header contains the current timestamp in milliseconds since the Unix epoch (January 1, 1970, 00:00:00 UTC). It follows this format:
+
+```
+X-Authorization-Timestamp: 1716211845123
+```
+
+The timestamp must be within 5 seconds of the server time to prevent replay attacks. This means your system clock must be synchronized with a reliable time source.
+
+### X-Authorization-Signature-SHA256 Header
+
+The `X-Authorization-Signature-SHA256` header contains the HMAC-SHA256 signature of your request. It's created using your API secret (provided along with your API key) and follows this format:
+
+```
+X-Authorization-Signature-SHA256: YOUR_HMAC_SIGNATURE
+```
+
+## Generating the HMAC Signature
+
+To generate the HMAC signature correctly:
+
+1. **Create the string to sign:**
+
+ - For REST API: Combine the HTTP method, endpoint path with query parameters, body hash, API key, and timestamp
+ - For WebSocket: Same format as REST API requests, using `GET` as the method
+
+1. **Generate the signature:**
+ - Use HMAC-SHA256 algorithm with your API secret as the key
+ - Sign the string created in step 1
+ - Hex encode the resulting binary hash
+
+### String to Sign Format
+
+The string to sign follows this format (for both REST API and WebSocket connections):
+
+```
+METHOD FULL_PATH BODY_HASH API_KEY TIMESTAMP
+```
+
+Where:
+
+- `METHOD`: The HTTP method in uppercase (e.g., `GET`, `POST`) (use `GET` for WebSocket connections)
+- `FULL_PATH`: The endpoint path including query parameters (e.g., `/api/v1/reports/latest?feedID=0x123...`)
+- `BODY_HASH`: SHA-256 hash of the request body, hex encoded (use empty string hash for GET requests or WebSocket connections)
+- `API_KEY`: Your API key (same as in the `Authorization` header)
+- `TIMESTAMP`: The timestamp in milliseconds since the Unix epoch (same as in the `X-Authorization-Timestamp` header)
+
+Note that the elements are joined with a single space character, not newlines.
+
+#### Body Hash Calculation
+
+Even for GET requests and WebSocket connections, you need to include a body hash in the string to sign:
+
+1. Calculate the SHA-256 hash of the request body (for GET requests or WebSocket connections, use an empty string)
+1. Hex encode the resulting hash
+1. Include this hex-encoded hash in the string to sign
+
+## Authentication Examples
+
+Below are complete examples for authenticating with the Data Streams API in various languages. Each example shows how to properly generate the required headers and make a request.
+
+- [JavaScript examples](/data-streams/reference/authentication/javascript-examples)
+- [TypeScript examples](/data-streams/reference/authentication/typescript-examples)
+- [Go examples](/data-streams/reference/authentication/go-examples)
+- [Rust examples](/data-streams/reference/authentication/rust-examples)
+
+## Common Authentication Errors
+
+When working with the Data Streams API, the most common authentication issues include:
+
+- **Signature Mismatch**: The HMAC signature generated by your client doesn't match what the server expects, often due to incorrect string-to-sign format or hash encoding
+- **Timestamp Issues**: Your system time isn't synchronized with the server (must be within 5 seconds)
+- **Missing or Malformed Headers**: Required authentication headers are missing or have incorrect format
+- **Insufficient Permissions**: Your API key doesn't have access to the requested feed ID
+
+For complete information on all possible error responses:
+
+- [REST API Error Response Codes](/data-streams/reference/interface-api#error-response-codes)
+- [WebSocket Error Response Codes](/data-streams/reference/interface-ws#error-response-codes)
+
+## Troubleshooting Authentication
+
+If you're experiencing authentication issues, follow these steps:
+
+1. **Check your API credentials**:
+
+ - Verify you're using the correct API key and secret
+ - Ensure there are no extra spaces or special characters
+
+1. **Verify timestamp synchronization**:
+
+ - Check if your system clock is accurate
+ - Consider using Network Time Protocol (NTP) to synchronize your clock
+
+1. **Inspect your signature calculation**:
+
+ - Verify the string to sign follows the exact format shown above
+ - Check that you're using HMAC-SHA256 (not just SHA-256)
+ - Ensure you're hex encoding the binary hash output (not Base64)
+
+1. **Debug output**:
+
+ - Print out the exact string being signed (without the API secret)
+ - Compare timestamps between your system and a reliable time source
+ - Check if all required headers are correctly formatted
diff --git a/src/content/data-streams/reference/authentication/javascript-examples.mdx b/src/content/data-streams/reference/authentication/javascript-examples.mdx
new file mode 100644
index 00000000000..f0b5384435d
--- /dev/null
+++ b/src/content/data-streams/reference/authentication/javascript-examples.mdx
@@ -0,0 +1,532 @@
+---
+section: dataStreams
+date: Last Modified
+title: "API Authentication - JavaScript examples"
+metadata:
+ title: "Data Streams API Authentication - JavaScript examples"
+ description: "Learn how to authenticate with the Data Streams API using JavaScript"
+ keywords: ["Data Streams", "API", "Authentication", "JavaScript"]
+---
+
+import { Aside, CopyText } from "@components"
+import DataStreams from "@features/data-streams/common/DataStreams.astro"
+
+
+
+Below are complete examples for authenticating with the Data Streams API in JavaScript, using Node.js. Each example shows how to properly generate the required headers and make a request.
+
+To learn more about the Data Streams API authentication, see the [Data Streams Authentication](/data-streams/reference/authentication) page.
+
+**Note**: The Data Streams SDKs handle authentication automatically. If you're using the [Go SDK](/data-streams/reference/go-sdk) or [Rust SDK](/data-streams/reference/rust-sdk), you don't need to implement the authentication logic manually.
+
+## API Authentication Example
+
+
+
+### Prerequisites
+
+- [Node.js](https://nodejs.org/en/download/) (v20 or later)
+- API credentials from Chainlink Data Streams
+
+### Running the Example
+
+1. Create a file named with the example code shown below
+1. Set your API credentials as environment variables:
+ ```bash
+ export STREAMS_API_KEY="your-api-key"
+ export STREAMS_API_SECRET="your-api-secret"
+ ```
+1. Run the example:
+ ```bash
+ node auth-example.js
+ ```
+
+**Example code**:
+
+```javascript
+const crypto = require("crypto")
+const https = require("https")
+const { promisify } = require("util")
+
+/**
+ * SingleReport represents a data feed report structure
+ * @typedef {Object} SingleReport
+ * @property {string} feedID - Feed identifier
+ * @property {number} validFromTimestamp - Timestamp from which the report is valid
+ * @property {number} observationsTimestamp - Timestamp of the observations
+ * @property {string} fullReport - Full report data in hex format
+ */
+
+/**
+ * SingleReportResponse is the response structure for a single report
+ * @typedef {Object} SingleReportResponse
+ * @property {SingleReport} report - Report data
+ */
+
+/**
+ * Generates HMAC signature for API authentication
+ * @param {string} method - HTTP method (GET, POST, etc.)
+ * @param {string} path - Request path including query parameters
+ * @param {Buffer|string} body - Request body (empty string for GET)
+ * @param {string} apiKey - API key for authentication
+ * @param {string} apiSecret - API secret for signature generation
+ * @returns {Object} Object containing signature and timestamp
+ */
+function generateHMAC(method, path, body, apiKey, apiSecret) {
+ // Generate timestamp (milliseconds since Unix epoch)
+ const timestamp = Date.now()
+
+ // Create body hash (empty for GET request)
+ const bodyHash = crypto
+ .createHash("sha256")
+ .update(body || "")
+ .digest("hex")
+
+ // Create string to sign
+ const stringToSign = `${method} ${path} ${bodyHash} ${apiKey} ${timestamp}`
+
+ // Generate HMAC-SHA256 signature
+ const signature = crypto.createHmac("sha256", apiSecret).update(stringToSign).digest("hex")
+
+ return { signature, timestamp }
+}
+
+/**
+ * Generates authentication headers for API requests
+ * @param {string} method - HTTP method
+ * @param {string} path - Request path with query parameters
+ * @param {string} apiKey - API key
+ * @param {string} apiSecret - API secret
+ * @returns {Object} Headers object for the request
+ */
+function generateAuthHeaders(method, path, apiKey, apiSecret) {
+ const { signature, timestamp } = generateHMAC(method, path, "", apiKey, apiSecret)
+
+ return {
+ Authorization: apiKey,
+ "X-Authorization-Timestamp": timestamp.toString(),
+ "X-Authorization-Signature-SHA256": signature,
+ }
+}
+
+/**
+ * Makes an HTTP request and returns a promise resolving to the response
+ * @param {Object} options - HTTP request options
+ * @returns {Promise} Response data as string
+ */
+function makeRequest(options) {
+ return new Promise((resolve, reject) => {
+ const req = https.request(options, (res) => {
+ let data = ""
+
+ res.on("data", (chunk) => {
+ data += chunk
+ })
+
+ res.on("end", () => {
+ if (res.statusCode >= 200 && res.statusCode < 300) {
+ resolve(data)
+ } else {
+ reject(new Error(`API error (status code ${res.statusCode}): ${data}`))
+ }
+ })
+ })
+
+ req.on("error", (error) => {
+ reject(new Error(`Request error: ${error.message}`))
+ })
+
+ req.end()
+ })
+}
+
+/**
+ * Fetches a single report for a specific feed
+ * @param {string} feedID - The feed ID to fetch the report for
+ * @returns {Promise} Promise resolving to the report data
+ */
+async function fetchSingleReport(feedID) {
+ // Get API credentials from environment variables
+ const apiKey = process.env.STREAMS_API_KEY
+ const apiSecret = process.env.STREAMS_API_SECRET
+
+ // Validate credentials
+ if (!apiKey || !apiSecret) {
+ throw new Error("API credentials not set. Please set STREAMS_API_KEY and STREAMS_API_SECRET environment variables")
+ }
+
+ // API connection details
+ const method = "GET"
+ const host = "api.testnet-dataengine.chain.link"
+ const path = "/api/v1/reports/latest"
+ const queryString = `?feedID=${feedID}`
+ const fullPath = path + queryString
+
+ // Create request options with authentication headers
+ const options = {
+ hostname: host,
+ path: fullPath,
+ method: method,
+ headers: generateAuthHeaders(method, fullPath, apiKey, apiSecret),
+ }
+
+ try {
+ // Make the request
+ const responseData = await makeRequest(options)
+
+ // Parse the response
+ const response = JSON.parse(responseData)
+
+ return response.report
+ } catch (error) {
+ throw new Error(`Failed to fetch report: ${error.message}`)
+ }
+}
+
+// Main execution function to support async/await
+async function main() {
+ try {
+ // Example feed ID (ETH/USD)
+ const feedID = "0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782"
+
+ console.log(`Fetching latest report for feed ID: ${feedID}`)
+
+ // Fetch the report
+ const report = await fetchSingleReport(feedID)
+
+ // Display the report
+ console.log("Successfully retrieved report:")
+ console.log(` Feed ID: ${report.feedID}`)
+ console.log(` Valid From: ${report.validFromTimestamp}`)
+ console.log(` Observations Timestamp: ${report.observationsTimestamp}`)
+ console.log(` Full Report: ${report.fullReport}`)
+ } catch (error) {
+ console.error("Error:", error.message)
+ process.exit(1)
+ }
+}
+
+// Start the main function
+main()
+```
+
+**Expected output**:
+
+```bash
+Fetching latest report for feed ID: 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782
+Successfully retrieved report:
+ Feed ID: 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782
+ Valid From: 1747922906
+ Observations Timestamp: 1747922906
+ Full Report: 0x00090d9e8d96765a0c49e03a6ae05c82e8f8de70cf179baa632f183[...]31208430b586890eff87d12750
+```
+
+### Production Considerations
+
+While this example demonstrates the authentication mechanism, production applications should consider:
+
+- **HTTP client libraries**: Use robust libraries like `axios` or `node-fetch` for better error handling and retry capabilities
+- **Retry logic**: Implement exponential backoff for transient failures
+- **Request timeouts**: Add timeout handling to prevent hanging requests
+- **Error types**: Create custom error classes for better error categorization
+- **Logging**: Use structured logging libraries like `winston` or `pino` instead of `console.log`
+- **Configuration**: Use environment configuration libraries like `dotenv` for managing credentials
+- **Input validation**: Validate feed IDs and other inputs before making requests
+- **Testing**: Add unit tests for HMAC generation and integration tests for API calls
+
+## WebSocket Authentication Example
+
+
+
+### Prerequisites
+
+- [Node.js](https://nodejs.org/en/download/) (v20 or later)
+- API credentials from Chainlink Data Streams
+
+### Project Setup
+
+1. Initialize a new Node.js project in your directory:
+
+ ```bash
+ npm init -y
+ ```
+
+1. Install the required WebSocket dependency:
+
+ ```bash
+ npm install ws
+ ```
+
+### Running the Example
+
+1. Create a file named with the example code shown below
+1. Set your API credentials as environment variables:
+ ```bash
+ export STREAMS_API_KEY="your-api-key"
+ export STREAMS_API_SECRET="your-api-secret"
+ ```
+1. Run the example:
+ ```bash
+ node ws-auth-example.js
+ ```
+1. Press Ctrl+C to stop the WebSocket stream when you're done
+
+**Example code**:
+
+```javascript
+const crypto = require("crypto")
+const WebSocket = require("ws")
+const os = require("os")
+const { URL } = require("url")
+
+// Constants for ping/pong intervals and timeouts
+const PING_INTERVAL = 5000 // 5 seconds
+const PONG_TIMEOUT = 10000 // 10 seconds
+const CONNECTION_TIMEOUT = 30000 // 30 seconds
+
+/**
+ * FeedReport represents the data structure received from the WebSocket
+ * @typedef {Object} FeedReport
+ * @property {Object} report - The report object
+ * @property {string} report.feedID - Feed identifier
+ * @property {string} report.fullReport - Full report data in hex format
+ */
+
+/**
+ * Generates HMAC signature for API authentication
+ * @param {string} method - HTTP method (GET for WebSocket connections)
+ * @param {string} path - Request path including query parameters
+ * @param {string} apiKey - API key for authentication
+ * @param {string} apiSecret - API secret for signature generation
+ * @returns {Object} Object containing signature and timestamp
+ */
+function generateHMAC(method, path, apiKey, apiSecret) {
+ // Generate timestamp (milliseconds since Unix epoch)
+ const timestamp = Date.now()
+
+ // Create body hash (empty for WebSocket connection)
+ const bodyHash = crypto.createHash("sha256").update("").digest("hex")
+
+ // Create string to sign
+ const stringToSign = `${method} ${path} ${bodyHash} ${apiKey} ${timestamp}`
+
+ // Generate HMAC-SHA256 signature
+ const signature = crypto.createHmac("sha256", apiSecret).update(stringToSign).digest("hex")
+
+ return { signature, timestamp }
+}
+
+/**
+ * Sets up the WebSocket connection with proper authentication
+ * @param {string} apiKey - API key for authentication
+ * @param {string} apiSecret - API secret for signature generation
+ * @param {string[]} feedIDs - Array of feed IDs to subscribe to
+ * @returns {Promise} Promise resolving to WebSocket connection
+ */
+function setupWebSocketConnection(apiKey, apiSecret, feedIDs) {
+ return new Promise((resolve, reject) => {
+ // Validate feed IDs
+ if (!feedIDs || feedIDs.length === 0) {
+ reject(new Error("No feed ID(s) provided"))
+ return
+ }
+
+ // WebSocket connection details
+ const host = "ws.testnet-dataengine.chain.link"
+ const path = "/api/v1/ws"
+ const queryString = `?feedIDs=${feedIDs.join(",")}`
+ const fullPath = path + queryString
+
+ // Generate authentication signature and timestamp
+ const { signature, timestamp } = generateHMAC("GET", fullPath, apiKey, apiSecret)
+
+ // Create WebSocket URL
+ const wsURL = `wss://${host}${fullPath}`
+ console.log("Connecting to:", wsURL)
+
+ // Set up the WebSocket connection with authentication headers
+ const ws = new WebSocket(wsURL, {
+ headers: {
+ Authorization: apiKey,
+ "X-Authorization-Timestamp": timestamp.toString(),
+ "X-Authorization-Signature-SHA256": signature,
+ },
+ timeout: CONNECTION_TIMEOUT,
+ })
+
+ // Handle connection errors
+ ws.on("error", (err) => {
+ reject(new Error(`WebSocket connection error: ${err.message}`))
+ })
+
+ // Resolve the promise when the connection is established
+ ws.on("open", () => {
+ console.log("WebSocket connection established")
+ resolve(ws)
+ })
+ })
+}
+
+/**
+ * Sets up ping/pong mechanism to keep the connection alive
+ * @param {WebSocket} ws - WebSocket connection
+ */
+function setupPingPong(ws) {
+ // Set up ping interval
+ const pingInterval = setInterval(() => {
+ if (ws.readyState === WebSocket.OPEN) {
+ console.log("Sending ping to keep connection alive...")
+ ws.ping(crypto.randomBytes(8))
+
+ // Set up pong timeout - if we don't receive a pong within timeout, close the connection
+ ws.pongTimeout = setTimeout(() => {
+ console.log("No pong received, closing connection...")
+ ws.terminate()
+ }, PONG_TIMEOUT)
+ }
+ }, PING_INTERVAL)
+
+ // Clear pong timeout when pong is received
+ ws.on("pong", () => {
+ console.log("Received pong from server")
+ clearTimeout(ws.pongTimeout)
+ })
+
+ // Clear intervals on close
+ ws.on("close", () => {
+ clearInterval(pingInterval)
+ clearTimeout(ws.pongTimeout)
+ })
+}
+
+/**
+ * Handle WebSocket messages
+ * @param {WebSocket} ws - WebSocket connection
+ */
+function handleMessages(ws) {
+ ws.on("message", (data) => {
+ try {
+ // Parse the message
+ const message = JSON.parse(data.toString())
+
+ // Check if it has the expected report format
+ if (message.report && message.report.feedID) {
+ const report = message.report
+ console.log("\nReceived new report:")
+ console.log(` Feed ID: ${report.feedID}`)
+
+ // Display timestamps if available
+ if (report.validFromTimestamp) {
+ console.log(` Valid From: ${report.validFromTimestamp}`)
+ }
+
+ if (report.observationsTimestamp) {
+ console.log(` Observations Timestamp: ${report.observationsTimestamp}`)
+ }
+
+ // Display the full report with truncation for readability
+ if (report.fullReport) {
+ const reportPreview =
+ report.fullReport.length > 40 ? `${report.fullReport.substring(0, 40)}...` : report.fullReport
+ console.log(` Full Report: ${reportPreview}`)
+ }
+ } else {
+ console.log("Received message with unexpected format:", message)
+ }
+ } catch (error) {
+ console.error("Error parsing message:", error)
+ console.log("Raw message:", data.toString())
+ }
+ })
+}
+
+/**
+ * Main function to set up and manage the WebSocket connection
+ */
+async function main() {
+ try {
+ // Get API credentials from environment variables
+ const apiKey = process.env.STREAMS_API_KEY
+ const apiSecret = process.env.STREAMS_API_SECRET
+
+ // Validate credentials
+ if (!apiKey || !apiSecret) {
+ throw new Error(
+ "API credentials not set. Please set STREAMS_API_KEY and STREAMS_API_SECRET environment variables"
+ )
+ }
+
+ // Example feed ID (ETH/USD)
+ const feedIDs = ["0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782"]
+
+ // Set up WebSocket connection
+ const ws = await setupWebSocketConnection(apiKey, apiSecret, feedIDs)
+
+ // Set up ping/pong to keep connection alive
+ setupPingPong(ws)
+
+ // Handle incoming messages
+ handleMessages(ws)
+
+ // Set up graceful shutdown on SIGINT (Ctrl+C)
+ process.on("SIGINT", () => {
+ console.log("\nInterrupt signal received, closing connection...")
+
+ // Close the WebSocket connection gracefully
+ if (ws.readyState === WebSocket.OPEN) {
+ ws.close(1000, "Client shutting down")
+ }
+
+ // Allow some time for the close to be sent, then exit
+ setTimeout(() => {
+ console.log("Exiting...")
+ process.exit(0)
+ }, 1000)
+ })
+ } catch (error) {
+ console.error("Error:", error.message)
+ process.exit(1)
+ }
+}
+
+// Start the main function
+main()
+```
+
+**Expected output**:
+
+```bash
+Connecting to: wss://ws.testnet-dataengine.chain.link/api/v1/ws?feedIDs=0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782
+WebSocket connection established
+
+Received new report:
+ Feed ID: 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782
+ Valid From: 1747929684
+ Observations Timestamp: 1747929684
+ Full Report: 0x00090d9e8d96765a0c49e03a6ae05c82e8f8de...
+
+Received new report:
+ Feed ID: 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782
+ Valid From: 1747929685
+ Observations Timestamp: 1747929685
+ Full Report: 0x00090d9e8d96765a0c49e03a6ae05c82e8f8de...
+
+Sending ping to keep connection alive...
+Received pong from server
+^C
+Interrupt signal received, closing connection...
+Exiting...
+```
+
+### Production Considerations
+
+While this example already includes many production-ready features (keepalive, timeouts, graceful shutdown), production applications should additionally consider:
+
+- **Automatic reconnection**: Implement exponential backoff reconnection logic for network disruptions
+- **Message queuing**: Buffer outgoing messages during reconnection attempts
+- **WebSocket libraries**: Consider using libraries like `socket.io-client` or `reconnecting-websocket` for additional features
+- **Structured logging**: Use `winston` or `pino` with log levels instead of `console.log`
+- **Metrics collection**: Track connection status, message rates, and latency
+- **Configuration management**: Use `dotenv` or similar for managing environment variables and timeouts
+- **Error categorization**: Create custom error classes to distinguish between retriable and fatal errors
+- **Testing**: Add unit tests for HMAC generation and mock WebSocket server for integration tests
diff --git a/src/content/data-streams/reference/authentication/rust-examples.mdx b/src/content/data-streams/reference/authentication/rust-examples.mdx
new file mode 100644
index 00000000000..05dd5f2628f
--- /dev/null
+++ b/src/content/data-streams/reference/authentication/rust-examples.mdx
@@ -0,0 +1,533 @@
+---
+section: dataStreams
+date: Last Modified
+title: "API Authentication - Rust examples"
+metadata:
+ title: "Data Streams API Authentication - Rust examples"
+ description: "Learn how to authenticate with the Data Streams API using Rust with examples for REST API and WebSocket connections."
+ keywords: ["Data Streams", "API", "Authentication", "Rust", "HMAC", "API Security"]
+---
+
+import { Aside, CopyText } from "@components"
+import DataStreams from "@features/data-streams/common/DataStreams.astro"
+
+
+
+Below are complete examples for authenticating with the Data Streams API in Rust. Each example shows how to properly generate the required headers and make a request.
+
+To learn more about the Data Streams API authentication, see the [Data Streams Authentication](/data-streams/reference/authentication) page.
+
+**Note**: The Data Streams SDKs handle authentication automatically. If you're using the [Go SDK](/data-streams/reference/go-sdk) or [Rust SDK](/data-streams/reference/rust-sdk), you don't need to implement the authentication logic manually.
+
+## API Authentication Example
+
+
+
+### Requirements
+
+- [Rust](https://www.rust-lang.org/tools/install) (v1.70 or later recommended)
+- API credentials from Chainlink Data Streams
+
+### Running the Example
+
+1. Create a file:
+
+ ```toml
+ [package]
+ name = "chainlink-streams-direct-auth"
+ version = "0.1.0"
+ edition = "2021"
+
+ [dependencies]
+ reqwest = { version = "0.11", features = ["json", "blocking"] }
+ serde = { version = "1.0", features = ["derive"] }
+ serde_json = "1.0"
+ tokio = { version = "1.32", features = ["full"] }
+ hmac = "0.12"
+ sha2 = "0.10"
+ hex = "0.4"
+ chrono = "0.4"
+ ```
+
+1. Create a file:
+
+ ```rust
+ use hmac::{Hmac, Mac};
+ use reqwest::header::{HeaderMap, HeaderValue};
+ use serde::{Deserialize, Serialize};
+ use sha2::{Digest, Sha256};
+ use std::env;
+ use std::error::Error;
+ use std::time::{SystemTime, UNIX_EPOCH};
+
+ type HmacSha256 = Hmac;
+
+ // SingleReport represents a data feed report structure
+ #[derive(Debug, Deserialize, Serialize)]
+ struct SingleReport {
+ #[serde(rename = "feedID")]
+ feed_id: String,
+ #[serde(rename = "validFromTimestamp")]
+ valid_from_timestamp: u32,
+ #[serde(rename = "observationsTimestamp")]
+ observations_timestamp: u32,
+ #[serde(rename = "fullReport")]
+ full_report: String,
+ }
+
+ // SingleReportResponse is the response structure for a single report
+ #[derive(Debug, Deserialize, Serialize)]
+ struct SingleReportResponse {
+ report: SingleReport,
+ }
+
+ // Generate HMAC signature for API authentication
+ fn generate_hmac(
+ method: &str,
+ path: &str,
+ body: &[u8],
+ api_key: &str,
+ api_secret: &str
+ ) -> Result<(String, u128), Box> {
+ // Generate timestamp (milliseconds since Unix epoch)
+ let timestamp = SystemTime::now()
+ .duration_since(UNIX_EPOCH)
+ .expect("Time went backwards")
+ .as_millis();
+
+ // Generate body hash
+ let mut hasher = Sha256::new();
+ hasher.update(body);
+ let body_hash = hex::encode(hasher.finalize());
+
+ // Create string to sign
+ let string_to_sign = format!("{} {} {} {} {}", method, path, body_hash, api_key, timestamp);
+
+ // Generate HMAC-SHA256 signature
+ let mut mac = HmacSha256::new_from_slice(api_secret.as_bytes())?;
+ mac.update(string_to_sign.as_bytes());
+ let signature = hex::encode(mac.finalize().into_bytes());
+
+ Ok((signature, timestamp))
+ }
+
+ // Generate authentication headers for API requests
+ fn generate_auth_headers(
+ method: &str,
+ path: &str,
+ api_key: &str,
+ api_secret: &str
+ ) -> Result> {
+ let (signature, timestamp) = generate_hmac(method, path, &[], api_key, api_secret)?;
+
+ let mut headers = HeaderMap::new();
+ headers.insert("Authorization", HeaderValue::from_str(api_key)?);
+ headers.insert(
+ "X-Authorization-Timestamp",
+ HeaderValue::from_str(×tamp.to_string())?
+ );
+ headers.insert(
+ "X-Authorization-Signature-SHA256",
+ HeaderValue::from_str(&signature)?
+ );
+
+ Ok(headers)
+ }
+
+ // Fetch a single report for a specific feed
+ async fn fetch_single_report(feed_id: &str) -> Result> {
+ // Get API credentials from environment variables
+ let api_key = env::var("STREAMS_API_KEY")
+ .map_err(|_| "API credentials not set. Please set STREAMS_API_KEY environment variable")?;
+ let api_secret = env::var("STREAMS_API_SECRET")
+ .map_err(|_| "API credentials not set. Please set STREAMS_API_SECRET environment variable")?;
+
+ // API connection details
+ let method = "GET";
+ let host = "api.testnet-dataengine.chain.link";
+ let path = "/api/v1/reports/latest";
+ let full_path = format!("{}?feedID={}", path, feed_id);
+
+ // Create headers with authentication
+ let headers = generate_auth_headers(method, &full_path, &api_key, &api_secret)?;
+
+ // Create and execute the request
+ let url = format!("https://{}{}", host, full_path);
+ let client = reqwest::Client::new();
+ let response = client
+ .get(&url)
+ .headers(headers)
+ .send()
+ .await?;
+
+ // Check for non-success status code
+ if !response.status().is_success() {
+ let status = response.status();
+ let error_text = response.text().await?;
+ return Err(format!("API error (status code {}): {}", status, error_text).into());
+ }
+
+ // Parse the response
+ let report_resp: SingleReportResponse = response.json().await?;
+ Ok(report_resp.report)
+ }
+
+ #[tokio::main]
+ async fn main() -> Result<(), Box> {
+ // Example feed ID (ETH/USD)
+ let feed_id = "0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782";
+
+ println!("Fetching latest report for feed ID: {}", feed_id);
+
+ // Fetch the report
+ let report = fetch_single_report(feed_id).await?;
+
+ // Display the report
+ println!("Successfully retrieved report:");
+ println!(" Feed ID: {}", report.feed_id);
+ println!(" Valid From: {}", report.valid_from_timestamp);
+ println!(" Observations Timestamp: {}", report.observations_timestamp);
+
+ // Display the full report with truncation for readability
+ let report_preview = if report.full_report.len() > 40 {
+ format!("{}...", &report.full_report[..40])
+ } else {
+ report.full_report.clone()
+ };
+ println!(" Full Report: {}", report_preview);
+
+ Ok(())
+ }
+ ```
+
+1. Set your API credentials as environment variables:
+ ```bash
+ export STREAMS_API_KEY="your-api-key"
+ export STREAMS_API_SECRET="your-api-secret"
+ ```
+1. Run with
+
+**Expected output**:
+
+```bash
+Fetching latest report for feed ID: 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782
+Successfully retrieved report:
+ Feed ID: 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782
+ Valid From: 1747933113
+ Observations Timestamp: 1747933113
+ Full Report: 0x00090d9e8d96765a0c49e03a6ae05c82e8f8de...
+```
+
+### Production Considerations
+
+While this example demonstrates the authentication mechanism, production applications should consider:
+
+- **Connection resilience**: Implement retry logic with exponential backoff for network failures
+- **Error handling**: Use custom error types instead of string errors for better error management
+- **Logging**: Replace `println!` with structured logging (e.g., `tracing`, `env_logger`)
+- **Configuration**: Make API endpoints configurable through environment variables
+- **Resource management**: Implement graceful shutdown for long-running connections
+- **Testing**: Add unit tests for HMAC generation and integration tests for API calls
+
+For production use, consider using the [Rust SDK](/data-streams/reference/rust-sdk) which handles authentication automatically and provides built-in fault tolerance.
+
+## WebSocket Authentication Example
+
+
+
+### Requirements
+
+- [Rust](https://www.rust-lang.org/tools/install) (v1.70 or later recommended)
+- API credentials from Chainlink Data Streams
+
+### Running the Example
+
+1. Create a file:
+
+ ```toml
+ [package]
+ name = "chainlink-streams-direct-auth"
+ version = "0.1.0"
+ edition = "2021"
+
+ [dependencies]
+ tokio = { version = "1.32", features = ["full"] }
+ tokio-tungstenite = { version = "0.20", features = ["native-tls"] }
+ futures-util = "0.3"
+ hmac = "0.12"
+ sha2 = "0.10"
+ hex = "0.4"
+ chrono = "0.4"
+ url = "2.4"
+ serde = { version = "1.0", features = ["derive"] }
+ serde_json = "1.0"
+ ```
+
+1. Create a file:
+
+ ```rust
+ use hmac::{ Hmac, Mac };
+ use sha2::{ Digest, Sha256 };
+ use std::{ env, error::Error, time::{ SystemTime, UNIX_EPOCH } };
+ use tokio_tungstenite::{
+ connect_async,
+ tungstenite::client::IntoClientRequest,
+ tungstenite::protocol::Message,
+ };
+ use futures_util::{ StreamExt, SinkExt };
+ use serde::{ Deserialize, Serialize };
+
+ type HmacSha256 = Hmac;
+
+ // Report structure for deserializing WebSocket messages
+ #[derive(Debug, Deserialize, Serialize)]
+ struct ReportWrapper {
+ report: Report,
+ }
+
+ #[derive(Debug, Deserialize, Serialize)]
+ struct Report {
+ #[serde(rename = "feedID")]
+ feed_id: String,
+
+ #[serde(rename = "fullReport")]
+ full_report: String,
+
+ #[serde(rename = "validFromTimestamp")]
+ valid_from_timestamp: u64,
+
+ #[serde(rename = "observationsTimestamp")]
+ observations_timestamp: u64,
+ }
+
+ // Generate HMAC signature for API authentication
+ fn generate_hmac(
+ method: &str,
+ path: &str,
+ body: &[u8],
+ api_key: &str,
+ api_secret: &str
+ ) -> Result<(String, u128), Box> {
+ // Generate timestamp (milliseconds since Unix epoch)
+ let timestamp = SystemTime::now()
+ .duration_since(UNIX_EPOCH)
+ .expect("Time went backwards")
+ .as_millis();
+
+ // Generate body hash
+ let mut hasher = Sha256::new();
+ hasher.update(body);
+ let body_hash = hex::encode(hasher.finalize());
+
+ // Create string to sign
+ let string_to_sign = format!("{} {} {} {} {}", method, path, body_hash, api_key, timestamp);
+
+ // Generate HMAC-SHA256 signature
+ let mut mac = HmacSha256::new_from_slice(api_secret.as_bytes())?;
+ mac.update(string_to_sign.as_bytes());
+ let signature = hex::encode(mac.finalize().into_bytes());
+
+ Ok((signature, timestamp))
+ }
+
+ // Set up WebSocket connection with proper authentication
+ async fn setup_websocket_connection(
+ api_key: &str,
+ api_secret: &str,
+ feed_ids: &[&str]
+ ) -> Result<
+ tokio_tungstenite::WebSocketStream>,
+ Box
+ > {
+ // Validate feed IDs
+ if feed_ids.is_empty() {
+ return Err("No feed ID(s) provided".into());
+ }
+
+ // WebSocket connection details
+ let host = "ws.testnet-dataengine.chain.link";
+ let path = "/api/v1/ws";
+ let feed_ids_joined = feed_ids.join(",");
+ let full_path = format!("{}?feedIDs={}", path, feed_ids_joined);
+
+ // Generate authentication signature and timestamp
+ let (signature, timestamp) = generate_hmac("GET", &full_path, &[], api_key, api_secret)?;
+
+ // Create WebSocket URL
+ let ws_url = format!("wss://{}{}", host, full_path);
+ println!("Connecting to: {}", ws_url);
+
+ // Create request with auth headers
+ let mut request = ws_url.into_client_request()?;
+ request.headers_mut().insert("Authorization", api_key.parse()?);
+ request.headers_mut().insert("X-Authorization-Timestamp", timestamp.to_string().parse()?);
+ request.headers_mut().insert("X-Authorization-Signature-SHA256", signature.parse()?);
+
+ // Connect to WebSocket server
+ let (ws_stream, _) = connect_async(request).await?;
+ println!("WebSocket connection established");
+
+ Ok(ws_stream)
+ }
+
+ // Handle incoming WebSocket messages
+ async fn handle_messages(
+ mut ws_stream: tokio_tungstenite::WebSocketStream>
+ ) {
+ println!("Waiting for incoming messages... (press Ctrl+C to exit)");
+
+ // Process messages as they arrive
+ while let Some(msg) = ws_stream.next().await {
+ match msg {
+ Ok(msg) => {
+ match msg {
+ Message::Text(text) => {
+ // Try to parse JSON
+ if let Ok(report_wrapper) = serde_json::from_str::(&text) {
+ let report = &report_wrapper.report;
+ println!("\nReceived new report:");
+ println!(" Feed ID: {}", report.feed_id);
+ println!(" Valid From: {}", report.valid_from_timestamp);
+ println!(" Observations Timestamp: {}", report.observations_timestamp);
+
+ // Display the full report with truncation for readability
+ let report_preview = if report.full_report.len() > 40 {
+ format!("{}...", &report.full_report[..40])
+ } else {
+ report.full_report.clone()
+ };
+ println!(" Full Report: {}", report_preview);
+ } else {
+ println!("Received text message: {}", text);
+ }
+ }
+ Message::Binary(data) => {
+ // Try to parse binary as JSON
+ if let Ok(text) = String::from_utf8(data.clone()) {
+ if
+ let Ok(report_wrapper) = serde_json::from_str::(
+ &text
+ )
+ {
+ let report = &report_wrapper.report;
+ println!("\nReceived new report:");
+ println!(" Feed ID: {}", report.feed_id);
+ println!(" Valid From: {}", report.valid_from_timestamp);
+ println!(
+ " Observations Timestamp: {}",
+ report.observations_timestamp
+ );
+
+ // Display the full report with truncation
+ let report_preview = if report.full_report.len() > 40 {
+ format!("{}...", &report.full_report[..40])
+ } else {
+ report.full_report.clone()
+ };
+ println!(" Full Report: {}", report_preview);
+ } else {
+ println!("Received binary message: {} bytes", data.len());
+ }
+ } else {
+ println!("Received binary message (not UTF-8): {} bytes", data.len());
+ }
+ }
+ Message::Ping(ping_data) => {
+ println!("Received ping, sending pong response");
+ // Send a pong with the same data to keep the connection alive
+ if let Err(e) = ws_stream.send(Message::Pong(ping_data)).await {
+ eprintln!("Error sending pong: {}", e);
+ }
+ }
+ Message::Pong(_) => println!("Received pong"),
+ Message::Close(_) => {
+ println!("Received close message");
+ break;
+ }
+ Message::Frame(_) => println!("Received raw frame"),
+ }
+ }
+ Err(e) => {
+ eprintln!("Error receiving message: {}", e);
+ break;
+ }
+ }
+ }
+ }
+
+ #[tokio::main]
+ async fn main() -> Result<(), Box> {
+ // Get API credentials from environment variables
+ let api_key = env
+ ::var("STREAMS_API_KEY")
+ .map_err(|_| "API credentials not set. Please set STREAMS_API_KEY environment variable")?;
+ let api_secret = env
+ ::var("STREAMS_API_SECRET")
+ .map_err(
+ |_| "API credentials not set. Please set STREAMS_API_SECRET environment variable"
+ )?;
+
+ // Example feed IDs (ETH/USD)
+ let feed_ids = vec!["0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782"];
+
+ // Set up WebSocket connection
+ let ws_stream = setup_websocket_connection(&api_key, &api_secret, &feed_ids).await?;
+
+ // Set up a task to handle WebSocket communication
+ let ws_task = tokio::spawn(handle_messages(ws_stream));
+
+ // Wait for user to press Ctrl+C
+ tokio::signal::ctrl_c().await?;
+ println!("Shutting down...");
+
+ // Clean up resources
+ let _ = ws_task.abort();
+
+ Ok(())
+ }
+ ```
+
+1. Set your API credentials as environment variables:
+ ```bash
+ export STREAMS_API_KEY="your-api-key"
+ export STREAMS_API_SECRET="your-api-secret"
+ ```
+1. Run with
+
+**Expected output**:
+
+```bash
+Connecting to: wss://ws.testnet-dataengine.chain.link/api/v1/ws?feedIDs=0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782
+WebSocket connection established
+Waiting for incoming messages... (press Ctrl+C to exit)
+Received ping, sending pong response
+
+Received new report:
+ Feed ID: 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782
+ Valid From: 1747934358
+ Observations Timestamp: 1747934358
+ Full Report: 0x00090d9e8d96765a0c49e03a6ae05c82e8f8de...
+
+Received new report:
+ Feed ID: 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782
+ Valid From: 1747934359
+ Observations Timestamp: 1747934359
+ Full Report: 0x00090d9e8d96765a0c49e03a6ae05c82e8f8de...
+
+^CShutting down...
+```
+
+### Production Considerations
+
+While this example demonstrates WebSocket authentication, production applications should consider:
+
+- **Connection resilience**: Implement automatic reconnection with exponential backoff
+- **Heartbeat mechanism**: Send periodic pings to detect stale connections
+- **Message buffering**: Queue messages during reconnection attempts
+- **Error handling**: Use custom error types for better error categorization
+- **Logging**: Replace `println!` with structured logging (e.g., `tracing`, `env_logger`)
+- **Configuration**: Make WebSocket endpoints and timeouts configurable
+- **Graceful shutdown**: Properly close WebSocket connections with close frames
+- **Testing**: Add tests for connection handling and message parsing
+
+For production use, consider using the [Rust SDK](/data-streams/reference/rust-sdk) which handles authentication automatically and provides built-in fault tolerance.
diff --git a/src/content/data-streams/reference/authentication/typescript-examples.mdx b/src/content/data-streams/reference/authentication/typescript-examples.mdx
new file mode 100644
index 00000000000..7045a8746e8
--- /dev/null
+++ b/src/content/data-streams/reference/authentication/typescript-examples.mdx
@@ -0,0 +1,624 @@
+---
+section: dataStreams
+date: Last Modified
+title: "API Authentication - TypeScript examples"
+metadata:
+ title: "Data Streams API Authentication - TypeScript examples"
+ description: "Learn how to authenticate with the Data Streams API using TypeScript"
+ keywords: ["Data Streams", "API", "Authentication", "TypeScript"]
+---
+
+import { Aside, CopyText } from "@components"
+import DataStreams from "@features/data-streams/common/DataStreams.astro"
+
+
+
+Below are complete examples for authenticating with the Data Streams API in TypeScript, using Node.js. Each example shows how to properly generate the required headers and make a request.
+
+To learn more about the Data Streams API authentication, see the [Data Streams Authentication](/data-streams/reference/authentication) page.
+
+**Note**: The Data Streams SDKs handle authentication automatically. If you're using the [Go SDK](/data-streams/reference/go-sdk) or [Rust SDK](/data-streams/reference/rust-sdk), you don't need to implement the authentication logic manually.
+
+## API Authentication Example
+
+
+
+### Prerequisites
+
+- [Node.js](https://nodejs.org/en/download/) (v20 or later recommended)
+- API credentials from Chainlink Data Streams
+
+### Project Setup
+
+1. Set up your TypeScript environment:
+
+ ```bash
+ # Install TypeScript tools
+ npm install -g ts-node
+ npm install --save-dev typescript @types/node
+ ```
+
+1. Create a file in your project folder:
+
+ ```json
+ {
+ "compilerOptions": {
+ "target": "ES2020",
+ "module": "commonjs",
+ "esModuleInterop": true,
+ "forceConsistentCasingInFileNames": true,
+ "strict": true,
+ "skipLibCheck": true
+ }
+ }
+ ```
+
+
+
+### Running the Example
+
+1. Create a file named with the example code shown below
+1. Set your API credentials as environment variables:
+ ```bash
+ export STREAMS_API_KEY="your-api-key"
+ export STREAMS_API_SECRET="your-api-secret"
+ ```
+1. Run the example:
+ ```bash
+ ts-node auth-example.ts
+ ```
+
+
+
+**Example code**:
+
+```typescript
+import crypto from "crypto"
+import https from "https"
+import { IncomingMessage, ClientRequest } from "http"
+
+/**
+ * Single report data structure
+ */
+interface SingleReport {
+ feedID: string
+ validFromTimestamp: number
+ observationsTimestamp: number
+ fullReport: string
+}
+
+/**
+ * SingleReportResponse is the response structure for a single report
+ */
+interface SingleReportResponse {
+ report: SingleReport
+}
+
+/**
+ * Generates HMAC signature for API authentication
+ * @param method - HTTP method (GET, POST, etc.)
+ * @param path - Request path including query parameters
+ * @param body - Request body (empty string for GET)
+ * @param apiKey - API key for authentication
+ * @param apiSecret - API secret for signature generation
+ * @returns Object containing signature and timestamp
+ */
+function generateHMAC(
+ method: string,
+ path: string,
+ body: string | Buffer,
+ apiKey: string,
+ apiSecret: string
+): { signature: string; timestamp: number } {
+ // Generate timestamp (milliseconds since Unix epoch)
+ const timestamp: number = Date.now()
+
+ // Create body hash (empty for GET request)
+ const bodyHash: string = crypto
+ .createHash("sha256")
+ .update(body || "")
+ .digest("hex")
+
+ // Create string to sign
+ const stringToSign: string = `${method} ${path} ${bodyHash} ${apiKey} ${timestamp}`
+
+ // Generate HMAC-SHA256 signature
+ const signature: string = crypto.createHmac("sha256", apiSecret).update(stringToSign).digest("hex")
+
+ return { signature, timestamp }
+}
+
+/**
+ * Generates authentication headers for API requests
+ * @param method - HTTP method
+ * @param path - Request path with query parameters
+ * @param apiKey - API key
+ * @param apiSecret - API secret
+ * @returns Headers object for the request
+ */
+function generateAuthHeaders(method: string, path: string, apiKey: string, apiSecret: string): Record {
+ const { signature, timestamp } = generateHMAC(method, path, "", apiKey, apiSecret)
+
+ return {
+ Authorization: apiKey,
+ "X-Authorization-Timestamp": timestamp.toString(),
+ "X-Authorization-Signature-SHA256": signature,
+ }
+}
+
+/**
+ * Makes an HTTP request and returns a promise resolving to the response
+ * @param options - HTTP request options
+ * @returns Response data as string
+ */
+function makeRequest(options: https.RequestOptions): Promise {
+ return new Promise((resolve, reject) => {
+ const req: ClientRequest = https.request(options, (res: IncomingMessage) => {
+ let data = ""
+
+ res.on("data", (chunk: Buffer) => {
+ data += chunk
+ })
+
+ res.on("end", () => {
+ if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {
+ resolve(data)
+ } else {
+ reject(new Error(`API error (status code ${res.statusCode}): ${data}`))
+ }
+ })
+ })
+
+ req.on("error", (error: Error) => {
+ reject(new Error(`Request error: ${error.message}`))
+ })
+
+ req.end()
+ })
+}
+
+/**
+ * Fetches a single report for a specific feed
+ * @param feedID - The feed ID to fetch the report for
+ * @returns Promise resolving to the report data
+ */
+async function fetchSingleReport(feedID: string): Promise {
+ // Get API credentials from environment variables
+ const apiKey = process.env.STREAMS_API_KEY
+ const apiSecret = process.env.STREAMS_API_SECRET
+
+ // Validate credentials
+ if (!apiKey || !apiSecret) {
+ throw new Error("API credentials not set. Please set STREAMS_API_KEY and STREAMS_API_SECRET environment variables")
+ }
+
+ // API connection details
+ const method = "GET"
+ const host = "api.testnet-dataengine.chain.link"
+ const path = "/api/v1/reports/latest"
+ const queryString = `?feedID=${feedID}`
+ const fullPath = path + queryString
+
+ // Create request options with authentication headers
+ const options: https.RequestOptions = {
+ hostname: host,
+ path: fullPath,
+ method: method,
+ headers: generateAuthHeaders(method, fullPath, apiKey, apiSecret),
+ }
+
+ try {
+ // Make the request
+ const responseData = await makeRequest(options)
+
+ // Parse the response
+ const response = JSON.parse(responseData) as SingleReportResponse
+
+ return response.report
+ } catch (error: any) {
+ throw new Error(`Failed to fetch report: ${error.message}`)
+ }
+}
+
+/**
+ * Main execution function to support async/await
+ */
+async function main(): Promise {
+ try {
+ // Example feed ID (ETH/USD)
+ const feedID = "0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782"
+
+ console.log(`Fetching latest report for feed ID: ${feedID}`)
+
+ // Fetch the report
+ const report = await fetchSingleReport(feedID)
+
+ // Display the report
+ console.log("Successfully retrieved report:")
+ console.log(` Feed ID: ${report.feedID}`)
+ console.log(` Valid From: ${report.validFromTimestamp}`)
+ console.log(` Observations Timestamp: ${report.observationsTimestamp}`)
+ console.log(` Full Report: ${report.fullReport}`)
+ } catch (error: any) {
+ console.error("Error:", error.message)
+ process.exit(1)
+ }
+}
+
+// Start the main function
+main()
+```
+
+**Expected output**:
+
+```bash
+Fetching latest report for feed ID: 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782
+Successfully retrieved report:
+ Feed ID: 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782
+ Valid From: 1747929367
+ Observations Timestamp: 1747929367
+ Full Report: 0x00090d9e8d96765a0c49e03a6ae05c82e8d69000000[...]79dd065e3f83ca7c0ca4aaa
+```
+
+### Production Considerations
+
+While this example demonstrates the authentication mechanism, production applications should consider:
+
+- **HTTP client libraries**: Use type-safe libraries like `axios` with TypeScript support for better error handling and retry capabilities
+- **Retry logic**: Implement exponential backoff for transient failures with proper type definitions
+- **Request timeouts**: Add typed timeout handling to prevent hanging requests
+- **Error types**: Create custom error classes extending `Error` for better error categorization
+- **Logging**: Use structured logging libraries like `winston` or `pino` with TypeScript definitions
+- **Configuration**: Use libraries like `dotenv` with type-safe configuration schemas (e.g., using `zod`)
+- **Input validation**: Use runtime type validation libraries for feed IDs and API responses
+- **Testing**: Add unit tests with `jest` and `@types/jest` for type-safe testing
+
+## WebSocket Authentication Example
+
+
+
+### Prerequisites
+
+- [Node.js](https://nodejs.org/en/download/) (v20 or later recommended)
+- API credentials from Chainlink Data Streams
+
+### Project Setup
+
+1. Set up your TypeScript environment:
+
+ ```bash
+ # Install TypeScript tools
+ npm install -g ts-node
+ npm install --save-dev typescript @types/node
+ ```
+
+1. Install the WebSocket library and its TypeScript definitions:
+
+ ```bash
+ npm install ws @types/ws
+ ```
+
+1. Create a file in your project folder:
+
+ ```json
+ {
+ "compilerOptions": {
+ "target": "ES2020",
+ "module": "commonjs",
+ "esModuleInterop": true,
+ "forceConsistentCasingInFileNames": true,
+ "strict": true,
+ "skipLibCheck": true
+ }
+ }
+ ```
+
+
+
+### Running the Example
+
+1. Create a file named with the example code shown below
+1. Set your API credentials as environment variables (if not already set):
+ ```bash
+ export STREAMS_API_KEY="your-api-key"
+ export STREAMS_API_SECRET="your-api-secret"
+ ```
+1. Run the example:
+ ```bash
+ ts-node ws-auth-example.ts
+ ```
+
+
+
+**Example code**:
+
+```typescript
+import crypto from "crypto"
+import WebSocket from "ws"
+
+// Constants for ping/pong intervals and timeouts
+const PING_INTERVAL = 5000 // 5 seconds
+const PONG_TIMEOUT = 10000 // 10 seconds
+const CONNECTION_TIMEOUT = 30000 // 30 seconds
+
+/**
+ * WebSocket with custom properties for TypeScript
+ */
+interface CustomWebSocket extends WebSocket {
+ pongTimeout?: NodeJS.Timeout
+}
+
+/**
+ * FeedReport represents the data structure received from the WebSocket
+ */
+interface FeedReport {
+ report: {
+ feedID: string
+ validFromTimestamp?: number
+ observationsTimestamp?: number
+ fullReport: string
+ }
+}
+
+/**
+ * Generates HMAC signature for API authentication
+ * @param method - HTTP method (GET for WebSocket connections)
+ * @param path - Request path including query parameters
+ * @param apiKey - API key for authentication
+ * @param apiSecret - API secret for signature generation
+ * @returns Object containing signature and timestamp
+ */
+function generateHMAC(
+ method: string,
+ path: string,
+ apiKey: string,
+ apiSecret: string
+): { signature: string; timestamp: number } {
+ // Generate timestamp (milliseconds since Unix epoch)
+ const timestamp: number = Date.now()
+
+ // Create body hash (empty for WebSocket connection)
+ const bodyHash: string = crypto.createHash("sha256").update("").digest("hex")
+
+ // Create string to sign
+ const stringToSign: string = `${method} ${path} ${bodyHash} ${apiKey} ${timestamp}`
+
+ // Generate HMAC-SHA256 signature
+ const signature: string = crypto.createHmac("sha256", apiSecret).update(stringToSign).digest("hex")
+
+ return { signature, timestamp }
+}
+
+/**
+ * Sets up the WebSocket connection with proper authentication
+ * @param apiKey - API key for authentication
+ * @param apiSecret - API secret for signature generation
+ * @param feedIDs - Array of feed IDs to subscribe to
+ * @returns Promise resolving to WebSocket connection
+ */
+function setupWebSocketConnection(apiKey: string, apiSecret: string, feedIDs: string[]): Promise {
+ return new Promise((resolve, reject) => {
+ // Validate feed IDs
+ if (!feedIDs || feedIDs.length === 0) {
+ reject(new Error("No feed ID(s) provided"))
+ return
+ }
+
+ // WebSocket connection details
+ const host = "ws.testnet-dataengine.chain.link"
+ const path = "/api/v1/ws"
+ const queryString = `?feedIDs=${feedIDs.join(",")}`
+ const fullPath = path + queryString
+
+ // Generate authentication signature and timestamp
+ const { signature, timestamp } = generateHMAC("GET", fullPath, apiKey, apiSecret)
+
+ // Create WebSocket URL
+ const wsURL = `wss://${host}${fullPath}`
+ console.log("Connecting to:", wsURL)
+
+ // Set up the WebSocket connection with authentication headers
+ const ws = new WebSocket(wsURL, {
+ headers: {
+ Authorization: apiKey,
+ "X-Authorization-Timestamp": timestamp.toString(),
+ "X-Authorization-Signature-SHA256": signature,
+ },
+ handshakeTimeout: CONNECTION_TIMEOUT,
+ }) as CustomWebSocket
+
+ // Handle connection errors
+ ws.on("error", (err) => {
+ reject(new Error(`WebSocket connection error: ${err.message}`))
+ })
+
+ // Resolve the promise when the connection is established
+ ws.on("open", () => {
+ console.log("WebSocket connection established")
+ resolve(ws)
+ })
+ })
+}
+
+/**
+ * Sets up ping/pong mechanism to keep the connection alive
+ * @param ws - WebSocket connection
+ */
+function setupPingPong(ws: CustomWebSocket): void {
+ // Set up ping interval
+ const pingInterval = setInterval(() => {
+ if (ws.readyState === ws.OPEN) {
+ console.log("Sending ping to keep connection alive...")
+ ws.ping(Buffer.from(crypto.randomBytes(8)))
+
+ // Set up pong timeout - if we don't receive a pong within timeout, close the connection
+ ws.pongTimeout = setTimeout(() => {
+ console.log("No pong received, closing connection...")
+ ws.terminate()
+ }, PONG_TIMEOUT)
+ }
+ }, PING_INTERVAL)
+
+ // Clear pong timeout when pong is received
+ ws.on("pong", () => {
+ console.log("Received pong from server")
+ clearTimeout(ws.pongTimeout)
+ })
+
+ // Clear intervals on close
+ ws.on("close", () => {
+ clearInterval(pingInterval)
+ clearTimeout(ws.pongTimeout)
+ })
+}
+
+/**
+ * Handle WebSocket messages
+ * @param ws - WebSocket connection
+ */
+function handleMessages(ws: CustomWebSocket): void {
+ ws.on("message", (data: Buffer | string) => {
+ try {
+ // Parse the message
+ const message = JSON.parse(data.toString()) as FeedReport
+
+ // Check if it has the expected report format
+ if (message.report && message.report.feedID) {
+ const report = message.report
+ console.log("\nReceived new report:")
+ console.log(` Feed ID: ${report.feedID}`)
+
+ // Display timestamps if available
+ if (report.validFromTimestamp) {
+ console.log(` Valid From: ${report.validFromTimestamp}`)
+ }
+
+ if (report.observationsTimestamp) {
+ console.log(` Observations Timestamp: ${report.observationsTimestamp}`)
+ }
+
+ // Display the full report with truncation for readability
+ if (report.fullReport) {
+ const reportPreview =
+ report.fullReport.length > 40 ? `${report.fullReport.substring(0, 40)}...` : report.fullReport
+ console.log(` Full Report: ${reportPreview}`)
+ }
+ } else {
+ console.log("Received message with unexpected format:", message)
+ }
+ } catch (error: any) {
+ console.error("Error parsing message:", error)
+ console.log("Raw message:", data.toString())
+ }
+ })
+}
+
+/**
+ * Main function to set up and manage the WebSocket connection
+ */
+async function main(): Promise {
+ try {
+ // Get API credentials from environment variables
+ const apiKey = process.env.STREAMS_API_KEY
+ const apiSecret = process.env.STREAMS_API_SECRET
+
+ // Validate credentials
+ if (!apiKey || !apiSecret) {
+ throw new Error(
+ "API credentials not set. Please set STREAMS_API_KEY and STREAMS_API_SECRET environment variables"
+ )
+ }
+
+ // Example feed ID (ETH/USD)
+ const feedIDs = ["0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782"]
+
+ // Set up WebSocket connection
+ const ws = await setupWebSocketConnection(apiKey, apiSecret, feedIDs)
+
+ // Set up ping/pong to keep connection alive
+ setupPingPong(ws)
+
+ // Handle incoming messages
+ handleMessages(ws)
+
+ // Set up graceful shutdown on SIGINT (Ctrl+C)
+ process.on("SIGINT", () => {
+ console.log("\nInterrupt signal received, closing connection...")
+
+ // Close the WebSocket connection gracefully
+ if (ws.readyState === ws.OPEN) {
+ ws.close(1000, "Client shutting down")
+ }
+
+ // Allow some time for the close to be sent, then exit
+ setTimeout(() => {
+ console.log("Exiting...")
+ process.exit(0)
+ }, 1000)
+ })
+ } catch (error: any) {
+ console.error("Error:", error.message)
+ process.exit(1)
+ }
+}
+
+// Start the main function
+main()
+```
+
+**Expected output**:
+
+```bash
+Connecting to: wss://ws.testnet-dataengine.chain.link/api/v1/ws?feedIDs=0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782
+WebSocket connection established
+
+Received new report:
+ Feed ID: 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782
+ Valid From: 1747930054
+ Observations Timestamp: 1747930054
+ Full Report: 0x00090d9e8d96765a0c49e03a6ae05c82e8f8de...
+
+[...]
+
+Received new report:
+ Feed ID: 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782
+ Valid From: 1747930059
+ Observations Timestamp: 1747930059
+ Full Report: 0x00090d9e8d96765a0c49e03a6ae05c82e8f8de...
+Sending ping to keep connection alive...
+Received pong from server
+
+Received new report:
+ Feed ID: 0x000359843a543ee2fe414dc14c7e7920ef10f4372990b79d6361cdc0dd1ba782
+ Valid From: 1747930060
+ Observations Timestamp: 1747930060
+ Full Report: 0x00090d9e8d96765a0c49e03a6ae05c82e8f8de...
+^C
+Interrupt signal received, closing connection...
+Exiting...
+```
+
+### Production Considerations
+
+While this example already includes many production-ready features (keepalive, timeouts, graceful shutdown), production applications should additionally consider:
+
+- **Automatic reconnection**: Implement typed exponential backoff reconnection logic for network disruptions
+- **Message queuing**: Create typed message buffers during reconnection attempts
+- **WebSocket libraries**: Consider type-safe libraries like `socket.io-client` with full TypeScript support
+- **Structured logging**: Use `winston` or `pino` with TypeScript definitions for type-safe logging
+- **Metrics collection**: Implement typed metrics for connection status, message rates, and latency
+- **Configuration management**: Use `dotenv` with type-safe schemas (e.g., `zod`) for environment configuration
+- **Error categorization**: Create custom error classes with specific types for different failure scenarios
+- **Testing**: Add unit tests with `jest` and WebSocket mocks for type-safe testing
diff --git a/src/content/data-streams/reference/streams-direct/streams-direct-go-sdk.mdx b/src/content/data-streams/reference/go-sdk.mdx
similarity index 93%
rename from src/content/data-streams/reference/streams-direct/streams-direct-go-sdk.mdx
rename to src/content/data-streams/reference/go-sdk.mdx
index 3d49aaba6ff..8f3866fa63c 100644
--- a/src/content/data-streams/reference/streams-direct/streams-direct-go-sdk.mdx
+++ b/src/content/data-streams/reference/go-sdk.mdx
@@ -1,11 +1,15 @@
---
section: dataStreams
date: Last Modified
-title: "Streams Direct SDK (Go)"
+title: "Data Streams SDK (Go)"
+metadata:
+ title: "Data Streams Go SDK Reference | Chainlink Documentation"
+ description: "Integrate with Chainlink Data Streams using the Go SDK. Learn about client configuration, authentication, fetching reports, and WebSocket streaming."
+ keywords: ["Go SDK", "Golang", "Data Streams", "Integration", "API Client", "WebSocket Client", "Report Decoding"]
whatsnext:
{
- "Learn how to fetch and decode Data Streams reports using the Data Streams SDK": "/data-streams/tutorials/streams-direct/streams-direct-api",
- "Learn how to stream and decode reports via a WebSocket connection using the Data Streams SDK": "/data-streams/tutorials/streams-direct/streams-direct-api",
+ "Learn how to fetch and decode Data Streams reports using the Data Streams SDK": "/data-streams/tutorials/api-go",
+ "Learn how to stream and decode reports via a WebSocket connection using the Data Streams SDK": "/data-streams/tutorials/ws-go",
}
---
@@ -15,17 +19,17 @@ import { PageTabs } from "@components"
+
+### API Interfaces
+
+- [REST API](/data-streams/reference/interface-api) - HTTP-based interface for simple integrations
+- [WebSocket](/data-streams/reference/interface-ws) - Real-time data streaming via WebSocket connection
+
+### SDK Integration
+
+- [Go SDK](/data-streams/reference/go-sdk) - Native Go language integration
+- [Rust SDK](/data-streams/reference/rust-sdk) - Native Rust language integration
+
+### Authentication
+
+- [Authentication](/data-streams/reference/authentication) - Learn how to authenticate with the Data Streams API (not required if using the SDKs)
+ - [JavaScript examples](/data-streams/reference/authentication/javascript-examples)
+ - [TypeScript examples](/data-streams/reference/authentication/typescript-examples)
+ - [Go examples](/data-streams/reference/authentication/go-examples)
+ - [Rust examples](/data-streams/reference/authentication/rust-examples)
+
+### Verification
+
+#### EVM chains
+
+- [Onchain report data verification](/data-streams/reference/onchain-verification) - Verify the authenticity of received data on EVM chains
+
+#### Solana
+
+- [Verify reports using the onchain integration method](/data-streams/tutorials/solana-onchain-report-verification)
+- [Verify reports using the offchain integration method](/data-streams/tutorials/solana-offchain-report-verification)
diff --git a/src/content/data-streams/reference/report-schema-v4.mdx b/src/content/data-streams/reference/report-schema-v4.mdx
index 6865d89133c..4f68ace2c30 100644
--- a/src/content/data-streams/reference/report-schema-v4.mdx
+++ b/src/content/data-streams/reference/report-schema-v4.mdx
@@ -2,6 +2,10 @@
section: dataStreams
date: Last Modified
title: "Report Schemas"
+metadata:
+ title: "Real World Asset (RWA) Report Schema (v4) | Chainlink Data Streams"
+ description: "Learn about Chainlink Data Streams Real World Asset (RWA) report schema (v4), including fields, encoding, and examples for integrating RWA data in your applications."
+ keywords: ["Report Schema", "RWA", "Real World Assets", "v4 Schema", "Data Format", "Report Structure"]
---
import DataStreams from "@features/data-streams/common/DataStreams.astro"
diff --git a/src/content/data-streams/reference/report-schema.mdx b/src/content/data-streams/reference/report-schema.mdx
index 6e33712fab1..97848116d14 100644
--- a/src/content/data-streams/reference/report-schema.mdx
+++ b/src/content/data-streams/reference/report-schema.mdx
@@ -2,6 +2,11 @@
section: dataStreams
date: Last Modified
title: "Report Schemas"
+metadata:
+ title: "Cryptocurrency Report Schema (v3) | Chainlink Data Streams"
+ description: "Learn about Chainlink Data Streams cryptocurrency report schema (v3), including fields, encoding, and examples to integrate market data into your applications."
+ keywords:
+ ["Report Schema", "Cryptocurrency", "v3 Schema", "Data Format", "Report Structure", "Liquidity-Weighted", "Bid-Ask"]
---
import DataStreams from "@features/data-streams/common/DataStreams.astro"
diff --git a/src/content/data-streams/reference/streams-direct/streams-direct-rust-sdk.mdx b/src/content/data-streams/reference/rust-sdk.mdx
similarity index 93%
rename from src/content/data-streams/reference/streams-direct/streams-direct-rust-sdk.mdx
rename to src/content/data-streams/reference/rust-sdk.mdx
index 495e4fcba74..b0cdb5a5904 100644
--- a/src/content/data-streams/reference/streams-direct/streams-direct-rust-sdk.mdx
+++ b/src/content/data-streams/reference/rust-sdk.mdx
@@ -1,11 +1,15 @@
---
section: dataStreams
date: Last Modified
-title: "Streams Direct SDK (Rust)"
+title: "Data Streams SDK (Rust)"
+metadata:
+ title: "Data Streams Rust SDK Reference | Chainlink Documentation"
+ description: "Integrate with Chainlink Data Streams using the Rust SDK. Learn about client configuration, authentication, fetching reports, and WebSocket streaming."
+ keywords: ["Rust SDK", "Data Streams", "Integration", "API Client", "WebSocket Client", "Report Decoding"]
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",
+ "Learn how to fetch and decode Data Streams reports using the Data Streams SDK": "/data-streams/tutorials/api-rust",
+ "Learn how to stream and decode reports via a WebSocket connection using the Data Streams SDK": "/data-streams/tutorials/ws-rust",
}
---
@@ -15,17 +19,17 @@ import { PageTabs } from "@components"
-
-### 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-trade-interface.mdx b/src/content/data-streams/reference/streams-trade-interface.mdx
deleted file mode 100644
index 45cb5012b9d..00000000000
--- a/src/content/data-streams/reference/streams-trade-interface.mdx
+++ /dev/null
@@ -1,28 +0,0 @@
----
-section: dataStreams
-date: Last Modified
-title: "Streams Trade Interface"
----
-
-import { Aside, CodeSample } from "@components"
-import DataStreams from "@features/data-streams/common/DataStreams.astro"
-
-
-
-To retrieve and verify reports, Streams Trade requires several interfaces.
-
-**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).
-
-## Automation interfaces
-
-- [StreamsLookupCompatibleInterface](/chainlink-automation/reference/automation-interfaces#streamslookupcompatibleinterface)
-- [ILogAutomation](/chainlink-automation/reference/automation-interfaces#ilogautomation)
-
-## Data Streams interfaces
-
-- IVerifierProxy
-- IFeeManager
-
-In the code example for using Data Streams with Automation (Streams Trade), the interfaces are specified in the example itself.
-
-
diff --git a/src/content/data-streams/streams-direct/index.mdx b/src/content/data-streams/streams-direct/index.mdx
deleted file mode 100644
index c4d23031269..00000000000
--- a/src/content/data-streams/streams-direct/index.mdx
+++ /dev/null
@@ -1,76 +0,0 @@
----
-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
index 3b684e2e932..724b3e3a40d 100644
--- a/src/content/data-streams/streams-trade/index.mdx
+++ b/src/content/data-streams/streams-trade/index.mdx
@@ -3,12 +3,17 @@ section: dataStreams
title: "Streams Trade Implementation"
date: Last Modified
isIndex: true
+metadata:
+ title: "Streams Trade Implementation | Chainlink Data Streams"
+ description: "Learn how Streams Trade combines Chainlink Data Streams with Automation to enable automated trade execution with frontrunning mitigation for DeFi applications."
+ keywords: ["Streams Trade", "Automated Execution", "Frontrunning Mitigation", "Data Streams", "Chainlink Automation"]
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",
+ "Check supported networks": "/data-streams/supported-networks#streams-trade-implementation-onchain-lookup",
+ "Explore available Stream IDs": "/data-streams/crypto-streams",
}
---
@@ -19,6 +24,7 @@ The Streams Trade implementation combines Chainlink Data Streams with [Chainlink
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).
@@ -27,7 +33,7 @@ Read more about the [Streams Trade Architecture](/data-streams/architecture#stre
To implement Streams Trade in your application:
-1. First, ensure Streams Trade is available on your desired network by checking the [Supported Networks](/data-streams/supported-networks) page.
+1. First, ensure Streams Trade is available on your desired network by checking the [Supported Networks](/data-streams/supported-networks#streams-trade-implementation-onchain-lookup) 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.
@@ -40,11 +46,3 @@ Streams Trade is particularly well-suited for:
- **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/reference/interfaces.mdx b/src/content/data-streams/streams-trade/interfaces.mdx
similarity index 66%
rename from src/content/data-streams/reference/interfaces.mdx
rename to src/content/data-streams/streams-trade/interfaces.mdx
index 15547364324..88b0f518d04 100644
--- a/src/content/data-streams/reference/interfaces.mdx
+++ b/src/content/data-streams/streams-trade/interfaces.mdx
@@ -2,6 +2,18 @@
section: dataStreams
date: Last Modified
title: "Interfaces"
+metadata:
+ title: "Streams Trade Interfaces | Chainlink Data Streams"
+ description: "Learn about the required interfaces for integrating Chainlink Data Streams with Automation, including StreamsLookupCompatibleInterface and report verification."
+ keywords:
+ [
+ "Interfaces",
+ "StreamsLookupCompatibleInterface",
+ "ILogAutomation",
+ "IVerifierProxy",
+ "IReportHandler",
+ "Data Streams",
+ ]
---
import { Aside, CodeSample } from "@components"
diff --git a/src/content/data-streams/supported-networks.mdx b/src/content/data-streams/supported-networks.mdx
index 76e28530697..411a9390263 100644
--- a/src/content/data-streams/supported-networks.mdx
+++ b/src/content/data-streams/supported-networks.mdx
@@ -4,27 +4,23 @@ date: Last Modified
title: "Supported Networks"
metadata:
title: "Chainlink Data Streams Supported Networks"
- description: "Find the list of blockchain networks supported by Chainlink Data Streams. Learn the differences in network availability for Streams Trade and Streams Direct."
+ description: "Find the list of blockchain networks supported by Chainlink Data Streams for accessing high-quality price feeds and real-world asset data."
---
import DataStreams from "@features/data-streams/common/DataStreams.astro"
-Chainlink Data Streams has two primary implementations: [Streams Direct](/data-streams/streams-direct) and [Streams Trade](/data-streams/streams-trade). Network support differs between these two implementations.
+Chainlink Data Streams provides data access directly via API or WebSocket for offchain use cases. It involves [verifying report integrity](/data-streams/tutorials/evm-onchain-report-verification) against onchain verifier proxy contracts.
-## Streams Direct (Offchain Access)
-
-Streams Direct provides data access directly via API or WebSocket for offchain use cases. It involves [verifying report integrity](/data-streams/tutorials/streams-direct/evm-onchain-report-verification) against onchain verifier proxy contracts.
-
-Streams Direct is available on any network listed on the following pages, where you can find the necessary Verifier Proxy addresses:
+Data Streams is available on any network listed on the following pages, where you can find the necessary Verifier Proxy addresses:
- [Cryptocurrency Streams](/data-streams/crypto-streams)
- [Real World Asset (RWA) Streams](/data-streams/rwa-streams)
-## Streams Trade (Onchain Lookup)
+## Streams Trade implementation (Onchain Lookup)
-Streams Trade allows smart contracts to access Data Streams onchain using the [`StreamsLookup`](/data-streams/getting-started) capability integrated with [Chainlink Automation](/chainlink-automation).
+Streams Trade, the alternative implementation, allows smart contracts to access Data Streams onchain using the [`StreamsLookup`](/data-streams/getting-started) capability integrated with [Chainlink Automation](/chainlink-automation).
Streams Trade is currently available on the following networks:
diff --git a/src/content/data-streams/tutorials/streams-direct/streams-direct-api-go.mdx b/src/content/data-streams/tutorials/api-go.mdx
similarity index 93%
rename from src/content/data-streams/tutorials/streams-direct/streams-direct-api-go.mdx
rename to src/content/data-streams/tutorials/api-go.mdx
index b9b78df4596..a08830b6f83 100644
--- a/src/content/data-streams/tutorials/streams-direct/streams-direct-api-go.mdx
+++ b/src/content/data-streams/tutorials/api-go.mdx
@@ -2,10 +2,14 @@
section: dataStreams
date: Last Modified
title: "Fetch and decode V3 reports using the Go SDK"
+metadata:
+ title: "Fetch and Decode Cryptocurrency Data with Go SDK | Chainlink Data Streams"
+ description: "Learn how to use the Go SDK to fetch and decode cryptocurrency market data reports from Chainlink Data Streams in your Go applications."
+ keywords: ["Go SDK", "Golang", "Cryptocurrency", "V3 Reports", "API Tutorial", "Data Streams", "Market Data"]
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",
+ "Learn how to stream and decode reports via a WebSocket connection": "/data-streams/tutorials/ws-go",
+ "Learn how to verify your data onchain": "/data-streams/reference/onchain-verification",
"Find the list of available Stream IDs": "/data-streams/crypto-streams",
}
---
@@ -19,28 +23,28 @@ import DataStreams from "@features/data-streams/common/DataStreams.astro"
pages={[
{
name: "Go SDK - V3 reports for Crypto streams",
- url: "/data-streams/tutorials/streams-direct/streams-direct-api-go",
+ url: "/data-streams/tutorials/api-go",
icon: "/images/tutorial-icons/go_logo_black.png",
},
{
name: "Go SDK - V4 reports for RWA streams",
- url: "/data-streams/tutorials/streams-direct/streams-direct-api-rwa-go",
+ url: "/data-streams/tutorials/api-rwa-go",
icon: "/images/tutorial-icons/go_logo_black.png",
},
{
name: "Rust SDK - V3 reports for Crypto streams",
- url: "/data-streams/tutorials/streams-direct/streams-direct-api-rust",
+ url: "/data-streams/tutorials/api-rust",
icon: "/images/tutorial-icons/rust_logo_blk.svg",
},
{
name: "Rust SDK - V4 reports for RWA streams",
- url: "/data-streams/tutorials/streams-direct/streams-direct-api-rwa-rust",
+ url: "/data-streams/tutorials/api-rwa-rust",
icon: "/images/tutorial-icons/rust_logo_blk.svg",
},
]}
/>
-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.
+In this tutorial, you'll learn how to use the [Data Streams SDK](/data-streams/reference/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.
@@ -48,9 +52,9 @@ In this guide, you'll learn how to use Chainlink Data Streams with the _[Streams
- **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 access.
+- **API Credentials**: Access to Data Streams 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 access.
-## Guide
+## Tutorial
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.
@@ -210,9 +214,9 @@ You'll start with the set up of your Go project. Next, you'll fetch and decode r
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.
+ - `RestURL` is the REST endpoint to poll for specific reports. See the [Data Streams Interface](/data-streams/reference/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.
+ See the [SDK Reference](/data-streams/reference/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.
@@ -258,9 +262,9 @@ The decoded report details include:
#### Payload for onchain verification
-In this guide, you log and decode the `full_report` payload to extract the report data. In a
+In this tutorial, 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.
+[Verify report data onchain](/data-streams/tutorials/evm-onchain-report-verification) tutorial.
### Fetch and decode reports for multiple streams
@@ -447,7 +451,7 @@ production environment, you should verify the data to ensure its integrity and a
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.
+[Verify report data onchain](/data-streams/tutorials/evm-onchain-report-verification) guide.
## Explanation
diff --git a/src/content/data-streams/tutorials/streams-direct/streams-direct-api-rust.mdx b/src/content/data-streams/tutorials/api-rust.mdx
similarity index 91%
rename from src/content/data-streams/tutorials/streams-direct/streams-direct-api-rust.mdx
rename to src/content/data-streams/tutorials/api-rust.mdx
index bab84fa47d4..f49aa042c39 100644
--- a/src/content/data-streams/tutorials/streams-direct/streams-direct-api-rust.mdx
+++ b/src/content/data-streams/tutorials/api-rust.mdx
@@ -2,10 +2,14 @@
section: dataStreams
date: Last Modified
title: "Fetch and decode V3 reports using the Rust SDK"
+metadata:
+ title: "Fetch and Decode Cryptocurrency Data with Rust SDK | Chainlink Data Streams"
+ description: "Learn how to use the Rust SDK to fetch and decode cryptocurrency market data reports from Chainlink Data Streams in your Rust applications."
+ keywords: ["Rust SDK", "Cryptocurrency", "V3 Reports", "API Tutorial", "Data Streams", "Market Data", "Async"]
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",
+ "Learn how to stream and decode reports via a WebSocket connection": "/data-streams/tutorials/ws-rust",
+ "Learn how to verify your data onchain": "/data-streams/reference/onchain-verification",
"Find the list of available Stream IDs": "/data-streams/crypto-streams",
}
---
@@ -19,37 +23,37 @@ import DataStreams from "@features/data-streams/common/DataStreams.astro"
pages={[
{
name: "Go SDK - V3 reports for Crypto streams",
- url: "/data-streams/tutorials/streams-direct/streams-direct-api-go",
+ url: "/data-streams/tutorials/api-go",
icon: "/images/tutorial-icons/go_logo_black.png",
},
{
name: "Go SDK - V4 reports for RWA streams",
- url: "/data-streams/tutorials/streams-direct/streams-direct-api-rwa-go",
+ url: "/data-streams/tutorials/api-rwa-go",
icon: "/images/tutorial-icons/go_logo_black.png",
},
{
name: "Rust SDK - V3 reports for Crypto streams",
- url: "/data-streams/tutorials/streams-direct/streams-direct-api-rust",
+ url: "/data-streams/tutorials/api-rust",
icon: "/images/tutorial-icons/rust_logo_blk.svg",
},
{
name: "Rust SDK - V4 reports for RWA streams",
- url: "/data-streams/tutorials/streams-direct/streams-direct-api-rwa-rust",
+ url: "/data-streams/tutorials/api-rwa-rust",
icon: "/images/tutorial-icons/rust_logo_blk.svg",
},
]}
/>
-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.
+In this tutorial, you'll learn how to use the [Data Streams SDK](/data-streams/reference/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
- **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 access.
+- **API Credentials**: Access to Data Streams 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 access.
-## Guide
+## Tutorial
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.
@@ -197,9 +201,9 @@ The decoded report details include:
#### Payload for onchain verification
-In this guide, you log and decode the `full_report` payload to extract the report data. In a
+In this tutorial, 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.
+[Verify report data onchain](/data-streams/tutorials/evm-onchain-report-verification) tutorial.
## Explanation
diff --git a/src/content/data-streams/tutorials/streams-direct/streams-direct-api-rwa-go.mdx b/src/content/data-streams/tutorials/api-rwa-go.mdx
similarity index 93%
rename from src/content/data-streams/tutorials/streams-direct/streams-direct-api-rwa-go.mdx
rename to src/content/data-streams/tutorials/api-rwa-go.mdx
index 86419755fc7..2bd849de188 100644
--- a/src/content/data-streams/tutorials/streams-direct/streams-direct-api-rwa-go.mdx
+++ b/src/content/data-streams/tutorials/api-rwa-go.mdx
@@ -2,11 +2,15 @@
section: dataStreams
date: Last Modified
title: "Fetch and decode V4 reports using the Go SDK"
+metadata:
+ title: "Fetch and Decode Real World Asset Data with Go SDK | Chainlink Data Streams"
+ description: "Learn how to use the Go SDK to fetch and decode Real World Asset (RWA) market data reports with V4 schema from Chainlink Data Streams."
+ keywords: ["Go SDK", "Golang", "RWA", "Real World Assets", "V4 Reports", "API Tutorial", "Data 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",
+ "Learn how to stream and decode reports via a WebSocket connection": "/data-streams/tutorials/ws-rwa-go",
+ "Learn how to verify your data onchain": "/data-streams/reference/onchain-verification",
+ "Find the list of available Stream IDs": "/data-streams/rwa-streams",
}
---
@@ -19,28 +23,28 @@ import DataStreams from "@features/data-streams/common/DataStreams.astro"
pages={[
{
name: "Go SDK - V3 reports for Crypto streams",
- url: "/data-streams/tutorials/streams-direct/streams-direct-api-go",
+ url: "/data-streams/tutorials/api-go",
icon: "/images/tutorial-icons/go_logo_black.png",
},
{
name: "Go SDK - V4 reports for RWA streams",
- url: "/data-streams/tutorials/streams-direct/streams-direct-api-rwa-go",
+ url: "/data-streams/tutorials/api-rwa-go",
icon: "/images/tutorial-icons/go_logo_black.png",
},
{
name: "Rust SDK - V3 reports for Crypto streams",
- url: "/data-streams/tutorials/streams-direct/streams-direct-api-rust",
+ url: "/data-streams/tutorials/api-rust",
icon: "/images/tutorial-icons/rust_logo_blk.svg",
},
{
name: "Rust SDK - V4 reports for RWA streams",
- url: "/data-streams/tutorials/streams-direct/streams-direct-api-rwa-rust",
+ url: "/data-streams/tutorials/api-rwa-rust",
icon: "/images/tutorial-icons/rust_logo_blk.svg",
},
]}
/>
-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.
+In this tutorial, you'll learn how to use the [Data Streams SDK](/data-streams/reference/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.
@@ -48,9 +52,9 @@ In this guide, you'll learn how to use Chainlink Data Streams with the _[Streams
- **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 access.
+- **API Credentials**: Access to Data Streams 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 access.
-## Guide
+## Tutorial
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.
@@ -208,9 +212,9 @@ You'll start with the set up of your Go project. Next, you'll fetch and decode r
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.
+ - `RestURL` is the REST endpoint to poll for specific reports. See the [Data Streams Interface](/data-streams/reference/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.
+ See the [SDK Reference](/data-streams/reference/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.
@@ -255,9 +259,9 @@ 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
+In this tutorial, 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.
+[Verify report data onchain](/data-streams/tutorials/evm-onchain-report-verification) tutorial.
### Fetch and decode reports for multiple streams
@@ -440,7 +444,7 @@ production environment, you should verify the data to ensure its integrity and a
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.
+[Verify report data onchain](/data-streams/tutorials/evm-onchain-report-verification) guide.
## Explanation
diff --git a/src/content/data-streams/tutorials/streams-direct/streams-direct-api-rwa-rust.mdx b/src/content/data-streams/tutorials/api-rwa-rust.mdx
similarity index 90%
rename from src/content/data-streams/tutorials/streams-direct/streams-direct-api-rwa-rust.mdx
rename to src/content/data-streams/tutorials/api-rwa-rust.mdx
index 78c5e629247..a2946f20366 100644
--- a/src/content/data-streams/tutorials/streams-direct/streams-direct-api-rwa-rust.mdx
+++ b/src/content/data-streams/tutorials/api-rwa-rust.mdx
@@ -2,10 +2,15 @@
section: dataStreams
date: Last Modified
title: "Fetch and decode V4 reports using the Rust SDK"
+metadata:
+ title: "Fetch and Decode Real World Asset Data with Rust SDK | Chainlink Data Streams"
+ description: "Learn how to use the Rust SDK to fetch and decode Real World Asset (RWA) market data reports with V4 schema from Chainlink Data Streams."
+ keywords:
+ ["Rust SDK", "RWA", "Real World Assets", "V4 Reports", "API Tutorial", "Data Streams", "Forex", "Commodities"]
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",
+ "Learn how to stream and decode reports via a WebSocket connection": "/data-streams/tutorials/ws-rwa-rust",
+ "Learn how to verify your data onchain": "/data-streams/reference/onchain-verification",
"Find the list of available Stream IDs": "/data-streams/rwa-streams",
}
---
@@ -19,37 +24,37 @@ import DataStreams from "@features/data-streams/common/DataStreams.astro"
pages={[
{
name: "Go SDK - V3 reports for Crypto streams",
- url: "/data-streams/tutorials/streams-direct/streams-direct-api-go",
+ url: "/data-streams/tutorials/api-go",
icon: "/images/tutorial-icons/go_logo_black.png",
},
{
name: "Go SDK - V4 reports for RWA streams",
- url: "/data-streams/tutorials/streams-direct/streams-direct-api-rwa-go",
+ url: "/data-streams/tutorials/api-rwa-go",
icon: "/images/tutorial-icons/go_logo_black.png",
},
{
name: "Rust SDK - V3 reports for Crypto streams",
- url: "/data-streams/tutorials/streams-direct/streams-direct-api-rust",
+ url: "/data-streams/tutorials/api-rust",
icon: "/images/tutorial-icons/rust_logo_blk.svg",
},
{
name: "Rust SDK - V4 reports for RWA streams",
- url: "/data-streams/tutorials/streams-direct/streams-direct-api-rwa-rust",
+ url: "/data-streams/tutorials/api-rwa-rust",
icon: "/images/tutorial-icons/rust_logo_blk.svg",
},
]}
/>
-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.
+In this tutorial, you'll learn how to use the [Data Streams SDK](/data-streams/reference/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
- **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 access.
+- **API Credentials**: Access to Data Streams 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 access.
-## Guide
+## Tutorial
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.
@@ -194,9 +199,9 @@ The decoded report details include:
#### Payload for onchain verification
-In this guide, you log and decode the `full_report` payload to extract the report data. In a
+In this tutorial, 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.
+[Verify report data onchain](/data-streams/tutorials/evm-onchain-report-verification) tutorial.
## Explanation
diff --git a/src/content/data-streams/tutorials/streams-direct/evm-onchain-report-verification.mdx b/src/content/data-streams/tutorials/evm-onchain-report-verification.mdx
similarity index 73%
rename from src/content/data-streams/tutorials/streams-direct/evm-onchain-report-verification.mdx
rename to src/content/data-streams/tutorials/evm-onchain-report-verification.mdx
index 175ab9a04c7..516b0dd7d07 100644
--- a/src/content/data-streams/tutorials/streams-direct/evm-onchain-report-verification.mdx
+++ b/src/content/data-streams/tutorials/evm-onchain-report-verification.mdx
@@ -1,7 +1,12 @@
---
section: dataStreams
date: Last Modified
-title: "Verify report data onchain"
+title: "Verify report data onchain (EVM)"
+metadata:
+ title: "Verify Data Streams Reports Onchain (EVM) | Chainlink Tutorial"
+ description: "Learn how to verify Chainlink Data Streams reports onchain using Solidity smart contracts on EVM-compatible blockchains to ensure data integrity."
+ keywords:
+ ["Onchain Verification", "EVM", "Solidity", "Smart Contract", "Data Integrity", "Tutorial", "Verifier Contract"]
whatsnext: { "Find the list of available Stream IDs": "/data-streams/crypto-streams" }
---
@@ -15,36 +20,36 @@ import DataStreams from "@features/data-streams/common/DataStreams.astro"
pages={[
{
name: "EVM Chains (Solidity)",
- url: "/data-streams/tutorials/streams-direct/evm-onchain-report-verification",
+ url: "/data-streams/tutorials/evm-onchain-report-verification",
icon: "/images/tutorial-icons/solidity_logo.svg",
},
{
name: "Solana (Rust) / onchain integration",
- url: "/data-streams/tutorials/streams-direct/solana-onchain-report-verification",
+ url: "/data-streams/tutorials/solana-onchain-report-verification",
icon: "/images/tutorial-icons/solanaLogoMark.svg",
},
{
name: "Solana (Rust) / offchain integration",
- url: "/data-streams/tutorials/streams-direct/solana-offchain-report-verification",
+ url: "/data-streams/tutorials/solana-offchain-report-verification",
icon: "/images/tutorial-icons/solanaLogoMark.svg",
},
]}
/>
-In this guide, you'll learn how to verify onchain the integrity of reports by confirming their authenticity as signed by the Decentralized Oracle Network (DON). You'll use a verifier contract to verify the data onchain and pay the verification fee in LINK tokens.
+In this tutorial, you'll learn how to verify onchain the integrity of reports by confirming their authenticity as signed by the Decentralized Oracle Network (DON). You'll use a verifier contract to verify the data onchain and pay the verification fee in LINK tokens.
## Before you begin
-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:
+Make sure you understand how to fetch reports via the [REST API](/data-streams/reference/interface-api) or [WebSocket](/data-streams/reference/interface-ws) connection. Refer to the following tutorials 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)
+- [Fetch and decode reports via a REST API](/data-streams/tutorials/api-go)
+- [Stream and decode reports via WebSocket](/data-streams/tutorials/ws-go)
## Requirements
-- This guide requires testnet ETH and LINK on _Arbitrum Sepolia_. Both are available at [faucets.chain.link](https://faucets.chain.link/arbitrum-sepolia).
+- This tutorial requires testnet ETH and LINK on _Arbitrum Sepolia_. Both are available at [faucets.chain.link](https://faucets.chain.link/arbitrum-sepolia).
- Learn how to [Fund your contract with LINK](/resources/fund-your-contract).
## Tutorial
@@ -62,6 +67,7 @@ Deploy a `ClientReportsVerifier` contract on _Arbitrum Sepolia_. This contract i
@@ -82,6 +88,7 @@ Deploy a `ClientReportsVerifier` contract on _Arbitrum Sepolia_. This contract i
@@ -90,6 +97,7 @@ Deploy a `ClientReportsVerifier` contract on _Arbitrum Sepolia_. This contract i
@@ -100,6 +108,7 @@ Deploy a `ClientReportsVerifier` contract on _Arbitrum Sepolia_. This contract i
@@ -117,18 +126,17 @@ For this tutorial on _Arbitrum Sepolia_, fees are required, so you need to fund
1. In Remix, on the **Deploy & Run Transactions** tab, expand your verifier contract under the **Deployed Contracts** section.
-1. Fill in the `verifyReport` function input parameter with the report payload you want to verify. You can use the following full report payload obtained in the [Fetch and decode report via a REST API](/data-streams/tutorials/streams-direct/streams-direct-api) guide as an example:
+1. Fill in the `verifyReport` function input parameter with the report payload you want to verify. You can use the following full report payload obtained in the [Fetch and decode report via a REST API](/data-streams/tutorials/api-go) tutorial as an example:
- ```
- 0x000660403d36be006d0c15d9b306f93c8660c5cfeab7db8e28c78ba316d395970000000000000000000000000000000000000000000000000000000032c3780a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001200003c8e550d2fc5304993010112de9b69798297e4cc11990ee6250e464daf760000000000000000000000000000000000000000000000000000000006706e595000000000000000000000000000000000000000000000000000000006706e595000000000000000000000000000000000000000000000000000025bd3eb74c080000000000000000000000000000000000000000000000000021c6a95c654c7400000000000000000000000000000000000000000000000000000000670837150000000000000000000000000000000000000000000000079a2ab4077fc8fc6000000000000000000000000000000000000000000000000799fcb42536dfd8300000000000000000000000000000000000000000000000079a59496c3f29a0000000000000000000000000000000000000000000000000000000000000000002bd4acd37ce3cd5799de05d156ab328a5effd94468ebbaf2ff18d13d9631259cbe66cca01af6a8bb36e79d2d731a44e16791ee31e46ce27ed6530f1590cd7734c0000000000000000000000000000000000000000000000000000000000000002391562f1f2e4986bdb978fbf5ee27f7012992a79301af42d3473761ef2ede6271a61fbf4b32ac5be68a598bcfa523e035b624dab3b3d9a46276834f824ee592a
- ```
+ ```
+ 0x000660403d36be006d0c15d9b306f93c8660c5cfeab7db8e28c78ba316d395970000000000000000000000000000000000000000000000000000000032c3780a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001200003c8e550d2fc5304993010112de9b69798297e4cc11990ee6250e464daf760000000000000000000000000000000000000000000000000000000006706e595000000000000000000000000000000000000000000000000000000006706e595000000000000000000000000000000000000000000000000000025bd3eb74c080000000000000000000000000000000000000000000000000021c6a95c654c7400000000000000000000000000000000000000000000000000000000670837150000000000000000000000000000000000000000000000079a2ab4077fc8fc6000000000000000000000000000000000000000000000000799fcb42536dfd8300000000000000000000000000000000000000000000000079a59496c3f29a0000000000000000000000000000000000000000000000000000000000000000002bd4acd37ce3cd5799de05d156ab328a5effd94468ebbaf2ff18d13d9631259cbe66cca01af6a8bb36e79d2d731a44e16791ee31e46ce27ed6530f1590cd7734c0000000000000000000000000000000000000000000000000000000000000002391562f1f2e4986bdb978fbf5ee27f7012992a79301af42d3473761ef2ede6271a61fbf4b32ac5be68a598bcfa523e035b624dab3b3d9a46276834f824ee592a
+ ```
- {" "}
-
1. Click the `verifyReport` button to call the function. MetaMask prompts you to accept the transaction.
@@ -138,6 +146,7 @@ For this tutorial on _Arbitrum Sepolia_, fees are required, so you need to fund
diff --git a/src/content/data-streams/tutorials/overview.mdx b/src/content/data-streams/tutorials/overview.mdx
new file mode 100644
index 00000000000..956f15d3ebe
--- /dev/null
+++ b/src/content/data-streams/tutorials/overview.mdx
@@ -0,0 +1,35 @@
+---
+section: dataStreams
+date: Last Modified
+title: "Data Streams Tutorials"
+isIndex: true
+metadata:
+ title: "Data Streams Tutorials | Learn to Build with Chainlink"
+ description: "Follow step-by-step tutorials for Chainlink Data Streams integration. Learn to fetch, decode, and verify market data in your applications."
+ keywords: ["Tutorials", "Data Streams", "Integration", "SDK", "API", "WebSocket", "Verification"]
+---
+
+import { Aside } from "@components"
+import DataStreams from "@features/data-streams/common/DataStreams.astro"
+
+
+
+Explore several tutorials to learn how to use the Data Streams.
+
+## Fetch, Stream, and Decode Reports
+
+- [Fetch and decode reports](/data-streams/tutorials/api-go): Learn how to fetch and decode reports from the Data Streams Aggregation Network, using the [Go](/data-streams/reference/go-sdk) or [Rust](/data-streams/reference/rust-sdk) SDKs.
+- [Stream and decode reports (WebSocket)](/data-streams/tutorials/ws-go): Learn how to listen for real-time reports from the Data Streams Aggregation Network, decode the report data, and log their attributes, using the [Go](/data-streams/reference/go-sdk) or [Rust](/data-streams/reference/rust-sdk) SDKs.
+
+
+
+## Verify Reports
+
+- [EVM onchain](/data-streams/tutorials/evm-onchain-report-verification): Learn how to verify onchain the integrity of reports by confirming their authenticity as signed by the Decentralized Oracle Network (DON).
+- [Solana onchain integration](/data-streams/tutorials/solana-onchain-report-verification): Learn how to verify Chainlink Data Streams reports directly within your Solana program using Cross-Program Invocation (CPI) to ensure data integrity.
+- [Solana offchain integration](/data-streams/tutorials/solana-offchain-report-verification): Learn how to verify Chainlink Data Streams reports client-side using the Rust SDK on Solana to ensure data authenticity before using it in your application.
diff --git a/src/content/data-streams/tutorials/streams-direct/solana-offchain-report-verification.mdx b/src/content/data-streams/tutorials/solana-offchain-report-verification.mdx
similarity index 90%
rename from src/content/data-streams/tutorials/streams-direct/solana-offchain-report-verification.mdx
rename to src/content/data-streams/tutorials/solana-offchain-report-verification.mdx
index a1011df53a0..ca421e1cb02 100644
--- a/src/content/data-streams/tutorials/streams-direct/solana-offchain-report-verification.mdx
+++ b/src/content/data-streams/tutorials/solana-offchain-report-verification.mdx
@@ -2,10 +2,14 @@
section: dataStreams
date: Last Modified
title: "Verify report data - Offchain integration (Solana)"
+metadata:
+ title: "Verify Data Streams Reports Offchain on Solana | Chainlink Tutorial"
+ description: "Learn how to verify Chainlink Data Streams reports client-side using the Rust SDK on Solana to ensure data authenticity before using it in your application."
+ keywords: ["Offchain Verification", "Solana", "Rust", "Client-side", "Verification", "Data Integrity", "Tutorial"]
whatsnext:
{
"Find the list of available Stream IDs": "/data-streams/crypto-streams",
- "Learn how to verify reports on Solana onchain": "/data-streams/tutorials/streams-direct/solana-onchain-report-verification",
+ "Learn how to verify reports on Solana onchain": "/data-streams/tutorials/solana-onchain-report-verification",
}
---
@@ -19,17 +23,17 @@ import DataStreams from "@features/data-streams/common/DataStreams.astro"
pages={[
{
name: "EVM Chains (Solidity)",
- url: "/data-streams/tutorials/streams-direct/evm-onchain-report-verification",
+ url: "/data-streams/tutorials/evm-onchain-report-verification",
icon: "/images/tutorial-icons/solidity_logo.svg",
},
{
- name: "Solana (Rust) - Onchain integration",
- url: "/data-streams/tutorials/streams-direct/solana-onchain-report-verification",
+ name: "Solana (Rust) / onchain integration",
+ url: "/data-streams/tutorials/solana-onchain-report-verification",
icon: "/images/tutorial-icons/solanaLogoMark.svg",
},
{
- name: "Solana (Rust) - Offchain integration",
- url: "/data-streams/tutorials/streams-direct/solana-offchain-report-verification",
+ name: "Solana (Rust) / offchain integration",
+ url: "/data-streams/tutorials/solana-offchain-report-verification",
icon: "/images/tutorial-icons/solanaLogoMark.svg",
},
]}
@@ -39,9 +43,9 @@ To verify a Data Streams report, you must confirm the report integrity signed by
You have two options to verify Data Streams reports on Solana:
-1. **Onchain integration**: Verify reports directly within your Solana program using [Cross-Program Invocation (CPI)](https://solana.com/docs/core/cpi) to the verifier program. Learn more about this method in the [onchain verification guide](/data-streams/tutorials/streams-direct/solana-onchain-report-verification).
+1. **Onchain integration**: Verify reports directly within your Solana program using [Cross-Program Invocation (CPI)](https://solana.com/docs/core/cpi) to the verifier program. Learn more about this method in the [onchain verification tutorial](/data-streams/tutorials/solana-onchain-report-verification).
-1. **Offchain integration**: Verify reports client-side using an SDK. You'll learn how to implement this method in this guide.
+1. **Offchain integration**: Verify reports client-side using an SDK. You'll learn how to implement this method in this tutorial.
Both methods use the same underlying verification logic and security guarantees, differing only in where the verification occurs.
@@ -49,7 +53,7 @@ Both methods use the same underlying verification logic and security guarantees,
The offchain integration allows you to verify the authenticity of Data Streams reports from your client-side application. While this method requires sending a transaction to the verifier program, the verification logic and processing of results happens in your client application rather than in a Solana program.
-In this guide, you'll learn how to:
+In this tutorial, you'll learn how to:
- Set up an Anchor project
- Configure the necessary dependencies
@@ -71,7 +75,7 @@ Before you begin, you should have:
### Requirements
-To complete this guide, you'll need:
+To complete this tutorial, you'll need:
- **Rust and Cargo**: Install the latest version using [rustup](https://rustup.rs/). Run to verify your installation.
@@ -83,9 +87,9 @@ To complete this guide, you'll need:
- **Allowlisted Account**: Your account must be allowlisted in the Data Streams Access Controller.
-> **Note**: While this guide uses the Anchor framework for project structure, you can integrate the verification using any Rust-based Solana project setup. The verifier SDK and client libraries are written in Rust, but you can integrate them into your preferred Rust project structure.
+> **Note**: While this tutorial uses the Anchor framework for project structure, you can integrate the verification using any Rust-based Solana project setup. The verifier SDK and client libraries are written in Rust, but you can integrate them into your preferred Rust project structure.
-### Implementation guide
+### Implementation tutorial
#### 1. Create a new Anchor project
diff --git a/src/content/data-streams/tutorials/streams-direct/solana-onchain-report-verification.mdx b/src/content/data-streams/tutorials/solana-onchain-report-verification.mdx
similarity index 93%
rename from src/content/data-streams/tutorials/streams-direct/solana-onchain-report-verification.mdx
rename to src/content/data-streams/tutorials/solana-onchain-report-verification.mdx
index 2c09402a5bd..f28fba61d0d 100644
--- a/src/content/data-streams/tutorials/streams-direct/solana-onchain-report-verification.mdx
+++ b/src/content/data-streams/tutorials/solana-onchain-report-verification.mdx
@@ -2,10 +2,23 @@
section: dataStreams
date: Last Modified
title: "Verify report data - Onchain integration (Solana)"
+metadata:
+ title: "Verify Data Streams Reports Onchain on Solana | Chainlink Tutorial"
+ description: "Learn how to verify Chainlink Data Streams reports directly within your Solana program using Cross-Program Invocation (CPI) to ensure data integrity."
+ keywords:
+ [
+ "Onchain Verification",
+ "Solana",
+ "Rust",
+ "CPI",
+ "Cross-Program Invocation",
+ "Program Verification",
+ "Anchor Framework",
+ ]
whatsnext:
{
"Find the list of available Stream IDs": "/data-streams/crypto-streams",
- "Learn how to verify reports on Solana offchain": "/data-streams/tutorials/streams-direct/solana-offchain-report-verification",
+ "Learn how to verify reports on Solana offchain": "/data-streams/tutorials/solana-offchain-report-verification",
}
---
@@ -19,17 +32,17 @@ import DataStreams from "@features/data-streams/common/DataStreams.astro"
pages={[
{
name: "EVM Chains (Solidity)",
- url: "/data-streams/tutorials/streams-direct/evm-onchain-report-verification",
+ url: "/data-streams/tutorials/evm-onchain-report-verification",
icon: "/images/tutorial-icons/solidity_logo.svg",
},
{
- name: "Solana (Rust) - Onchain integration",
- url: "/data-streams/tutorials/streams-direct/solana-onchain-report-verification",
+ name: "Solana (Rust) / onchain integration",
+ url: "/data-streams/tutorials/solana-onchain-report-verification",
icon: "/images/tutorial-icons/solanaLogoMark.svg",
},
{
- name: "Solana (Rust) - Offchain integration",
- url: "/data-streams/tutorials/streams-direct/solana-offchain-report-verification",
+ name: "Solana (Rust) / offchain integration",
+ url: "/data-streams/tutorials/solana-offchain-report-verification",
icon: "/images/tutorial-icons/solanaLogoMark.svg",
},
]}
@@ -39,9 +52,9 @@ To verify a Data Streams report, you must confirm the report integrity signed by
You have two options to verify Data Streams reports on Solana:
-1. **Onchain integration**: Verify reports directly within your Solana program using [Cross-Program Invocation (CPI)](https://solana.com/docs/core/cpi) to the Verifier program. You'll learn how to implement this method in this guide.
+1. **Onchain integration**: Verify reports directly within your Solana program using [Cross-Program Invocation (CPI)](https://solana.com/docs/core/cpi) to the Verifier program. You'll learn how to implement this method in this tutorial.
-1. **Offchain integration**: Verify reports client-side using an SDK. Learn more about this method in the [offchain verification guide](/data-streams/tutorials/streams-direct/solana-offchain-report-verification).
+1. **Offchain integration**: Verify reports client-side using an SDK. Learn more about this method in the [offchain verification tutorial](/data-streams/tutorials/solana-offchain-report-verification).
Both methods use the same underlying verification logic and security guarantees, differing only in where the verification occurs.
@@ -49,7 +62,7 @@ Both methods use the same underlying verification logic and security guarantees,
You can verify Data Streams reports directly within your Solana program using this integration. This method ensures atomic verification and processing of report data.
-In this guide, you'll learn how to:
+In this tutorial, you'll learn how to:
- Integrate with the Chainlink Data Streams Verifier program
- Create and invoke the verification instruction
@@ -71,7 +84,7 @@ Before you begin, you should have:
### Requirements
-To complete this guide, you'll need:
+To complete this tutorial, you'll need:
- **Rust and Cargo**: Install the latest version using [rustup](https://rustup.rs/). Run to verify your installation.
@@ -85,9 +98,9 @@ To complete this guide, you'll need:
- **Devnet SOL**: You'll need devnet SOL for deployment and testing. Use the [Solana CLI](https://docs.solana.com/cli/transfer-tokens#airdrop-some-tokens-to-get-started) or the [Solana Faucet](https://faucet.solana.com/) to get devnet SOL.
-> **Note**: While this guide uses the Anchor framework for project structure, you can integrate the verification using any Rust-based Solana program framework. The verifier SDK is written in Rust, but you can integrate it into your preferred Rust program structure.
+> **Note**: While this tutorial uses the Anchor framework for project structure, you can integrate the verification using any Rust-based Solana program framework. The verifier SDK is written in Rust, but you can integrate it into your preferred Rust program structure.
-### Implementation guide
+### Implementation tutorial
#### 1. Create a new Anchor project
@@ -499,7 +512,7 @@ The SDK's `VerifierInstructions::verify` helper method performs these steps:
#### Best practices
-This guide provides a basic example on how to verify reports. When you implement reports verification, consider the following best practices:
+This tutorial provides a basic example on how to verify reports. When you implement reports verification, consider the following best practices:
- Implement robust error handling:
- Handle verification failures and invalid reports comprehensively
diff --git a/src/content/data-streams/tutorials/streams-direct/index.mdx b/src/content/data-streams/tutorials/streams-direct/index.mdx
deleted file mode 100644
index fa761cfd3f0..00000000000
--- a/src/content/data-streams/tutorials/streams-direct/index.mdx
+++ /dev/null
@@ -1,12 +0,0 @@
----
-section: dataStreams
-date: Last Modified
-title: "Streams Direct guides"
-isIndex: true
----
-
-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.
-- [Verify report data onchain](/data-streams/tutorials/streams-direct/streams-direct-onchain-verification): Learn how to verify onchain the integrity of reports by confirming their authenticity as signed by the Decentralized Oracle Network (DON).
diff --git a/src/content/data-streams/getting-started-hardhat.mdx b/src/content/data-streams/tutorials/streams-trade/getting-started-hardhat.mdx
similarity index 86%
rename from src/content/data-streams/getting-started-hardhat.mdx
rename to src/content/data-streams/tutorials/streams-trade/getting-started-hardhat.mdx
index ab3e2d3cacf..cf38cd506b4 100644
--- a/src/content/data-streams/getting-started-hardhat.mdx
+++ b/src/content/data-streams/tutorials/streams-trade/getting-started-hardhat.mdx
@@ -20,12 +20,12 @@ import DataStreams from "@features/data-streams/common/DataStreams.astro"
pages={[
{
name: "Remix",
- url: "/data-streams/getting-started",
+ url: "/data-streams/tutorials/streams-trade/getting-started",
icon: "/images/tutorial-icons/remix-icn.png",
},
{
name: "Hardhat",
- url: "/data-streams/getting-started-hardhat",
+ url: "/data-streams/tutorials/streams-trade/getting-started-hardhat",
icon: "/images/tutorial-icons/hardhat-icn.png",
},
]}
diff --git a/src/content/data-streams/getting-started.mdx b/src/content/data-streams/tutorials/streams-trade/getting-started.mdx
similarity index 86%
rename from src/content/data-streams/getting-started.mdx
rename to src/content/data-streams/tutorials/streams-trade/getting-started.mdx
index ac984346657..76d540f4dde 100644
--- a/src/content/data-streams/getting-started.mdx
+++ b/src/content/data-streams/tutorials/streams-trade/getting-started.mdx
@@ -20,12 +20,12 @@ import DataStreams from "@features/data-streams/common/DataStreams.astro"
pages={[
{
name: "Remix",
- url: "/data-streams/getting-started",
+ url: "/data-streams/tutorials/streams-trade/getting-started",
icon: "/images/tutorial-icons/remix-icn.png",
},
{
name: "Hardhat",
- url: "/data-streams/getting-started-hardhat",
+ url: "/data-streams/tutorials/streams-trade/getting-started-hardhat",
icon: "/images/tutorial-icons/hardhat-icn.png",
},
]}
diff --git a/src/content/data-streams/tutorials/streams-trade/index.mdx b/src/content/data-streams/tutorials/streams-trade/index.mdx
index c4c6874cd3a..6adc54e53f9 100644
--- a/src/content/data-streams/tutorials/streams-trade/index.mdx
+++ b/src/content/data-streams/tutorials/streams-trade/index.mdx
@@ -7,7 +7,7 @@ isIndex: true
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.
+- [Getting Started](/data-streams/tutorials/streams-trade/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.
**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).
diff --git a/src/content/data-streams/tutorials/streams-direct/streams-direct-ws-go.mdx b/src/content/data-streams/tutorials/ws-go.mdx
similarity index 90%
rename from src/content/data-streams/tutorials/streams-direct/streams-direct-ws-go.mdx
rename to src/content/data-streams/tutorials/ws-go.mdx
index 638b7f37986..9b4cf71d50a 100644
--- a/src/content/data-streams/tutorials/streams-direct/streams-direct-ws-go.mdx
+++ b/src/content/data-streams/tutorials/ws-go.mdx
@@ -2,9 +2,13 @@
section: dataStreams
date: Last Modified
title: "Stream and decode V3 reports via WebSocket using the Go SDK"
+metadata:
+ title: "Stream Real-time Cryptocurrency Data with Go SDK | WebSocket Tutorial"
+ description: "Learn how to use the Go SDK to stream and decode real-time cryptocurrency market data via WebSocket connections from Chainlink Data Streams."
+ keywords: ["WebSocket", "Go SDK", "Golang", "Real-time", "Streaming", "Crypto Data", "V3 Reports", "Data Streams"]
whatsnext:
{
- "Learn how to verify your data onchain": "/data-streams/reference/streams-direct/streams-direct-onchain-verification",
+ "Learn how to verify your data onchain": "/data-streams/reference/onchain-verification",
"Find the list of available Stream IDs": "/data-streams/crypto-streams",
}
---
@@ -18,28 +22,28 @@ import DataStreams from "@features/data-streams/common/DataStreams.astro"
pages={[
{
name: "Go SDK - V3 reports for Crypto streams",
- url: "/data-streams/tutorials/streams-direct/streams-direct-ws-go",
+ url: "/data-streams/tutorials/ws-go",
icon: "/images/tutorial-icons/go_logo_black.png",
},
{
name: "Go SDK - V4 reports for RWA streams",
- url: "/data-streams/tutorials/streams-direct/streams-direct-ws-rwa-go",
+ url: "/data-streams/tutorials/ws-rwa-go",
icon: "/images/tutorial-icons/go_logo_black.png",
},
{
name: "Rust SDK - V3 reports for Crypto streams",
- url: "/data-streams/tutorials/streams-direct/streams-direct-ws-rust",
+ url: "/data-streams/tutorials/ws-rust",
icon: "/images/tutorial-icons/rust_logo_blk.svg",
},
{
name: "Rust SDK - V4 reports for RWA streams",
- url: "/data-streams/tutorials/streams-direct/streams-direct-ws-rwa-rust",
+ url: "/data-streams/tutorials/ws-rwa-rust",
icon: "/images/tutorial-icons/rust_logo_blk.svg",
},
]}
/>
-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.
+In this tutorial, you'll learn how to use the [Data Streams SDK](/data-streams/reference/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/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.
@@ -47,9 +51,9 @@ In this guide, you'll learn how to use Chainlink Data Streams with the _[Streams
- **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 access.
+- **API Credentials**: Access to Data Streams 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 access.
-## Guide
+## Tutorial
### Set up your Go project
@@ -215,9 +219,9 @@ In this guide, you'll learn how to use Chainlink Data Streams with the _[Streams
Replace `` and `` with your API credentials.
- - `WsURL` is the [WebSocket URL](/data-streams/reference/streams-direct/streams-direct-interface-ws#domains) for the Data Streams Aggregation Network. Use for the testnet environment.
+ - `WsURL` is the [WebSocket URL](/data-streams/reference/interface-ws#domains) for the Data Streams Aggregation Network. Use for the testnet environment.
- See the [SDK Reference](/data-streams/reference/streams-direct/streams-direct-go-sdk#config-struct) page for more configuration options.
+ See the [SDK Reference](/data-streams/reference/go-sdk#config-struct) page for more configuration options.
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.
@@ -311,15 +315,15 @@ 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
+In this tutorial, 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.
+[Verify report data onchain](/data-streams/tutorials/evm-onchain-report-verification) tutorial.
## Explanation
### Establishing a WebSocket connection and listening for reports
-Your application uses the [Stream](https://github.com/smartcontractkit/data-streams-sdk/blob/main/go/client.go#L98) function in the [Data Streams SDK](/data-streams/reference/streams-direct/streams-direct-go-sdk)'s client package to establish a real-time WebSocket connection with the Data Streams Aggregation Network.
+Your application uses the [Stream](https://github.com/smartcontractkit/data-streams-sdk/blob/main/go/client.go#L98) function in the [Data Streams SDK](/data-streams/reference/go-sdk)'s client package to establish a real-time WebSocket connection with the Data Streams Aggregation Network.
Once the WebSocket connection is established, your application subscribes to one or more streams by passing an array of `feed.IDs` to the `Stream` function. This subscription lets the client receive real-time updates whenever new report data is available for the specified streams.
diff --git a/src/content/data-streams/tutorials/streams-direct/streams-direct-ws-rust.mdx b/src/content/data-streams/tutorials/ws-rust.mdx
similarity index 93%
rename from src/content/data-streams/tutorials/streams-direct/streams-direct-ws-rust.mdx
rename to src/content/data-streams/tutorials/ws-rust.mdx
index dd7220572cd..04bc579ebda 100644
--- a/src/content/data-streams/tutorials/streams-direct/streams-direct-ws-rust.mdx
+++ b/src/content/data-streams/tutorials/ws-rust.mdx
@@ -2,9 +2,13 @@
section: dataStreams
date: Last Modified
title: "Stream and decode V3 reports via WebSocket using the Rust SDK"
+metadata:
+ title: "WebSocket Integration with Rust SDK | Chainlink Data Streams"
+ description: "Learn how to stream and decode Chainlink Data Streams V3 reports using WebSocket connections with the Rust SDK."
+ keywords: ["WebSocket", "Rust SDK", "Data Streams", "Real-time data", "Crypto pricing", "Tutorial"]
whatsnext:
{
- "Learn how to verify your data onchain": "/data-streams/reference/streams-direct/streams-direct-onchain-verification",
+ "Learn how to verify your data onchain": "/data-streams/reference/onchain-verification",
"Find the list of available Stream IDs": "/data-streams/crypto-streams",
}
---
@@ -18,37 +22,37 @@ import DataStreams from "@features/data-streams/common/DataStreams.astro"
pages={[
{
name: "Go SDK - V3 reports for Crypto streams",
- url: "/data-streams/tutorials/streams-direct/streams-direct-ws-go",
+ url: "/data-streams/tutorials/ws-go",
icon: "/images/tutorial-icons/go_logo_black.png",
},
{
name: "Go SDK - V4 reports for RWA streams",
- url: "/data-streams/tutorials/streams-direct/streams-direct-ws-rwa-go",
+ url: "/data-streams/tutorials/ws-rwa-go",
icon: "/images/tutorial-icons/go_logo_black.png",
},
{
name: "Rust SDK - V3 reports for Crypto streams",
- url: "/data-streams/tutorials/streams-direct/streams-direct-ws-rust",
+ url: "/data-streams/tutorials/ws-rust",
icon: "/images/tutorial-icons/rust_logo_blk.svg",
},
{
name: "Rust SDK - V4 reports for RWA streams",
- url: "/data-streams/tutorials/streams-direct/streams-direct-ws-rwa-rust",
+ url: "/data-streams/tutorials/ws-rwa-rust",
icon: "/images/tutorial-icons/rust_logo_blk.svg",
},
]}
/>
-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.
+In this tutorial, you'll learn how to use the [Data Streams SDK](/data-streams/reference/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/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
- **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 access.
+- **API Credentials**: Access to Data Streams 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 access.
-## Guide
+## Tutorial
### Set up your Rust project
@@ -324,9 +328,9 @@ The decoded report details include:
#### Payload for onchain verification
-In this guide, you log and decode the `full_report` payload to extract the report data. In a
+In this tutorial, 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.
+[Verify report data onchain](/data-streams/tutorials/evm-onchain-report-verification) tutorial.
## Explanation
diff --git a/src/content/data-streams/tutorials/streams-direct/streams-direct-ws-rwa-go.mdx b/src/content/data-streams/tutorials/ws-rwa-go.mdx
similarity index 89%
rename from src/content/data-streams/tutorials/streams-direct/streams-direct-ws-rwa-go.mdx
rename to src/content/data-streams/tutorials/ws-rwa-go.mdx
index 47fc83e993d..286bd99d358 100644
--- a/src/content/data-streams/tutorials/streams-direct/streams-direct-ws-rwa-go.mdx
+++ b/src/content/data-streams/tutorials/ws-rwa-go.mdx
@@ -2,10 +2,14 @@
section: dataStreams
date: Last Modified
title: "Stream and decode V4 reports via WebSocket using the Go SDK"
+metadata:
+ title: "RWA V4 Reports via WebSocket with Go SDK | Chainlink Data Streams"
+ description: "Tutorial on streaming and decoding Real World Assets (RWA) V4 reports using WebSocket connections with the Go SDK for Chainlink Data Streams."
+ keywords: ["WebSocket", "Go SDK", "Real World Assets", "RWA", "V4 reports", "Data Streams", "Real-time data"]
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",
+ "Learn how to verify your data onchain": "/data-streams/reference/onchain-verification",
+ "Find the list of available Stream IDs": "/data-streams/rwa-streams",
}
---
@@ -18,28 +22,28 @@ import DataStreams from "@features/data-streams/common/DataStreams.astro"
pages={[
{
name: "Go SDK - V3 reports for Crypto streams",
- url: "/data-streams/tutorials/streams-direct/streams-direct-ws-go",
+ url: "/data-streams/tutorials/ws-go",
icon: "/images/tutorial-icons/go_logo_black.png",
},
{
name: "Go SDK - V4 reports for RWA streams",
- url: "/data-streams/tutorials/streams-direct/streams-direct-ws-rwa-go",
+ url: "/data-streams/tutorials/ws-rwa-go",
icon: "/images/tutorial-icons/go_logo_black.png",
},
{
name: "Rust SDK - V3 reports for Crypto streams",
- url: "/data-streams/tutorials/streams-direct/streams-direct-ws-rust",
+ url: "/data-streams/tutorials/ws-rust",
icon: "/images/tutorial-icons/rust_logo_blk.svg",
},
{
name: "Rust SDK - V4 reports for RWA streams",
- url: "/data-streams/tutorials/streams-direct/streams-direct-ws-rwa-rust",
+ url: "/data-streams/tutorials/ws-rwa-rust",
icon: "/images/tutorial-icons/rust_logo_blk.svg",
},
]}
/>
-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.
+In this tutorial, you'll learn how to use the [Data Streams SDK](/data-streams/reference/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/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.
@@ -47,9 +51,9 @@ In this guide, you'll learn how to use Chainlink Data Streams with the _[Streams
- **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 access.
+- **API Credentials**: Access to Data Streams 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 access.
-## Guide
+## Tutorial
### Set up your Go project
@@ -213,9 +217,9 @@ In this guide, you'll learn how to use Chainlink Data Streams with the _[Streams
Replace `` and `` with your API credentials.
- - `WsURL` is the [WebSocket URL](/data-streams/reference/streams-direct/streams-direct-interface-ws#domains) for the Data Streams Aggregation Network. Use for the testnet environment.
+ - `WsURL` is the [WebSocket URL](/data-streams/reference/interface-ws#domains) for the Data Streams Aggregation Network. Use for the testnet environment.
- See the [SDK Reference](/data-streams/reference/streams-direct/streams-direct-go-sdk#config-struct) page for more configuration options.
+ See the [SDK Reference](/data-streams/reference/go-sdk#config-struct) page for more configuration options.
1. For this example, you'll subscribe to the AUD/USD RWA streams. This stream ID is . See the [RWA Streams](/data-streams/rwa-streams) page for a complete list of available Real World Assets.
@@ -305,15 +309,15 @@ 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
+In this tutorial, 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.
+[Verify report data onchain](/data-streams/tutorials/evm-onchain-report-verification) tutorial.
## Explanation
### Establishing a WebSocket connection and listening for reports
-Your application uses the [Stream](https://github.com/smartcontractkit/data-streams-sdk/blob/main/go/client.go#L98) function in the [Data Streams SDK](/data-streams/reference/streams-direct/streams-direct-go-sdk)'s client package to establish a real-time WebSocket connection with the Data Streams Aggregation Network.
+Your application uses the [Stream](https://github.com/smartcontractkit/data-streams-sdk/blob/main/go/client.go#L98) function in the [Data Streams SDK](/data-streams/reference/go-sdk)'s client package to establish a real-time WebSocket connection with the Data Streams Aggregation Network.
Once the WebSocket connection is established, your application subscribes to one or more streams by passing an array of `feed.IDs` to the `Stream` function. This subscription lets the client receive real-time updates whenever new report data is available for the specified streams.
diff --git a/src/content/data-streams/tutorials/streams-direct/streams-direct-ws-rwa-rust.mdx b/src/content/data-streams/tutorials/ws-rwa-rust.mdx
similarity index 92%
rename from src/content/data-streams/tutorials/streams-direct/streams-direct-ws-rwa-rust.mdx
rename to src/content/data-streams/tutorials/ws-rwa-rust.mdx
index 8e9933f81c1..0c4ab92a5c6 100644
--- a/src/content/data-streams/tutorials/streams-direct/streams-direct-ws-rwa-rust.mdx
+++ b/src/content/data-streams/tutorials/ws-rwa-rust.mdx
@@ -2,9 +2,13 @@
section: dataStreams
date: Last Modified
title: "Stream and decode V4 reports via WebSocket using the Rust SDK"
+metadata:
+ title: "RWA V4 Reports via WebSocket with Rust SDK | Chainlink Data Streams"
+ description: "Step-by-step tutorial on streaming and decoding Real World Assets (RWA) V4 reports using WebSocket connections with the Rust SDK."
+ keywords: ["WebSocket", "Rust SDK", "Real World Assets", "RWA", "V4 reports", "Data Streams"]
whatsnext:
{
- "Learn how to verify your data onchain": "/data-streams/reference/streams-direct/streams-direct-onchain-verification",
+ "Learn how to verify your data onchain": "/data-streams/reference/onchain-verification",
"Find the list of available Stream IDs": "/data-streams/rwa-streams",
}
---
@@ -18,37 +22,37 @@ import DataStreams from "@features/data-streams/common/DataStreams.astro"
pages={[
{
name: "Go SDK - V3 reports for Crypto streams",
- url: "/data-streams/tutorials/streams-direct/streams-direct-ws-go",
+ url: "/data-streams/tutorials/ws-go",
icon: "/images/tutorial-icons/go_logo_black.png",
},
{
name: "Go SDK - V4 reports for RWA streams",
- url: "/data-streams/tutorials/streams-direct/streams-direct-ws-rwa-go",
+ url: "/data-streams/tutorials/ws-rwa-go",
icon: "/images/tutorial-icons/go_logo_black.png",
},
{
name: "Rust SDK - V3 reports for Crypto streams",
- url: "/data-streams/tutorials/streams-direct/streams-direct-ws-rust",
+ url: "/data-streams/tutorials/ws-rust",
icon: "/images/tutorial-icons/rust_logo_blk.svg",
},
{
name: "Rust SDK - V4 reports for RWA streams",
- url: "/data-streams/tutorials/streams-direct/streams-direct-ws-rwa-rust",
+ url: "/data-streams/tutorials/ws-rwa-rust",
icon: "/images/tutorial-icons/rust_logo_blk.svg",
},
]}
/>
-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.
+In this tutorial, you'll learn how to use the [Data Streams SDK](/data-streams/reference/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/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
- **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 access.
+- **API Credentials**: Access to Data Streams 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 access.
-## Guide
+## Tutorial
### Set up your Rust project
@@ -303,9 +307,9 @@ The decoded report details include:
#### Payload for onchain verification
-In this guide, you log and decode the `full_report` payload to extract the report data. In a
+In this tutorial, 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.
+[Verify report data onchain](/data-streams/tutorials/evm-onchain-report-verification) tutorial.
## Explanation
diff --git a/src/features/data-streams/common/asideOnChainVerification.mdx b/src/features/data-streams/common/asideOnChainVerification.mdx
index 3dd99ba8d4b..9c3bb209e7d 100644
--- a/src/features/data-streams/common/asideOnChainVerification.mdx
+++ b/src/features/data-streams/common/asideOnChainVerification.mdx
@@ -3,6 +3,5 @@ import { Aside } from "@components"
diff --git a/src/features/data-streams/common/gettingStarted.mdx b/src/features/data-streams/common/gettingStarted.mdx
index 52898ca2f1a..f61eba170f8 100644
--- a/src/features/data-streams/common/gettingStarted.mdx
+++ b/src/features/data-streams/common/gettingStarted.mdx
@@ -5,7 +5,7 @@ This guide shows you how to read data from a Data Streams stream, verify the ans
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) 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 Data Streams with the REST API or WebSocket, see the [Fetch and decode reports via a REST API](/data-streams/tutorials/api-go) guide or the [Stream and decode reports via WebSocket](/data-streams/tutorials/ws-go) guide.
diff --git a/src/features/data-streams/common/gettingStartedHardhat.mdx b/src/features/data-streams/common/gettingStartedHardhat.mdx
index 1d2e4722bac..7747924bd85 100644
--- a/src/features/data-streams/common/gettingStartedHardhat.mdx
+++ b/src/features/data-streams/common/gettingStartedHardhat.mdx
@@ -5,7 +5,7 @@ This guide shows you how to read data from a Data Streams stream, verify the ans
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) 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 Data Streams with the REST API or WebSocket, see the [Fetch and decode reports via a REST API](/data-streams/tutorials/api-go) guide or the [Stream and decode reports via WebSocket](/data-streams/tutorials/ws-go) guide.
diff --git a/src/features/redirects/redirects.json b/src/features/redirects/redirects.json
index b1de1a528fa..4e965c698d9 100644
--- a/src/features/redirects/redirects.json
+++ b/src/features/redirects/redirects.json
@@ -2339,6 +2339,121 @@
"source": "chainlink-nodes/node-versions",
"destination": "https://dev.chain.link/changelog?product=Nodes",
"statusCode": 301
+ },
+ {
+ "source": "data-streams/getting-started",
+ "destination": "data-streams/tutorials/streams-trade/getting-started",
+ "statusCode": 301
+ },
+ {
+ "source": "data-streams/getting-started-hardhat",
+ "destination": "data-streams/tutorials/streams-trade/getting-started-hardhat",
+ "statusCode": 301
+ },
+ {
+ "source": "data-streams/tutorials/streams-direct/evm-onchain-report-verification",
+ "destination": "data-streams/tutorials/evm-onchain-report-verification",
+ "statusCode": 301
+ },
+ {
+ "source": "data-streams/tutorials/streams-direct",
+ "destination": "data-streams/tutorials",
+ "statusCode": 301
+ },
+ {
+ "source": "data-streams/tutorials/streams-direct/solana-offchain-report-verification",
+ "destination": "data-streams/tutorials/solana-offchain-report-verification",
+ "statusCode": 301
+ },
+ {
+ "source": "data-streams/tutorials/streams-direct/solana-onchain-report-verification",
+ "destination": "data-streams/tutorials/solana-onchain-report-verification",
+ "statusCode": 301
+ },
+ {
+ "source": "data-streams/tutorials/streams-direct/streams-direct-api-go",
+ "destination": "data-streams/tutorials/api-go",
+ "statusCode": 301
+ },
+ {
+ "source": "data-streams/tutorials/streams-direct/streams-direct-api-rust",
+ "destination": "data-streams/tutorials/api-rust",
+ "statusCode": 301
+ },
+ {
+ "source": "data-streams/tutorials/streams-direct/streams-direct-api-rwa-go",
+ "destination": "data-streams/tutorials/api-rwa-go",
+ "statusCode": 301
+ },
+ {
+ "source": "data-streams/tutorials/streams-direct/streams-direct-api-rwa-rust",
+ "destination": "data-streams/tutorials/api-rwa-rust",
+ "statusCode": 301
+ },
+ {
+ "source": "data-streams/tutorials/streams-direct/streams-direct-ws-go",
+ "destination": "data-streams/tutorials/ws-go",
+ "statusCode": 301
+ },
+ {
+ "source": "data-streams/tutorials/streams-direct/streams-direct-ws-rust",
+ "destination": "data-streams/tutorials/ws-rust",
+ "statusCode": 301
+ },
+ {
+ "source": "data-streams/tutorials/streams-direct/streams-direct-ws-rwa-go",
+ "destination": "data-streams/tutorials/ws-rwa-go",
+ "statusCode": 301
+ },
+ {
+ "source": "data-streams/tutorials/streams-direct/streams-direct-ws-rwa-rust",
+ "destination": "data-streams/tutorials/ws-rwa-rust",
+ "statusCode": 301
+ },
+ {
+ "source": "data-streams/reference/streams-trade-interface",
+ "destination": "data-streams/streams-trade/interfaces",
+ "statusCode": 301
+ },
+ {
+ "source": "data-streams/reference/streams-direct",
+ "destination": "data-streams/reference/overview",
+ "statusCode": 301
+ },
+ {
+ "source": "data-streams/reference/streams-direct/streams-direct-go-sdk",
+ "destination": "data-streams/reference/go-sdk",
+ "statusCode": 301
+ },
+ {
+ "source": "data-streams/reference/streams-direct/streams-direct-interface-api",
+ "destination": "data-streams/reference/interface-api",
+ "statusCode": 301
+ },
+ {
+ "source": "data-streams/reference/streams-direct/streams-direct-interface-ws",
+ "destination": "data-streams/reference/interface-ws",
+ "statusCode": 301
+ },
+ {
+ "source": "data-streams/reference/streams-direct/streams-direct-onchain-verification",
+ "destination": "data-streams/reference/onchain-verification",
+ "statusCode": 301
+ },
+ {
+ "source": "data-streams/reference/streams-direct/streams-direct-rust-sdk",
+ "destination": "data-streams/reference/rust-sdk",
+ "statusCode": 301
+ },
+ {
+ "source": "data-streams/streams-trade/architecture",
+ "destination": "data-streams/architecture",
+ "statusCode": 301
+ },
+ {
+ "source": "data-streams/tutorials",
+ "destination": "data-streams/tutorials/overview",
+ "statusCode": 301
}
]
}
diff --git a/src/scripts/click-to-zoom.ts b/src/scripts/click-to-zoom.ts
index f1c20b320cb..87ebd85fc35 100644
--- a/src/scripts/click-to-zoom.ts
+++ b/src/scripts/click-to-zoom.ts
@@ -3,6 +3,12 @@ document.addEventListener("DOMContentLoaded", () => {
element.addEventListener("click", () => {
if (element.classList.contains("expanded")) return
+ // Check if an expanded view already exists (shouldn't happen often, but safety first)
+ const existingWrapper = document.getElementById("expanded-image-wrapper")
+ if (existingWrapper) {
+ existingWrapper.remove()
+ }
+
element.classList.add("expanded")
// create wrapper for preview
const wrapper = document.createElement("div")
@@ -11,24 +17,43 @@ document.addEventListener("DOMContentLoaded", () => {
// create image node
const img = document.createElement("img")
img.src = element.src
+ img.alt = element.alt
img.className = "expanded"
img.id = "expanded-image-preview"
wrapper.appendChild(img)
+ const captionText = element.dataset.caption
+ let captionElement: HTMLParagraphElement | null = null
+ if (captionText) {
+ captionElement = document.createElement("p")
+ captionElement.className = "expanded-image-caption"
+ captionElement.textContent = captionText
+ wrapper.appendChild(captionElement)
+ }
+
// setup events to close the preview
- wrapper.onclick = () => {
+ const closePreview = () => {
+ // Remove caption first if it exists
+ if (captionElement && wrapper.contains(captionElement)) {
+ wrapper.removeChild(captionElement)
+ }
wrapper.remove()
element.classList.remove("expanded")
+ document.removeEventListener("keyup", handleKeyUp) // Clean up key listener
}
- document.onkeyup = (e) => {
+
+ const handleKeyUp = (e: KeyboardEvent) => {
if (e.key === "Escape") {
- wrapper.remove()
- element.classList.remove("expanded")
+ closePreview()
}
}
+ wrapper.onclick = closePreview
+ document.addEventListener("keyup", handleKeyUp) // Add key listener
+
// add the wrapper to the DOM
- element.insertAdjacentElement("afterend", wrapper)
+ document.body.appendChild(wrapper)
+ wrapper.style.display = "flex"
})
})
})