At a glance
| Capability | v1 | v2 |
|---|---|---|
| Real-time transaction stream | ||
Account include / exclude / required filters | ||
| Ping and version checks | ||
| Change filters live, without reconnecting | ||
| Named filters with accept / reject acknowledgements | ||
| Enriched transaction fields (fee payer, priority fee, compute units, program IDs, writable accounts, size) | ||
| Resolved address-lookup-table accounts | ||
| Slot lifecycle stream (alive / complete / dead) | ||
| Per-message sequence numbers for gap detection | ||
| Idle heartbeats |
Both v1 and v2 give you the decoded transaction: signatures, account keys, instructions, the
message header, and any address-lookup-table references. What v2 adds is enrichment on top of
that (the pre-computed fields above), plus the live-subscription, slot, and liveness features.
Enrichment is opt-in; see below.
More data, fewer RPC calls
With v1 you get the decoded transaction and work out the rest yourself. Anything past the core fields is on you: who paid the fee, what the priority fee was, which accounts are writable, and the real accounts behind a versioned transaction’s lookup tables. v2 can do that work for you. Turn on enrichment and each transaction also carries the fields below.| To get… | On v1 you… | On v2 (enrichment on) |
|---|---|---|
| The full account list of a versioned (v0) transaction | Make a full RPC call per transaction to fetch the lookup table, then resolve the indexes yourself | Already resolved and included (loaded_writable_addresses / loaded_readonly_addresses) |
| The fee payer | Derive it from the account keys and header | Included (fee_payer) |
| The priority fee and compute-unit limit | Parse the compute-budget instructions yourself | Included (priority_fee, compute_limit) |
| The writable accounts | Compute them from the header and resolved lookup tables | Included (writable_accounts) |
| The program IDs the transaction touches | Walk every instruction | Included (program_ids) |
| The transaction size | Reconstruct and measure the transaction | Included (tx_size) |
Enrichment is opt-in and off by default. Flip it on per subscription (
include_enrichment: true on a filter) whenever you want the extra fields. It is subscription-wide: if any active
filter turns it on, every transaction the session receives is enriched.Manage your stream without reconnecting
In v1 you set your filters once, in the message that opens the stream. To watch something different you drop the connection and open a new one, losing the warm stream while you reconnect. v2 keeps the stream open and lets you add and remove filters as you go. You give each filter your ownfilter_id, the server acknowledges every add and remove (and tells you why if it rejects one), and
every transaction lists the filter_id values it matched. Run several filters on one connection,
change them on the fly, and always know which filter produced a given transaction.
Follow the chain with slot events
v2 adds a second, separate stream,SubscribeSlots, that v1 has nothing like. You get an event when
a slot starts (ALIVE), finishes (COMPLETE), or is skipped or times out (DEAD), along with that
slot’s leader and parent. It is a cheap way to track where the chain is instead of inferring it from
the transaction flow.
Know when you have missed something
Two things v1 never gave you:- Every v2 message, transactions and slot events alike, carries a
sequencenumber that climbs by one. See a gap and you know you dropped a message. - When a stream goes quiet, v2 sends a
Heartbeatabout once a minute, stamped with the server’s clock. That keeps the connection alive through NAT and load-balancer idle timeouts, and tells a quiet stream apart from a dead one.
Why this adds up to a faster result
- A whole RPC call removed. Resolving a lookup table on v1 is a full RPC request and response, much slower than the stream itself. v2 does it for you, so that call never sits between a transaction arriving and you acting on it.
- Work done once, not per client. Enrichment is computed on our low-latency pipeline instead of in every client, every time.
- No reconnect gaps. Changing filters live means you never drop the stream to re-subscribe.
- Loss and stalls are visible immediately through sequence numbers and heartbeats, instead of being inferred after the fact.
Which should you use
Use v2 for new integrations. It is where enrichment, slot events, live filters, and the liveness signals live, and where every new capability lands. v1 stays fully supported and has no set retirement date, so an existing v1 client can keep running as it is. We do encourage moving over, though: as more traffic consolidates onto v2, it frees the capacity we dedicate to v1 today for the next generation of OrbitFlare streaming. Either way, migrating is a change in your client code, not your connection: same endpoints, same authentication, running side by side.See Also
Jetstream v2 Overview
The streaming model, connecting, and best practices.
v2 Protocol Reference
Full v2 Protocol Buffer specification, endpoints, and code generation.
Jetstream (v1)
The v1 overview, client examples, and filtering guide.