x402-compatible — accountless pay-per-call

Every raw event.
No node required.

The immutable, replayable log of everything the chain emits — ordered, cursor-paginated, reorg-aware. Tail the tip over SSE, page over REST, or pull signed bulk dumps — the raw feed you'd run a node for.

firehose.ts
import { createStreamsClient } from "@secondlayer/sdk";

const streams = createStreamsClient({ apiKey: process.env.SL_API_KEY });

// Every event the chain emits, in order — resume from any
// cursor, reorg-aware, no node to run.
await streams.events.consume({
  fromCursor: lastCheckpoint,
  types: ["print"],
  contractId: "SP2QEZ…BNS-V2",
  batchSize: 500,
  onBatch: async (events, _envelope, { cursor }) => {
    for (const e of events) await handle(e);
    await saveCheckpoint(cursor);
  },
  onReorg: async (reorg, { cursor }) => {
    await rollbackFrom(reorg.fork_point_height); // inclusive of the fork block
    await saveCheckpoint(cursor);
  },
});
curl — streams
$ curl …/v1/streams/events?from_cursor=8249712:0
{ "events": [ …500 ],
  "next_cursor": "8249713:6",
  "tip": { "block_height": 8249743 } }
$

One firehose, three ways in.
Stream it, pull it, or pay per call.

Tail the tip over SSE, backfill cold history from signed dumps, or let an agent pay per call with x402, no account required.

Read the Streams docs

Live (SSE)

Tail the tip over a single connection — events arrive as they land.

live · cursor 8,249,714:0
#8,249,712 · 11 events · +2.4s
#8,249,713 · 6 events · +4.9s
#8,249,714 · 12 events · +7.3s

Bulk

Backfill cold history from signed dumps, then tail live with no gap.

signed bulk dumps
0008240000-0008249999.parquet
   102 MB · 1.33M rows
0008230000-0008239999.parquet
   98 MB · 1.29M rows

x402

No account, no key — an agent pays per call over HTTP 402.

GET /v1/streams/events
402 Payment Required
→ x402 · pay 0.001 STX
200 { events: [ … ] }

Point your cursor at genesis.
Press play.

Every event the chain emits, ordered and replayable — over SSE, REST, or signed dumps.