Use code JSON50 for 50% off your first month of any plan Code JSON50 - 50% off your first month
Skip to content

Rewind (Historical Streaming)

Coming soon - design preview: Rewind is not live yet. The connection parameters and code examples on this page are a design preview of the upcoming API - the mode=rewind parameters are not yet accepted by the Warp endpoints and may change before launch. Want early access or to shape the design? Contact us or ping us on Discord.

Overview

Rewind is Warp, pointed at the past. Every Warp stream type - Events, Addresses, Coins, Objects - can start from any historical checkpoint instead of the live tip. The same filters, the same payloads, the same delivery guarantees, over one connection:

  • Bounded replay (fromto): stream everything that matched your filters between two checkpoints, then the stream completes. Backtests, incident reprocessing, database rebuilds.
  • Catch-up to live (from → live): replay history from a checkpoint, and when Rewind reaches the chain tip the connection hands off to live Warp seamlessly - no gap, no duplicates, no reconnect. Your consumer restarts where it died and just keeps going.

Checkpoints are Sui's universal cursor: a globally agreed, gap-free sequence over everything that ever happened on chain. Rewind leans on that directly - positions are plain checkpoint coordinates, not opaque tokens, so you can construct one from a checkpoint number you got anywhere (your database, our explorer, an incident timeline).

How It Works

┌────────────────┐
│  Sui Archive   │───┐
│ (full history) │   │   ┌───────────────────────┐    WebSocket or SSE    ┌───────────┐
└────────────────┘   ├──►│     Inodra Rewind     │───────Connection──────►│ Your App  │
┌────────────────┐   │   │ scan → filter → order │  (history, then live)  │           │
│ Sui Live Node  │───┘   └───────────────────────┘                        └───────────┘
└────────────────┘
  1. You connect to an existing Warp stream with a from_checkpoint (and optionally to_checkpoint)
  2. Inodra scans history from that checkpoint, applies your stream's filters server-side, and delivers matches in ledger order
  3. Bounded replays finish with a rewind_complete event; open-ended replays emit caught_up and continue as a normal live Warp stream on the same connection

Quick Start

Rewind uses your existing Warp streams - create one in the dashboard first (see Warp Quick Start), then connect with rewind parameters.

Catch up from a checkpoint, then go live (WebSocket, recommended):

javascript
const streamId = 'your-stream-id'
const apiKey = 'your-api-key'

const ws = new WebSocket(
  `wss://mainnet-api.inodra.com/v1/warp/${streamId}/ws?api_key=${apiKey}` +
    `&mode=rewind&from_checkpoint=187432001`
)

ws.onmessage = (event) => {
  const msg = JSON.parse(event.data)

  if (msg.event === 'caught_up') {
    console.log('Replay done - now streaming live from checkpoint', msg.data.checkpoint)
  } else if (msg.event === 'rewind_progress') {
    console.log('Scanned through checkpoint', msg.data.checkpoint)
  } else {
    console.log(msg.event, msg.data) // your stream type: 'event', 'address', 'coin', 'object'
  }

  // ACKs work exactly like live Warp - exactly-once delivery, and Rewind paces to your ACKs
  if (msg.id) {
    ws.send(JSON.stringify({ type: 'ack', id: msg.id }))
  }
}

Bounded replay of a fixed range (SSE):

javascript
const streamId = 'your-stream-id'
const apiKey = 'your-api-key'

const res = await fetch(
  `https://mainnet-api.inodra.com/v1/warp/${streamId}/stream` +
    `?mode=rewind&from_checkpoint=187000000&to_checkpoint=187500000`,
  { headers: { 'x-api-key': apiKey } }
)

let buffer = ''
for await (const chunk of res.body) {
  buffer += new TextDecoder().decode(chunk)
  const parts = buffer.split('\n\n')
  buffer = parts.pop()
  for (const part of parts) {
    const eventLine = part.split('\n').find((l) => l.startsWith('event:'))
    const dataLine = part.split('\n').find((l) => l.startsWith('data:'))
    if (!dataLine) continue
    const type = eventLine?.slice(6).trim()
    const data = JSON.parse(dataLine.slice(5))
    if (type === 'rewind_complete') {
      console.log('Range fully replayed:', data)
    } else {
      console.log(type, data)
    }
  }
}
// The server closes the connection after rewind_complete

Connection Parameters

Rewind adds three parameters to the existing Warp connect endpoints (/v1/warp/{streamId}/ws and /v1/warp/{streamId}/stream):

ParameterRequiredDescription
mode=rewindYesSelects rewind. Mutually exclusive with mode=resume (see Connect modes).
from_checkpointYesCheckpoint sequence number to start from (inclusive). Any checkpoint back to genesis.
to_checkpointNoCheckpoint to stop at (inclusive). Omit to hand off to live streaming when caught up.

Instead of from_checkpoint, you can pass a full position cursor as from - or, on SSE, in the standard Last-Event-ID header. Positions are legible ledger coordinates:

<checkpoint>:<transactionIndex>:<eventIndex>     e.g.  187432001:14:2

Every replayed message carries its position as the message id (WebSocket) / SSE id: field, so native EventSource reconnection resumes a dropped rewind automatically, exactly where it stopped - the browser sends Last-Event-ID for you. WebSocket clients pass the last processed id as from on reconnect.

Stream Event Types

Rewind connections emit the standard Warp lifecycle events (connected, quota_exceeded, error) plus your stream type's data events, and three rewind-specific events:

EventWhenPayload
rewind_progressPeriodically while scanning sparse ranges{ "checkpoint": 187210000 } - fully covered through here
caught_upRewind reached the live tip (no to_checkpoint){ "checkpoint": 187994210 } - live from the next checkpoint
rewind_completeBounded rewind reached to_checkpoint{ "from": ..., "to": ..., "matched": 45210 }

rewind_progress is a watermark: it tells you every match at or below that checkpoint has been delivered, even when your filter hasn't matched anything for a while. Persist it alongside your data - it's a valid resume position and it keeps "quiet" replays observably alive.

Ordering & Delivery Guarantees

  • Ledger order, gap-free: matches arrive strictly ordered by (checkpoint, transactionIndex, eventIndex). The history→live handoff happens on a checkpoint boundary - nothing is skipped or delivered twice across the seam.
  • WebSocket: exactly-once, exactly like live Warp - messages are marked delivered only after your ACK, and an unACKed replay resumes from the last acknowledged position.
  • SSE: at-least-once. Reconnect with Last-Event-ID (automatic with EventSource) and delivery continues from that position; you may see the last in-flight message again.
  • Backpressure: replaying history produces data far faster than the chain does. The server paces delivery to your consumption (ACK window on WebSocket, socket backpressure on SSE) - a slow consumer slows the rewind down; it never overruns you or buffers unboundedly. If a connection drops mid-rewind, nothing is lost: reconnect with your last position.

History Depth & Performance

Rewind reads from Inodra's full-history archive - the same storage that serves archival gRPC and GraphQL back to genesis.

Two things affect replay throughput:

  • Filter density: for indexed filter dimensions (event types, emitting modules, senders, addresses, objects), Rewind skips directly to matching checkpoints - a sparse filter over a huge range is fast because most of the range is never touched.
  • Range temperature: recent history is served hot; deep-history segments are fetched from cold archival storage on demand. Deep sparse replays interleave rewind_progress watermarks while the scan works, so your client always sees forward motion.

Preview limits: maximum rewind range per connection, per-plan history depth, and concurrent rewind connections are being finalized during the preview. Current preview builds allow one active connection per stream (same as live Warp).

Billing

Preview pricing - subject to change.

Replayed messages are billed like live Warp delivery (per event + connection time - see Credits & Billing). Historical scanning adds a per-range scan component for deep or unindexed ranges; indexed, filtered replays only pay for what's delivered. Exact rates will be published when Rewind reaches general availability.

Common Use Cases

Recovery & Reindexing

Your consumer, indexer, or database died at checkpoint N. Connect with from_checkpoint=N and no to_checkpoint: Rewind backfills everything you missed and hands off to live on the same connection. No dual code paths, no gap math, no "poll then switch" logic.

Backtesting

Replay every Swap a DEX emitted across a historical window - with the same field filtering your live strategy uses - into your backtest at full speed. to_checkpoint bounds the run, and rewind_complete tells you the dataset is complete (and how many events matched).

Incident Reprocessing

Something went wrong between two checkpoints. Replay exactly that window through the exact filters your production stream uses and re-run your pipeline against what actually happened, in the order it happened.

Populating a New System

Launching a feature that needs history? Point a bounded rewind at genesis-to-now with your filters, bulk-load the results, then flip the same stream to live mode. One filter definition, one delivery format, both directions of time.

Rewind vs. Raw Checkpoint Streaming

Rewind delivers filtered, decoded, application-level data with Warp's delivery guarantees. If you need the raw firehose instead - every full checkpoint over a historical range, BCS or structured - the same engine powers checkpoint-range streaming on the gRPC gateway's SubscribeCheckpoints. That mode is available for enterprise plans today; contact us for access.

FeatureRewind (Warp)Checkpoint-range streaming (gRPC)
PayloadMatched events/addresses/coins/objects, JSONFull checkpoints (proto, mask-gated)
FilteringFull Warp filters incl. field filteringField masks only (all transactions)
DeliveryExactly-once (WS ACKs) / at-least-once (SSE)gRPC stream, client tracks cursor
Best forApp-level consumers, pipelines, backtestsIndexers, mirrors, checkpoint tooling

Next Steps

Released under the MIT License.