From b41bae659e57a573b6f22c7f8d12f3523ba55722 Mon Sep 17 00:00:00 2001 From: Josh Neuroth Date: Wed, 26 Aug 2026 06:34:42 -0400 Subject: [PATCH] docs(data-streams): add How Report Timestamps Work page Adds a concepts page explaining that reports describe a span of time (validFromTimestamp through observationsTimestamp) rather than an instant, how gaps between reports are absorbed, and how timestamps anchor TWAP stream calculations. Cross-links it from Architecture, Best Practices, and the REST API reference. Co-Authored-By: Claude Opus 5 --- src/config/sidebar.ts | 4 + src/content/data-streams/architecture.mdx | 1 + .../data-streams/concepts/best-practices.mdx | 5 ++ .../how-report-timestamps-work.mdx | 88 +++++++++++++++++++ .../data-streams-api/interface-api.mdx | 2 + 5 files changed, 100 insertions(+) create mode 100644 src/content/data-streams/how-report-timestamps-work.mdx diff --git a/src/config/sidebar.ts b/src/config/sidebar.ts index 7000d697f3f..a9b24b7f3e4 100644 --- a/src/config/sidebar.ts +++ b/src/config/sidebar.ts @@ -1340,6 +1340,10 @@ export const SIDEBAR: Partial> = { title: "Architecture", url: "data-streams/architecture", }, + { + title: "How Report Timestamps Work", + url: "data-streams/how-report-timestamps-work", + }, { title: "Best Practices", url: "data-streams/concepts/best-practices", diff --git a/src/content/data-streams/architecture.mdx b/src/content/data-streams/architecture.mdx index 94667261fd5..4d85cf2d29e 100644 --- a/src/content/data-streams/architecture.mdx +++ b/src/content/data-streams/architecture.mdx @@ -8,6 +8,7 @@ metadata: whatsnext: { "Learn more about the Standard API Implementation": "/data-streams/tutorials/go-sdk-fetch", + "Learn how report timestamps work": "/data-streams/how-report-timestamps-work", "Find the list of available Stream IDs": "/data-streams/crypto-streams", "Find the schema of data to expect from Data Streams reports: Crypto": "/data-streams/reference/report-schema-v3", "Find the schema of data to expect from Data Streams reports: RWA": "/data-streams/reference/report-schema-v8", diff --git a/src/content/data-streams/concepts/best-practices.mdx b/src/content/data-streams/concepts/best-practices.mdx index abf7033cada..880575825f0 100644 --- a/src/content/data-streams/concepts/best-practices.mdx +++ b/src/content/data-streams/concepts/best-practices.mdx @@ -27,6 +27,7 @@ whatsnext: "Learn about Data Streams market hours and schedules": "/data-streams/market-hours", "Learn how to handle market events": "/data-streams/rwa-streams/handling-market-events", "Learn how to handle stock splits": "/data-streams/tokenized-asset-streams/handling-stock-splits", + "Learn how report timestamps work": "/data-streams/how-report-timestamps-work", } --- @@ -51,3 +52,7 @@ For best practices regarding RWA streams: ## Tokenized Assets For best practices regarding stock splits and reverse splits for tokenized assets, please see the [Handling Stock Splits](/data-streams/tokenized-asset-streams/handling-stock-splits) guide. + +## Report Timestamps + +Each report applies to a span of time defined by `validFromTimestamp` and `observationsTimestamp`, and that span isn't always exactly one second wide. Read both fields from each report rather than assuming a fixed cadence or deriving the window from your own clock. See [How Report Timestamps Work](/data-streams/how-report-timestamps-work) for details, including how gaps between reports are absorbed and how timestamps apply to TWAP streams. diff --git a/src/content/data-streams/how-report-timestamps-work.mdx b/src/content/data-streams/how-report-timestamps-work.mdx new file mode 100644 index 00000000000..75c10488c38 --- /dev/null +++ b/src/content/data-streams/how-report-timestamps-work.mdx @@ -0,0 +1,88 @@ +--- +section: dataStreams +date: "Last Modified" +title: "How Report Timestamps Work" +metadata: + title: "How Chainlink Data Streams Report Timestamps Work | validFromTimestamp and observationsTimestamp" + description: "Learn how Chainlink Data Streams report timestamps define a span of time rather than an instant, how gaps between reports are absorbed, and how timestamps apply to TWAP streams." + keywords: + [ + "Data Streams", + "Timestamps", + "validFromTimestamp", + "observationsTimestamp", + "TWAP", + "Time Weighted Average Price", + "Reports", + ] +whatsnext: + { + "See the REST API reference": "/data-streams/reference/data-streams-api/interface-api", + "See the WebSocket reference": "/data-streams/reference/data-streams-api/interface-ws", + "Learn about Data Streams architecture": "/data-streams/architecture", + "Review Data Streams best practices": "/data-streams/concepts/best-practices", + } +--- + +import { Aside } from "@components" +import DataStreams from "@features/data-streams/common/DataStreams.astro" + + + +Every Data Streams report carries two timestamps: `validFromTimestamp` and `observationsTimestamp`. Together they describe a span of time rather than a single instant. This page explains how that span is constructed, what to expect when no report exists for a given second, and how timestamps apply to Time Weighted Average Price (TWAP) streams. + +## Reports are spans, not ticks + +A report doesn't represent a price at an instant. It represents a price over a span of time: + +> From `validFromTimestamp` through `observationsTimestamp`, the price is X. + +- **`validFromTimestamp`** — the floor of the span +- **`observationsTimestamp`** — the ceiling of the span + +Both fields are Unix timestamps in seconds. + +This span can be 1 second wide or several seconds wide, depending on how frequently the Decentralized Oracle Network (DON) can observe the data and generate reports. Spans are contiguous by construction: each one starts the second after the previous one ended. No gaps, no overlaps — every second in time belongs to exactly one report. + +## Understanding real-time transmission + +Say wall-clock time is `12:05:00`. What price is "current" at that instant depends on whether a report exists for it yet. + +**Normal case** + +A report exists with `observationsTimestamp = 12:05:00`. Its window is 1 second wide. You'll receive it slightly after `12:05:00` — typically up to 1-2 seconds later — due to DON consensus and transmission to you. + +**Edge case: no report at that exact second** + +Sometimes there's no report observed with `observationsTimestamp = 12:05:00`. For example: + +- Last report: `observationsTimestamp = 12:04:59` +- Next report: `observationsTimestamp = 12:05:01` + +The next report's window absorbs the gap: its `validFromTimestamp` is `12:05:00`, making its window 2 seconds wide (`12:05:00` → `12:05:01`). + +In this example, the price for `12:05:00` is observed one second later at `12:05:01`. + + + +## How timestamps relate to TWAP streams + +TWAP streams function differently than traditional data reports. A TWAP report is an **aggregated calculation** derived from the underlying reports. + +A TWAP span is anchored to `observationsTimestamp`, not to Unix time. It doesn't pad or extend to hit a round boundary — it slides. + +For example, a 60-second TWAP requested "at `12:05:01`" covers `12:04:01` → `12:05:01`, not `12:04:00` → `12:05:00` or anything else artificially aligned to the clock. + +**Formula:** + +``` +TWAP = (sum of price × duration for each report in the window) / window length in seconds +``` + +- 30-second TWAP → divide by 30 +- 60-second TWAP → divide by 60 + +If a report's window is wider than 1 second (that is, it spans a gap where no intermediate report existed), that report's price is interpolated across the seconds it covers rather than treated as a single point. diff --git a/src/content/data-streams/reference/data-streams-api/interface-api.mdx b/src/content/data-streams/reference/data-streams-api/interface-api.mdx index 815be286a75..66cff20d0b6 100644 --- a/src/content/data-streams/reference/data-streams-api/interface-api.mdx +++ b/src/content/data-streams/reference/data-streams-api/interface-api.mdx @@ -37,6 +37,8 @@ All routes require the following three headers for user authentication: ## API endpoints +Report responses include `validFromTimestamp` and `observationsTimestamp`, which together define the span of time the report's price applies to rather than a single instant. See [How Report Timestamps Work](/data-streams/how-report-timestamps-work) for details, including what happens when no report exists for a given second. + ### Return a single report at a given timestamp ##### Endpoint