Skip to main content

Available Endpoints

Jetstream v2 is served on the same endpoints as v1 — there is no separate host. The JetstreamV2 service is exposed over the same HTTP/2 connection and routed by the gRPC method path, so you connect to the region closest to your infrastructure exactly as you would for v1.
CityRegion SlugEndpoint
New Yorknyhttp://ny.jetstream.orbitflare.com
Salt Lake Cityslchttp://slc.jetstream.orbitflare.com
Ashburnashhttp://ash.jetstream.orbitflare.com
Los Angeleslahttp://la.jetstream.orbitflare.com
Jetstream uses plain http:// (not https://) for gRPC connections. gRPC negotiates its own transport security over HTTP/2. Use https:// only if your dedicated node explicitly requires it.

Authentication

Authentication is the same as v1: supply your API key in the x-token gRPC metadata header, or use IP-whitelist authentication. See Authentication for details.

Protocol Buffer Specification

This document outlines the Protocol Buffer (protobuf) specification used by OrbitFlare Jetstream v2. The jetstream.v2 package is fully independent of v1 — generate a separate client from the definition below.

Service Definition

syntax = "proto3";

package jetstream.v2;

import "google/protobuf/timestamp.proto";

service JetstreamV2 {
  rpc SubscribeTransactions(stream SubscribeTransactionsRequest) returns (stream SubscribeTransactionsResponse) {}

  // Server-streaming slot lifecycle events.
  rpc SubscribeSlots(SubscribeSlotsRequest) returns (stream SlotEvent) {}

  // Unary health/version probes.
  rpc Ping(PingRequest) returns (PongResponse) {}
  rpc GetVersion(GetVersionRequest) returns (GetVersionResponse) {}
}

Request Messages

SubscribeTransactions is a bidirectional stream. The client sends a sequence of request messages — each carrying exactly one payload — to manage its subscription while the stream is open.

SubscribeTransactionsRequest

message SubscribeTransactionsRequest {
  oneof payload {
    Ping          ping           = 1;
    AddFilters    add_filters    = 2;
    RemoveFilters remove_filters = 3;
  }
}

message Ping {
  int32 ping_id = 1;
}

Adding Filters

Filters are added dynamically while the stream is open. Each filter carries a client-chosen filter_id that is echoed back on every matching transaction and in the validation acknowledgement.
message AddFilters {
  repeated TxFilter filters = 1;
}

message TxFilter {
  string                             filter_id = 1;  // client-provided, max 128 chars
  SubscribeRequestFilterTransactions filter    = 2;
}

message SubscribeRequestFilterTransactions {
  repeated string account_include  = 1;
  repeated string account_exclude  = 2;
  repeated string account_required = 3;

  // Opt-in enrichment. Default false = lean response (core fields only). Set
  // true to also receive fee_payer / writable_accounts / program_ids /
  // priority_fee / compute_limit / tx_size. Applies to the whole
  // subscription: if any of your active filters sets this true, every
  // transaction you receive is enriched.
  bool include_enrichment = 4;
}
A filter must specify at least one of account_include / account_exclude / account_required. Empty (match-everything) filters are rejected — see FilterResult.

Removing Filters

message RemoveFilters {
  repeated string filter_ids = 1;
}

Response Messages

SubscribeTransactionsResponse

Every message on the stream carries a server timestamp and a monotonically increasing sequence number (per stream) so clients can detect gaps. Exactly one payload is set.
message SubscribeTransactionsResponse {
  google.protobuf.Timestamp created_at = 1;

  oneof payload {
    FilteredTransaction transaction       = 2;
    Pong                pong              = 3;
    FilterResult        filter_validation = 5;
    Heartbeat           heartbeat         = 6;
  }

  uint64 sequence = 4;
}

message Pong {
  int32 ping_id = 1;
}

Filter Validation

After each AddFilters / RemoveFilters, the server returns one FilterResult per filter, acknowledging acceptance or explaining the rejection.
message FilterResult {
  string filter_id        = 1;
  bool   accepted         = 2;
  string rejection_reason = 3;  // empty string when accepted=true (proto3 default elision)
}

Heartbeat

message Heartbeat {
  // Server wall-clock at emit time, milliseconds since Unix epoch. Lets
  // clients measure one-way skew / network delay and age out stale
  // connections.
  uint64 server_ts_ms = 1;
}

Filtered Transaction

Each matched transaction lists the filter_id values it matched, followed by the transaction itself.
message FilteredTransaction {
  repeated string    filter_ids  = 1;
  TransactionMessage transaction = 2;
}

// TransactionMessage — a flat transaction representation (all fields inline).
// Fields 1-13 are the core transaction and are always present (the default
// "lean" output). Fields 14-21 are optional enrichment, emitted only when the
// session opts in via SubscribeRequestFilterTransactions.include_enrichment.
message TransactionMessage {
  // Identity / placement
  uint64 slot      = 1;
  bytes  signature = 2;  // primary signature (signatures[0])
  uint32 tx_index  = 3;  // position of this tx within its entry

  // Full signature set (repeated bytes)
  repeated bytes signatures = 4;

  // Vote flag
  bool is_vote = 5;

  // Message header
  uint32 num_required_signatures        = 6;
  uint32 num_readonly_signed_accounts   = 7;
  uint32 num_readonly_unsigned_accounts = 8;

  // Recent blockhash
  bytes recent_blockhash = 9;

  // Versioned-transaction flag.
  bool versioned = 10;

  // Core body contents
  repeated bytes                     account_keys          = 11;
  repeated CompiledInstruction       instructions          = 12;
  repeated MessageAddressTableLookup address_table_lookups = 13;

  // Enrichment — emitted only when the session opts in via
  // SubscribeRequestFilterTransactions.include_enrichment.
  bytes          fee_payer         = 14;
  repeated bytes writable_accounts = 15;
  repeated bytes program_ids       = 16;
  uint64         priority_fee      = 17;
  uint32         compute_limit     = 18;
  uint32         tx_size           = 19;

  // Resolved addresses from a versioned tx's address_table_lookups. Emitted
  // only when enrichment is opted in (same gate as fields 14-19). Empty when
  // address-lookup-table resolution is disabled or the referenced table is
  // unavailable (other lookups in the same tx still resolve).
  repeated bytes loaded_writable_addresses = 20;
  repeated bytes loaded_readonly_addresses = 21;
}

Shared Types

message CompiledInstruction {
  uint32 program_id_index = 1;
  bytes  accounts         = 2;
  bytes  data             = 3;
}

message MessageAddressTableLookup {
  bytes account_key      = 1;
  bytes writable_indexes = 2;
  bytes readonly_indexes = 3;
}

Slot Streaming

SubscribeSlots is a server stream of slot lifecycle events. It takes no parameters — open the stream and receive events as slots progress.
// SubscribeSlots takes no request parameters.
message SubscribeSlotsRequest {
}

enum SlotStatus {
  SLOT_STATUS_UNSPECIFIED = 0;
  SLOT_STATUS_ALIVE       = 1;  // first shred of this slot received
  SLOT_STATUS_COMPLETE    = 2;  // last shred of this slot received
  SLOT_STATUS_DEAD        = 3;  // slot skipped, or not completed before timeout
}

message SlotEvent {
  uint64     slot           = 1;
  SlotStatus status         = 2;
  // 32-byte pubkey. Empty bytes (proto3 default) means the leader schedule
  // is disabled at the server.
  bytes      current_leader = 3;
  // Parent slot, from the first shred received for this slot. 0 means
  // "unknown parent" (e.g. a DEAD event for a slot that was never observed).
  uint64     parent_slot    = 4;
  uint64     sequence       = 5;  // monotonic per-stream
}

Non-streaming Methods

message PingRequest {
  int32 count = 1;
}

message PongResponse {
  int32 count = 1;
}

message GetVersionRequest {}

message GetVersionResponse {
  string version = 1;
}

Using the Protocol

A typical v2 client:
  1. Generate client code from the jetstream.v2 definition above.
  2. Open the SubscribeTransactions bidirectional stream and authenticate (x-token header or IP whitelist).
  3. Send an AddFilters request with one or more TxFilter entries, each with a unique filter_id.
  4. Read the FilterResult acknowledgements, then the stream of FilteredTransaction messages.
  5. Add or remove filters at any time without reopening the stream.
  6. Track sequence to detect gaps, and treat a connection close as a signal to reconnect.
  7. Optionally open SubscribeSlots (a separate stream) for slot lifecycle events.

Code Generation

For TypeScript/JavaScript:
protoc --plugin=protoc-gen-ts_proto=./node_modules/.bin/protoc-gen-ts_proto \
  --ts_proto_out=. \
  --ts_proto_opt=esModuleInterop=true \
  jetstream_v2.proto
For Rust:
protoc --rust_out=. jetstream_v2.proto

Best Practices

  1. Filtering
    • Always set at least one account constraint; empty filters are rejected.
    • Use a stable, unique filter_id per filter so you can correlate matches and remove filters later.
  2. Enrichment
    • Leave include_enrichment off unless you need the extra fields — lean output is smaller and faster.
    • Enrichment is subscription-wide: enabling it on any one filter enriches every transaction the session receives.
  3. Sequence & Reconnection
    • Track the sequence number to detect dropped messages.
    • Implement automatic reconnection; on reconnect, re-send your AddFilters.
  4. Liveness
    • Use Heartbeat and Ping/Pong to confirm the stream is healthy and measure latency.

See Also

Jetstream v2 Overview

What v2 adds over v1, the streaming model, and getting started.

Jetstream (v1) Reference

The v1 Protocol Buffer specification.

Support

For technical questions about the v2 protocol or implementation details, please join our Discord community.