Skip to main content

At a glance

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, the compute-unit price it set, 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.
compute_unit_price is the compute-unit price — the micro-lamports-per-CU value from SetComputeUnitPrice, not the total priority fee. For the total priority fee in lamports, multiply by the compute-unit limit and divide by 1,000,000: compute_unit_price × compute_limit / 1e6. compute_limit reflects only an explicit SetComputeUnitLimit (0 if the transaction sets none).
The lookup-table row is the big one. A versioned transaction does not carry its full account list. It carries a reference to an on-chain lookup table plus a set of indexes. On v1, to learn which accounts the transaction actually touches, you make a full RPC call to fetch that table and then resolve the indexes yourself, for every transaction — an extra request and response that is far slower than the stream itself and sits right on your critical path. With v2 enrichment on, those resolved addresses are already included, so that lookup is off your critical path. The other rows are work your client would otherwise repeat on every transaction; v2 delivers the answers inline instead.
For a versioned transaction, the resolved lookup-table addresses are included. If any can’t be fully included, alt_resolution_incomplete is set on that transaction so you resolve those yourself (fetch the tables via RPC) — no silent gaps.
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 — turning it on adds no latency to the stream; the only difference is a modestly larger message. 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 live stream while you reconnect. v2 keeps the stream open and lets you add and remove filters as you go. You give each filter your own filter_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. Account include / exclude / required behave exactly as in v1 — required is any-of (a transaction matches if it references at least one listed account), not all-of.

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 superseded by later slots without completing (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 sequence number that climbs by one. See a gap and you know you dropped a message.
  • When a transaction stream goes quiet, v2 sends a Heartbeat every 60 seconds, stamped with the server’s clock. That keeps the connection alive through load-balancer idle timeouts, and tells a quiet stream apart from a dead one.

Why this adds up to a faster result

  • A round-trip off your critical path. On v1, resolving a lookup table is a full RPC request and response, much slower than the stream itself. With v2 enrichment on, a versioned transaction’s resolved addresses arrive inline, so that call never sits between a transaction arriving and you acting on it.
  • Less work per transaction on your side. The enrichment fields arrive already computed, so your client doesn’t re-derive them on every transaction.
  • 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 yet, 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.

Support

For technical support or questions about Jetstream v2, please contact our support team or join our Discord community.