> For the complete documentation index, see [llms.txt](https://raiden-4.gitbook.io/raiden.wtf.docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://raiden-4.gitbook.io/raiden.wtf.docs/shred-streaming-decoded-pulse/getting-started.md).

# Getting Started

Connect to Raiden Pulse gRPC binary stream in minutes

## 1. Reserve Access

→ [dashboard](https://raiden.wtf/dashboard/pulse)

## 2. Get Your Endpoint

| Region  | Endpoint                             |
| ------- | ------------------------------------ |
| **FRA** | `http://fra.pulse.raiden.wtf:16000/` |
| **NYC** | `http://nyc.pulse.raiden.wtf:16000/` |
| **AMS** | `http://ams.pulse.raiden.wtf:16000/` |

Each region requires a separate subscription.

## 3. Protocol

Raiden Pulse is **protocol-compatible** with the open [`shreder-rust-example`](https://github.com/shrederxyz/shreder-rust-example/tree/main/src/examples/binary) reference client and its `shreder_binary.proto`. If your stack already integrates that proto, you can point it at Raiden Pulse endpoints with no code changes.

### Proto summary

* Service: `ShrederBinaryService`
* RPC: `SubscribeBinaryTransactions` — bidirectional streaming
* Request: `SubscribeBinaryTransactionsRequest` with named filter map
* Filter: `SubscribeRequestFilterBinaryTransactions` — `account_include`, `account_exclude`, `account_required`
* Payload: raw bytes deserialized via `bincode` into Solana `VersionedTransaction`

## 4. Connect

### Rust (tonic)

```rust
pub mod shreder_binary {
    tonic::include_proto!("shreder_binary");
}

use futures::{channel::mpsc::unbounded, sink::SinkExt};
use maplit::hashmap;
use shreder_binary::{
    shreder_binary_service_client::ShrederBinaryServiceClient,
    SubscribeBinaryTransactionsRequest,
    SubscribeRequestFilterBinaryTransactions,
};
use solana_transaction::versioned::VersionedTransaction;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let entrypoint = "http://fra.pulse.raiden.wtf:9991";
    let mut client = ShrederBinaryServiceClient::connect(entrypoint).await?;

    let (mut tx_req, rx_req) = unbounded();
    let request = SubscribeBinaryTransactionsRequest {
        transactions: hashmap! {
            "pumpfun".to_owned() => SubscribeRequestFilterBinaryTransactions {
                account_exclude: vec![],
                account_include: vec![],
                account_required: vec![
                    "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P".to_owned(),
                ],
            }
        },
    };
    tx_req.send(request).await?;

    let mut stream = client
        .subscribe_binary_transactions(rx_req)
        .await?
        .into_inner();

    while let Some(response) = stream.message().await? {
        let Some(update) = response.transaction else { continue };
        let Some(tx) = update.transaction else { continue };

        let versioned_tx: VersionedTransaction =
            match bincode::deserialize(&tx.binary_transaction) {
                Ok(vt) => vt,
                Err(_) => continue,
            };

        let instruction_count = versioned_tx.message.instructions().len();
        println!(
            "slot={} sig={} ixs={}",
            tx.slot,
            tx.signature,
            instruction_count,
        );
    }
    Ok(())
}
```

Enable tonic TLS features if your endpoint uses HTTPS:

```toml
tonic = { version = "0.10", features = ["tls", "tls-roots", "tls-webpki-roots"] }
```

### Python (grpcio + protobuf)

Generate Python bindings from `shreder_binary.proto`:

```bash
python -m grpc_tools.protoc -Iproto \
  --python_out=. --grpc_python_out=. \
  proto/shreder_binary.proto
```

Then connect:

```python
import grpc
from shreder_binary_pb2 import (
    SubscribeBinaryTransactionsRequest,
    SubscribeRequestFilterBinaryTransactions,
)
from shreder_binary_pb2_grpc import ShrederBinaryServiceStub

channel = grpc.insecure_channel("fra.pulse.raiden.wtf:9991")
stub = ShrederBinaryServiceStub(channel)

def make_requests():
    yield SubscribeBinaryTransactionsRequest(
        transactions={
            "pumpfun": SubscribeRequestFilterBinaryTransactions(
                account_required=["6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"],
            ),
        },
    )

for response in stub.SubscribeBinaryTransactions(make_requests()):
    tx = response.transaction.transaction
    # tx.binary_transaction is raw bincode-encoded VersionedTransaction
    print(f"slot {tx.slot} sig {tx.signature}")
```

### TypeScript (`@grpc/grpc-js`)

Generate TS bindings from the proto, then:

```ts
import { credentials } from '@grpc/grpc-js';
import { ShrederBinaryServiceClient } from './generated/shreder_binary_grpc_pb';
import {
  SubscribeBinaryTransactionsRequest,
  SubscribeRequestFilterBinaryTransactions,
} from './generated/shreder_binary_pb';

const client = new ShrederBinaryServiceClient(
  'fra.pulse.raiden.wtf:9991',
  credentials.createInsecure(),
);

const stream = client.subscribeBinaryTransactions();

const filter = new SubscribeRequestFilterBinaryTransactions();
filter.setAccountRequiredList(['6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P']);

const req = new SubscribeBinaryTransactionsRequest();
req.getTransactionsMap().set('pumpfun', filter);
stream.write(req);

stream.on('data', (response) => {
  const tx = response.getTransaction().getTransaction();
  console.log(`slot ${tx.getSlot()} sig ${tx.getSignature()}`);
});
```

## 5. Filtering

Every subscription requires at least one filter entry in the `transactions` map. Each entry name is client-chosen (e.g. `"pumpfun"`, `"jupiter-swaps"`) and carries:

| Field              | Purpose                                            |
| ------------------ | -------------------------------------------------- |
| `account_required` | Transactions **must** touch every listed account   |
| `account_include`  | Transactions **may** touch any listed account      |
| `account_exclude`  | Transactions **must not** touch any listed account |

Server-side filtering — no wasted bandwidth.

## 6. Decoding the Payload

Each `tx.binary_transaction` is a `bincode`-encoded Solana `VersionedTransaction`. Deserialize client-side with your language's bincode / serde equivalent:

* **Rust:** `bincode::deserialize::<VersionedTransaction>(&bytes)`
* **Python:** [`solders`](https://github.com/kevinheavey/solders) → `VersionedTransaction.from_bytes(bytes)`
* **TS:** `@solana/web3.js` → `VersionedTransaction.deserialize(bytes)`

## 7. Limits

| Limit                      | Value                  |
| -------------------------- | ---------------------- |
| **Concurrent connections** | 10                     |
| **Named filters**          | 35 per connection      |
| **Account filters**        | 5,000 per named filter |

A named filter carrying more than 5,000 accounts is rejected. If you need to watch more, split them across filters, and across connections once you pass 35.

## 8. Pulse V2: `raiden_binary.proto` and resolved ALTs

Pulse V2 moves off the third-party `shreder_binary` proto onto Raiden's own, `raiden_binary`. Both are served during the transition, so nothing breaks on the day it lands, but new integrations should expect to move.

{% hint style="info" %}
The rename is not the point. **V2 resolves address lookup tables server-side**, which is what makes the migration worth doing rather than merely necessary.
{% endhint %}

### What changes

|                      | `shreder_binary` (today)                     | `raiden_binary` (Pulse V2)                                                  |
| -------------------- | -------------------------------------------- | --------------------------------------------------------------------------- |
| Package              | `shreder_binary`                             | `raiden_binary`                                                             |
| Service              | `ShrederBinaryService`                       | `RaidenBinaryService`                                                       |
| RPC                  | `SubscribeBinaryTransactions`                | unchanged                                                                   |
| Filters              | `account_include` / `_exclude` / `_required` | unchanged                                                                   |
| Matched filter names | not reported                                 | `filters` on every response                                                 |
| Server timestamp     | not reported                                 | `created_at`                                                                |
| ALT resolution       | client-side, your problem                    | server-side, in `loaded_writable_addresses` and `loaded_readonly_addresses` |
| Signatures           | single field                                 | `signatures`, repeated                                                      |

### Resolved ALTs

A V0 transaction names most of its accounts indirectly, through an address lookup table. To know which accounts it actually touches you have to resolve those tables yourself, which means fetching them, caching them, and keeping the cache correct as tables change.

Pulse V2 does that resolution server-side and ships the result alongside the transaction. The full account set is then the direct keys inside `binary_transaction` **plus** `loaded_writable_addresses` and `loaded_readonly_addresses`. Both are empty for legacy transactions, which carry no lookup tables.

If you are filtering or routing on the accounts a transaction touches, this removes an entire subsystem from your client.

### The proto

```protobuf
syntax = "proto3";

package raiden_binary;

import "google/protobuf/timestamp.proto";

service RaidenBinaryService {
  rpc SubscribeBinaryTransactions(stream SubscribeBinaryTransactionsRequest)
      returns (stream SubscribeBinaryTransactionsResponse);
}

message SubscribeBinaryTransactionsRequest {
  map<string, SubscribeRequestFilterBinaryTransactions> transactions = 3;
}

message SubscribeBinaryTransactionsResponse {
  repeated string filters = 1;
  SubscribeUpdateBinaryTransaction transaction = 4;
  google.protobuf.Timestamp created_at = 11;
}

message SubscribeUpdateBinaryTransaction {
  BinaryTransaction transaction = 1;
  uint64 slot = 2;
  // ALT-resolved accounts. Empty for legacy transactions.
  repeated bytes loaded_writable_addresses = 3;
  repeated bytes loaded_readonly_addresses = 4;
}

message SubscribeRequestFilterBinaryTransactions {
  repeated string account_include = 3;
  repeated string account_exclude = 4;
  repeated string account_required = 6;
}

message BinaryTransaction {
  repeated bytes signatures = 1;
  // Serialized VersionedTransaction
  bytes binary_transaction = 3;
}
```

### Migrating

The subscription shape is unchanged, so a filter map written for `shreder_binary` transfers as-is. What moves is where fields live:

* Regenerate bindings from `raiden_binary.proto` and swap `ShrederBinaryServiceClient` for `RaidenBinaryServiceClient`.
* `slot` is on the update, not on the transaction.
* `signatures` is a repeated field of raw bytes rather than a single string, so take the first element and encode it yourself if you were printing it.
* `binary_transaction` is unchanged: still a bincode-encoded `VersionedTransaction`, decoded exactly as before.

## Pricing

See [Pricing](/raiden.wtf.docs/infrastructure/pricing.md).

{% hint style="info" %}
Payment in **USDC on Solana** via the dashboard.
{% endhint %}
