Skip to content
Indexer Access

Streams

Live subscriptions to heads, blocks, transactions, logs, transfers, AMM events, creations and launches, with filters you can change without reconnecting.

Streams are the push side of the same data the read routes serve. Where a read route answers what is true at one block, a stream tells you as new records land.

Topics

TopicEmits
headsCanonical head movement
blocksNew canonical blocks
transactionsNew transactions
logsNew logs
transfersNew token transfers
amm-eventsNew swaps and liquidity events
creationsNew contract and token creations
launchesLaunch lifecycle transitions: new, graduating, graduated
candlesLive candle state per named token or pool series: a snapshot on connect, then updates and a final close per bucket

Topics are isolated, so a slow consumer on one topic does not hold up another.

Every topic has its own single-topic route under /stream/. All of them except heads can also be multiplexed through /stream/subscribe. The single-topic path is /stream/amm-events, but the multiplexed select and resume parameters spell the same topic amm_events.

One connection, several topics

GET /stream/subscribe multiplexes several topics over a single connection rather than making you hold one per topic.

Filters on an open subscription can be changed in place:

POST /stream/subscribe/{topic}/{id}/selectors

That mutates the filter set of a subscription that is already open, so narrowing or widening what you receive does not cost a reconnect and does not create a gap while you reconnect.

What a stream event is, and is not

Streams carry the same speculative-versus-canonical distinction as everything else, and it is the thing to get right when building on them.

A speculative event is an early observation. It has not been confirmed by execution, and the transaction behind it may revert. A confirmed event has been through receipt and root verification.

If you are driving something that must not act on an unconfirmed event, key on confirmed records. If you are driving a live view where being seconds early is worth being occasionally wrong, early observations are the reason streams exist. The overview explains how the two relate.

Recovering after a disconnect

Every durable event carries an id: of the form v1.<namespace>.<sequence>. Record it only after your application has durably processed the event, then use it to resume:

RouteResume with
Single-topic streamsafter_sequence=<sequence> (the number at the end of the ID), or the full ID in the Last-Event-ID header when after_sequence is absent
/stream/subscriberesume=<topic>:<full ID>, one entry per topic. Last-Event-ID alone is not honoured here

A browser EventSource resends the last full ID as Last-Event-ID on its own, so it resumes without extra code. An ID is bound to its topic and store, so send it back only to the route that emitted it. A Last-Event-ID the route cannot use (a bare number, an ID from another topic, or any header on /stream/subscribe) is not an error: the stream opens live and its first frame is event: resume_unsupported, saying the header was not honoured and which form to use instead.

Two topics do not replay history. The head stream is not durable, and a reconnect across an API restart reports a gap. The candle stream has no resume cursor at all: every connection opens with a fresh snapshot of each selected series, and naming candles in resume is a 400.

Catch-up is bounded. A consumer that reads too slowly, or whose catch-up stopped short of the present, receives an event: lag frame naming the last sequence delivered, instead of silently losing events. A resume point older than what the store still retains is handled by how you sent it:

  • An explicit after_sequence or resume below the retention floor is refused with a 400 naming the lowest sequence still retained.
  • A Last-Event-ID below the floor is served live, and the first frame is an event: lag with reason: resume_cursor_below_retention_floor, the requested sequence, and the retentionFloor. It is served rather than refused because a browser EventSource never retries after a 4xx.

In every case, read the gap from the indexed routes, then reopen the stream. Do not skip the gap.

A sequence gap is recorded as unhealthy until the corresponding canonical blocks and receipts have been reconciled.

View this page as Markdown