Hold your own cursor
A long-running pull from any point in chain history, one event per line. You decide where to resume, and reorgs are a list you can read.
Resume, don't restart
The cursor is height:index. Write it down, and a killed consumer picks up where it stopped.
jsonl, so pipe it anywhere
One event per line on stdout. jq, a file, a queue, Postgres. Your sink, no config to learn.
Reorgs are a list you can read
A fork rewinds to the fork point and re-delivers. streams reorgs pages the history, so you can reconcile.
One command, until you stop it
streams consume pulls from a cursor and prints jsonl until you stop it. Filters run before the wire, so a consumer for one asset pays for one asset.
{"block_height":8948506,"event_index":12,"type":"ft_transfer"}
{"block_height":8948506,"event_index":19,"type":"ft_transfer"}
{"block_height":8948506,"event_index":24,"type":"ft_transfer"}
{"block_height":8948507,"event_index":3,"type":"ft_transfer"}
{"block_height":8948507,"event_index":8,"type":"ft_transfer"}Two numbers, total ordering
Block height plus event index orders every event on the chain exactly once. That pair is the whole checkpoint. No consumer group, no offset topic, no broker to run.
- 506:19read
- 506:24read
- 507:03cursor
- 507:08next
- …tip
Every frame is signed
The SSE stream carries each event with an ed25519 signature. The SDK checks every frame against our published key by default, so a tampered event fails before your code sees it.
Backfill from signed dumps, then tail live
events.replay reads the finalized parquet dumps, then switches to the live stream at the manifest's last finalized cursor. No gap and no duplicate at the seam.
3every window the dumps hold
4every dump is sha256-verified
8the seam: live from here
Nothing runs on our side between pulls. A consumer you are not running costs nothing.
Rows delivered, dropping to $2 per 1M past $50 of monthly spend. The first 1M each month are free. Filters cut the bill along with the output.
Runes on the same loop
chain=bitcoin serves Runes events on their own cursor space, from block 840,000, checked against ord with 0 mismatches.
rolling outThey read the same index. The difference is who holds the state.
Run it yourself
Hosted is api.secondlayer.tools. Point SECONDLAYER_API_URL at your own instance and the same CLI, SDK and /v1/streams routes answer. Reads over loopback need no key, so a local consumer pays nothing per row.
Streams questions
What exactly is the cursor?
block_height:event_index, a total order over chain events. Store it wherever you store anything, and pass --cursor to resume.What happens on a reorg?
finalized_height is provisional until six Bitcoin confirmations.Can I read everything one transaction emitted?
streams by-tx <txId> returns every event it emitted. block-events does the same for a height or hash, and canonical <height> returns block metadata.Is this push or pull?
Do filters reduce the bill?
--types and --contract-id cut the bill and the output together.