> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbitflare.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Jetstream v2 Protocol Reference

> Protocol Buffer specification for OrbitFlare Jetstream v2

## 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.

<Tabs>
  <Tab title="US">
    | City           | Region Slug | Endpoint                              |
    | -------------- | ----------- | ------------------------------------- |
    | New York       | `ny`        | `http://ny.jetstream.orbitflare.com`  |
    | Salt Lake City | `slc`       | `http://slc.jetstream.orbitflare.com` |
    | Ashburn        | `ash`       | `http://ash.jetstream.orbitflare.com` |
    | Los Angeles    | `la`        | `http://la.jetstream.orbitflare.com`  |
  </Tab>

  <Tab title="Europe">
    | City                | Region Slug | Endpoint                               |
    | ------------------- | ----------- | -------------------------------------- |
    | Frankfurt           | `fra`       | `http://fra.jetstream.orbitflare.com`  |
    | Amsterdam           | `ams`       | `http://ams.jetstream.orbitflare.com`  |
    | London              | `lon`       | `http://lon.jetstream.orbitflare.com`  |
    | Dublin              | `dub`       | `http://dub.jetstream.orbitflare.com`  |
    | Siauliai, Lithuania | `siau`      | `http://siau.jetstream.orbitflare.com` |
  </Tab>

  <Tab title="Asia Pacific">
    | City      | Region Slug | Endpoint                              |
    | --------- | ----------- | ------------------------------------- |
    | Tokyo     | `jp`        | `http://jp.jetstream.orbitflare.com`  |
    | Singapore | `sgp`       | `http://sgp.jetstream.orbitflare.com` |
  </Tab>
</Tabs>

<Note>
  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.
</Note>

## 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](/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

```protobuf theme={null}
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

```protobuf theme={null}
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.

```protobuf theme={null}
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;
}
```

<Note>
  A filter must specify at least one of `account_include` / `account_exclude` / `account_required`.
  Empty (match-everything) filters are rejected — see [FilterResult](#filter-validation).
</Note>

#### Removing Filters

```protobuf theme={null}
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.

```protobuf theme={null}
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.

```protobuf theme={null}
message FilterResult {
  string filter_id        = 1;
  bool   accepted         = 2;
  string rejection_reason = 3;  // empty string when accepted=true (proto3 default elision)
}
```

#### Heartbeat

```protobuf theme={null}
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.

```protobuf theme={null}
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

```protobuf theme={null}
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.

```protobuf theme={null}
// 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

```protobuf theme={null}
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:

```bash theme={null}
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:

```bash theme={null}
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

<CardGroup cols={2}>
  <Card title="Jetstream v2 Overview" icon="bolt" href="/data-streaming/jetstream-v2">
    What v2 adds over v1, the streaming model, and getting started.
  </Card>

  <Card title="Jetstream (v1) Reference" icon="book" href="/data-streaming/jetstream-reference">
    The v1 Protocol Buffer specification.
  </Card>
</CardGroup>

## Support

For technical questions about the v2 protocol or implementation details, please join our
[Discord community](https://discord.gg/orbitflare).
