> For the complete documentation index, see [llms.txt](https://docs.rpcfast.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.rpcfast.com/rpc-fast-saas-solana/sending-transactions/rpc-fast-beam-beta.md).

# RPC Fast Beam (Beta)

## Overview

{% hint style="info" %}
RPC Fast Beam is currently in beta. Core changes may be introduced as the product evolves.
{% endhint %}

**RPC Fast Beam** is a low-latency Solana transaction submission service for execution-sensitive systems.

Beam routes signed transactions through partner delivery paths such as **SWQoS-backed validators**, **Jito Block Engine submission**, and other provider-specific low-latency infrastructure. This improves landing probability during congestion and reduces latency variance.

Beam is built for HFT, MEV searchers, liquidation bots, arbitrage engines, latency-sensitive market makers, and apps that care about delivery quality.

Beam is also useful for users who need maximum transaction protection from sandwich attacks, front-running, and toxic MEV.

{% hint style="info" %}
RPC Fast Beam is a **transaction delivery service** – not a general-purpose Solana RPC endpoint.
{% endhint %}

### At a Glance

| Capability             | Details                                                                                                                                                           |
| ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Purpose                | Fast Solana transaction delivery                                                                                                                                  |
| HTTP endpoint          | `https://beam.rpcfast.com`                                                                                                                                        |
| QUIC endpoint          | `beam.rpcfast.com:9900`                                                                                                                                           |
| Tip feed               | `wss://beam.rpcfast.com/tips?provider=<provider>`                                                                                                                 |
| Provider score feed    | `wss://beam.rpcfast.com/provider-scores`                                                                                                                          |
| HTTP methods           | `sendTransaction`, `sendBundle`                                                                                                                                   |
| QUIC methods           | `sendTransaction`, `sendTransactionFast`                                                                                                                          |
| Rust QUIC client       | [`beam-quic-client`](https://crates.io/crates/beam-quic-client)                                                                                                   |
| Providers              | `astralane`, `bloxroute`, `falcon`                                                                                                                                |
| Modes                  | `fastest`, `mev_protect`                                                                                                                                          |
| Authorization          | `api_key` query arg or `X-Token` header                                                                                                                           |
| Availability           | All plans                                                                                                                                                         |
| CU cost                | `5 CU` per request                                                                                                                                                |
| Rate limit             | <ul><li>Start plan - <code>60 txs/minute</code></li><li>Focus plan - <code>200 txs/minute</code></li><li>Stream, Aperture - <code>500 txs/minute</code></li></ul> |
| Required on every send | Tip transfer instruction                                                                                                                                          |
| Ignored on send path   | Node-side retries and preflight controls                                                                                                                          |

***

### How Beam Works

When you send a transaction through Beam, it’s routed via your selected provider.

Under the hood, Beam leverages provider-specific low-latency infrastructure – such as **SWQoS-backed validator paths**, **Jito Block Engine**, **Harmonic**, or **Rakurai** submission – to maximize how quickly your transaction reaches the current leader. In competitive conditions, this can significantly improve landing probability.

This becomes critical in scenarios where packet delivery speed matters just as much as on-chain priority fees.

For deeper background, see [SWQoS](/rpc-fast-saas-solana/sending-transactions/swqos.md) and [Aperture gRPC (Beta)](/rpc-fast-saas-solana/data-streaming/aperture-grpc-beta.md).

#### Best practices

To maximize reliability and performance, distribute your transaction submissions across multiple providers in parallel. This reduces reliance on any single route and improves overall resilience.

#### Abuse prevention policy

**Users are prohibited from abusing the platform infrastructure,** including but not limited to excessive spam transaction generation, persistent failed bundle submissions, artificial traffic amplification, or any activity that negatively impacts platform stability, SWQoS partners, or other users of the service.

Because our sender service is currently provided in Beta, our abuse-detection systems, fair-use thresholds, rate limits, and enforcement policies may change at any time without prior notice. We reserve the right to make enforcement decisions at our sole discretion when necessary to protect the platform, infrastructure providers, or other users. Read more in [Terms of Service](https://docs.rpcfast.com/legal/terms-of-service#id-4.-subscription-plans-credits-and-billing).

***

### Endpoints

#### Transactions submission endpoint

Supports `sendTransaction` and `sendBundle` methods.

```http
https://beam.rpcfast.com
```

#### QUIC submission endpoint

Use the Beam QUIC endpoint provided for your account.

```http
beam.rpcfast.com:9900
```

#### Tip guidance feed

```http
wss://beam.rpcfast.com/tips?provider=<provider>
```

Replace `<provider>` with one of:

```
astralane
bloxroute
falcon
```

***

### Authorization

Beam accepts an API key through either of these methods:

* `api_key` query argument
* `X-Token` header

#### Query argument

```bash
curl 'https://beam.rpcfast.com/?api_key=<your-api-key>' \
  -X POST \
  -H 'Content-Type: application/json' \
  -d '{}'
```

#### Header

```bash
curl 'https://beam.rpcfast.com/?mode=fastest&provider=bloxroute' \
  -X POST \
  -H 'Content-Type: application/json' \
  -H 'X-Token: <your-api-key>' \
  -d '{}'
```

#### QUIC

For QUIC, pass the same RPC Fast API key to `BeamQuicClient::connect`. The client authenticates with an ephemeral client certificate whose Common Name contains the API key; the key is not sent as a query argument, HTTP header, or request-frame field.

***

### Query Arguments

Beam supports transaction mode selection and provider override through URL query arguments.

#### Provider override

```
provider=astralane | bloxroute | falcon
```

If `provider` is not specified, Beam detects the provider from the tipping address you have included in your transaction.

**Example**

```
https://beam.rpcfast.com/?provider=falcon
```

#### Mode

```
mode=fastest | mev_protect
```

If `mode` is not specified, Beam uses `fastest` by default.

Supported modes depend on the selected provider. See [Providers](#providers).

| Mode          | Use when                                                                  | Notes                                                            |
| ------------- | ------------------------------------------------------------------------- | ---------------------------------------------------------------- |
| `fastest`     | Lowest possible submission latency matters most                           | Best for HFT, arbitrage, liquidations, and same-slot competition |
| `mev_protect` | Protection against frontrunning, backrunning and sandwiching matters most | Best for sensitive order flow and execution privacy              |

Choose the mode that matches the intent of the transaction.

***

### QUIC Transaction Submission (Beta)

Use Beam QUIC when transaction delivery latency matters more than HTTP compatibility. It is best suited for HFT systems, MEV searchers, liquidation bots, arbitrage engines, and market makers that keep a long-lived sender process running.

Beam QUIC supports:

| Method                | Use when                                                                                           | Response |
| --------------------- | -------------------------------------------------------------------------------------------------- | -------- |
| `sendTransaction`     | You want low-latency submission and still need Beam to return the signature and routed provider.   | Yes      |
| `sendTransactionFast` | You want the lowest-latency fire-and-forget path and can track the transaction in your own system. | No       |

`sendTransactionFast` is intentionally a separate low-latency path:

* `provider` is required.
* Beam does not return a response.
* Beam does not wait for an upstream provider response.
* Beam skips Beam-side transaction deserialization, signature extraction, and tip validation.
* If `signature` is provided, Beam can use it for landing metrics.
* If `signature` is omitted, Beam submits the transaction bytes but does not create a tracking row for that transaction.

{% hint style="warning" %}
Use regular QUIC `sendTransaction` if your application needs immediate request-level feedback. Use `sendTransactionFast` only when your application can handle fire-and-forget submission.
{% endhint %}

#### Rust QUIC client

The recommended Rust integration is the shared [`beam-quic-client`](https://crates.io/crates/beam-quic-client) crate.

```toml
[dependencies]
beam-quic-client = "0.1.0"
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }
```

The client reuses a QUIC connection, generates the Beam client certificate automatically, places your API key in the certificate Common Name, and reconnects if the connection is closed.

See the `Rust QUIC` tab in [Code Examples](#code-examples) for a complete integration that fetches a blockhash, appends a provider tip, signs the transaction, and submits it through `beam-quic-client`.

***

### Providers and Tips

Every transaction sent through Beam **must include a valid tip** instruction to the addresses provided in these docs.

{% hint style="warning" %}
RPC Fast Beam does not inject tip instructions automatically. Your application must append the provider-specific tip transfer before signing and sending.
{% endhint %}

Sending a transaction without a valid provider tip **is not supported** and will lead to send failure.

It is strongly recommended to **rotate the tip account** on every transaction.

Regular QUIC `sendTransaction` follows the same provider and tip validation rules as HTTP `sendTransaction`.

`sendTransactionFast` requires an explicit `provider` and skips Beam-side tip validation/signature extraction for latency reasons. Your transaction should still include the appropriate provider tip instruction before signing.

#### Providers

<table><thead><tr><th width="103.109375">Provider</th><th width="415.18359375">Tip accounts</th><th width="101.1328125">Bundle support</th><th>Mode support</th></tr></thead><tbody><tr><td>Astralane</td><td><pre><code>ASdXviZw2kbViFuAgZF26RPZL1HdybUoWdcveG2nfU8D
Ax2JBnTPUpBFWe75z3YtgueWUfvZPZ6ZFXiMWJMUnjbo
</code></pre></td><td><span data-gb-custom-inline data-tag="emoji" data-code="2705">✅</span></td><td><code>fastest</code>, <code>mev_protect</code></td></tr><tr><td>bloXroute</td><td><pre><code>rfBP8KJ6KMqvBhmqaV7EoNHVexXQdn1sX4CJ9aLv5w2
rfBkmha9yK5QS7h562Pn6Bfw6cPjsrgVqgcnnXBoXj7
rfBxDPw4XK2WKBinv7Vbr68inD964H7HTMLMWshe3jT
</code></pre></td><td><span data-gb-custom-inline data-tag="emoji" data-code="2705">✅</span></td><td><code>fastest</code>, <code>mev_protect</code></td></tr><tr><td>Falcon by Corvus</td><td><pre><code>rfCCxFtXuwjjnP9cXAaEgvCzLkrzXwAiWQadJ4uNKmf
rfCTcFU5p63roQ7S8sTwpQ93NHfGxf5ThSsbH1CjQbf
rfC18Jx6rqwhvwjWpkZnX8q7vE45vzxBXtic1jLr32R
rfCmxTvz2LeEzVmFZHvcfLvz4EaT6Rbkkff98RufbdZ
rfCaRhB66prehCypC53XeSPJ83cTjzwa8cHMeNpenQ8
</code></pre></td><td><span data-gb-custom-inline data-tag="emoji" data-code="274c">❌</span></td><td><code>fastest</code></td></tr></tbody></table>

`sendBundle` is supported only by `astralane` and `bloxroute`.

`mev_protect` is supported only by `astralane` and `bloxroute`.

#### Recommended tip amounts

RPC Fast Beam provides real-time tip guidance over WebSocket.

**WebSocket URL**

```
wss://beam.rpcfast.com/tips?provider=<provider>&api_key=YOUR_API_KEY
```

**Example response**

```json
{
  "time": "2026-04-15T11:03:44Z",
  "provider": "bloxroute",
  "25th_percentile": 0.001,
  "50th_percentile": 0.001,
  "75th_percentile": 0.001,
  "95th_percentile": 0.001,
  "99th_percentile": 0.001
}
```

All percentile values are denominated in `SOL`.

Higher percentiles generally improve landing probability during contention. Lower percentiles may be enough in quieter conditions.

#### Provider score feed

RPC Fast Beam provides real-time provider scoring feed over WebSocket.

**WebSocket URL**

```
wss://beam.rpcfast.com/provider-scores?api_key=YOUR_API_KEY
```

**Example response**

```json
[
  {
    "provider": "bloxroute",
    "score": 0.9,
    "success_rate": 1.0,
    "landing_latency": 186.263,
    "landing_rate": 1.0
  },
  {
    "provider": "astralane",
    "score": 1.0,
    "success_rate": 1.0,
    "landing_latency": 95.177,
    "landing_rate": 1.0
  },
  {
    "provider": "falcon",
    "score": 0.95,
    "success_rate": 1.0,
    "landing_latency": 145.311,
    "landing_rate": 1.0
  }
]
```

**Response fields**

* `landing_latency` - delay between transaction received on Beam and first seen across shreds.
* `landing_rate` - ratio of landed vs sent transactions
* `success_rate` - ratio of valid vs sent transactions
* `score` - computed score with following weights
  * 50 for landing\_rate
  * 30 for landing\_latency
  * 20 for success\_rate

***

### Pricing & Availability

Beam is available on all RPC Fast plans!

Transaction bundles submission is available **only on paid plans**.

#### Compute Units cost

Each transaction submission request costs **5 CU.**

***

### Rate limits

RPC Fast Beam currently offers:

* **60 transactions per minute** on Start plan
* **200 transactions per minute** on Focus plan
* **500 transactions per minute** on Stream and Aperture plans

These limits apply to both `sendTransaction` and `sendBundle` methods. Each transaction in a bundle is taken into account when calculating the rate limit.

QUIC submissions are subject to the same Beam plan limits as HTTP submissions. `sendTransactionFast` counts as a transaction submission request.

{% hint style="warning" %}
Please note that Beam has built-in spam classifier, so you need to maintain the quality of your transactions, otherwise rate limit penalties may be applied to your account.

For more info: [Spam Transactions & Abuse Prevention Policy (Beta)](/rpc-fast-saas-solana/sending-transactions/spam-transactions-and-abuse-prevention-policy-beta.md)
{% endhint %}

{% hint style="info" %}
Beam is currently in beta, and rate limits are subject to change as the service evolves.
{% endhint %}

***

### Supported Submission Methods

Beam currently supports HTTP JSON-RPC and QUIC submission methods.

HTTP JSON-RPC supports:

* `sendTransaction`
* `sendBundle`

QUIC supports:

* `sendTransaction`
* `sendTransactionFast`

`sendBundle` is not supported over Beam QUIC.

#### sendTransaction

Submit a signed transaction using the standard Solana JSON-RPC payload.

```bash
curl 'https://beam.rpcfast.com/' \
  -X POST \
  -H 'Content-Type: application/json' \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "sendTransaction",
    "params": [
      "<base64-encoded-signed-transaction>",
      {
        "encoding": "base64"
      }
    ]
  }'
```

#### Ignored `sendTransaction` options

Beam ignores Solana retry and preflight controls on the send path.

The following parameters are ignored:

* `maxRetries`
* `skipPreflight=false`

Retry logic must be implemented in your application. If a transaction does not land, rebuild or re-sign as needed and resubmit according to your own policy.

#### sendBundle

Use `sendBundle` when submitting bundles through a supported provider path. Bundles are mostly used in cases where you need atomic execution of transactions. These transactions are executed sequentially. If one of transaction fails the whole bundle gets reverted and never appears on-chain.

Supported providers: `astralane`, `bloxroute`.

```bash
curl 'https://beam.rpcfast.com/?mode=fastest' \
  -X POST \
  -H 'Content-Type: application/json' \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "sendBundle",
    "params": [
      [
        "<base64-encoded-signed-transaction-1>",
        "<base64-encoded-signed-transaction-2>"
      ]
    ]
  }'
```

***

### Code Examples

The same rules apply in every language:

* Reuse one RPC client across all sends.
* Use HTTP/2.
* Keep connections warm.
* Enable keep-alive and TCP keepalive where supported.
* Rotate the tip account for every transaction.
* Append the tip instruction before signing.
* For Rust QUIC integrations, use the shared `beam-quic-client` crate and reuse one long-lived client.

{% tabs %}
{% tab title="Rust QUIC" %}

```rust
use std::sync::atomic::{AtomicUsize, Ordering};
use std::time::Duration;

use anyhow::{anyhow, Result};
use beam_quic_client::{
    BeamQuicClient, Provider, RoutingMode, SendTransactionFastOptions, SendTransactionOptions,
};
use reqwest::{
    header::{HeaderMap, HeaderValue, CONTENT_TYPE},
    Client,
};
use serde_json::{json, Value};
use solana_sdk::{
    hash::Hash,
    instruction::Instruction,
    message::Message,
    pubkey::Pubkey,
    signature::{Keypair, Signature, Signer},
    system_instruction,
    transaction::Transaction,
};

const RPCFAST_TOKEN: &str = "YOUR_RPCFAST_TOKEN";
const SOLANA_RPC_URL: &str = "https://solana-rpc.rpcfast.com";
const BEAM_QUIC_ENDPOINT: &str = "beam.rpcfast.com:9900";

const BLOXROUTE_TIP_ACCOUNTS: [&str; 3] = [
    "rfBP8KJ6KMqvBhmqaV7EoNHVexXQdn1sX4CJ9aLv5w2",
    "rfBkmha9yK5QS7h562Pn6Bfw6cPjsrgVqgcnnXBoXj7",
    "rfBxDPw4XK2WKBinv7Vbr68inD964H7HTMLMWshe3jT",
];

pub struct JsonRpcClient {
    http: Client,
    rpc_url: String,
}

impl JsonRpcClient {
    pub fn new(rpc_url: impl Into<String>, token: &str) -> Result<Self> {
        let mut headers = HeaderMap::new();
        headers.insert(CONTENT_TYPE, HeaderValue::from_static("application/json"));
        headers.insert("X-Token", HeaderValue::from_str(token)?);

        let http = Client::builder()
            .default_headers(headers)
            .http2_prior_knowledge()
            .pool_idle_timeout(Duration::from_secs(90))
            .pool_max_idle_per_host(64)
            .tcp_keepalive(Duration::from_secs(30))
            .tcp_nodelay(true)
            .build()?;

        Ok(Self {
            http,
            rpc_url: rpc_url.into(),
        })
    }

    pub async fn call(&self, method: &str, params: Value) -> Result<Value> {
        let payload = json!({
            "jsonrpc": "2.0",
            "id": 1,
            "method": method,
            "params": params
        });

        let value: Value = self
            .http
            .post(&self.rpc_url)
            .json(&payload)
            .send()
            .await?
            .error_for_status()?
            .json()
            .await?;

        if let Some(error) = value.get("error") {
            return Err(anyhow!("rpc error: {error}"));
        }

        value
            .get("result")
            .cloned()
            .ok_or_else(|| anyhow!("missing result field"))
    }
}

pub struct BeamQuicExampleClient {
    // Recent blockhashes should be fetched from the standard Solana RPC endpoint.
    solana_rpc: JsonRpcClient,
    // Reuse this QUIC client for the lifetime of the process.
    beam_quic: BeamQuicClient,
    tip_accounts: Vec<Pubkey>,
    next_tip_idx: AtomicUsize,
}

impl BeamQuicExampleClient {
    pub async fn new(
        solana_rpc_url: impl Into<String>,
        beam_quic_endpoint: &str,
        token: &str,
        tip_accounts: &[&str],
    ) -> Result<Self> {
        if tip_accounts.is_empty() {
            return Err(anyhow!("tip account list must not be empty"));
        }

        let parsed_tip_accounts = tip_accounts
            .iter()
            .map(|s| s.parse::<Pubkey>())
            .collect::<std::result::Result<Vec<_>, _>>()?;

        Ok(Self {
            solana_rpc: JsonRpcClient::new(solana_rpc_url, token)?,
            beam_quic: BeamQuicClient::connect(beam_quic_endpoint, token).await?,
            tip_accounts: parsed_tip_accounts,
            next_tip_idx: AtomicUsize::new(0),
        })
    }

    fn next_tip_account(&self) -> Pubkey {
        let idx = self.next_tip_idx.fetch_add(1, Ordering::Relaxed) % self.tip_accounts.len();
        self.tip_accounts[idx]
    }

    fn build_tip_instruction(&self, payer: &Pubkey, tip_lamports: u64) -> Result<Instruction> {
        if tip_lamports == 0 {
            return Err(anyhow!("Beam requires a tip instruction on every transaction"));
        }

        Ok(system_instruction::transfer(
            payer,
            &self.next_tip_account(),
            tip_lamports,
        ))
    }

    async fn get_latest_blockhash(&self) -> Result<Hash> {
        let result = self
            .solana_rpc
            .call("getLatestBlockhash", json!([{ "commitment": "processed" }]))
            .await?;

        let blockhash = result["value"]["blockhash"]
            .as_str()
            .ok_or_else(|| anyhow!("missing blockhash"))?;

        Ok(blockhash.parse()?)
    }

    async fn build_signed_transaction(
        &self,
        payer: &Keypair,
        mut instructions: Vec<Instruction>,
        tip_lamports: u64,
    ) -> Result<Transaction> {
        let blockhash = self.get_latest_blockhash().await?;
        instructions.push(self.build_tip_instruction(&payer.pubkey(), tip_lamports)?);

        let message = Message::new(&instructions, Some(&payer.pubkey()));
        Ok(Transaction::new(&[payer], message, blockhash))
    }

    pub async fn send_transaction(
        &self,
        payer: &Keypair,
        instructions: Vec<Instruction>,
        tip_lamports: u64,
    ) -> Result<Signature> {
        let tx = self
            .build_signed_transaction(payer, instructions, tip_lamports)
            .await?;
        let tx_bytes = bincode::serialize(&tx)?;

        let result = self
            .beam_quic
            .send_transaction_bytes(
                tx_bytes,
                SendTransactionOptions {
                    provider: Some(Provider::Bloxroute),
                    mode: RoutingMode::Fastest,
                    request_id: None,
                },
            )
            .await?;

        Ok(result.signature.parse()?)
    }

    pub async fn send_transaction_fast(
        &self,
        payer: &Keypair,
        instructions: Vec<Instruction>,
        tip_lamports: u64,
    ) -> Result<Signature> {
        let tx = self
            .build_signed_transaction(payer, instructions, tip_lamports)
            .await?;
        let signature = tx
            .signatures
            .first()
            .cloned()
            .ok_or_else(|| anyhow!("missing transaction signature"))?;
        let tx_bytes = bincode::serialize(&tx)?;

        self.beam_quic
            .send_transaction_fast_bytes(
                tx_bytes,
                SendTransactionFastOptions {
                    provider: Provider::Bloxroute,
                    mode: RoutingMode::Fastest,
                    request_id: None,
                    signature: Some(signature.to_string()),
                },
            )
            .await?;

        Ok(signature)
    }
}

#[tokio::main]
async fn main() -> Result<()> {
    let beam = BeamQuicExampleClient::new(
        SOLANA_RPC_URL,
        BEAM_QUIC_ENDPOINT,
        RPCFAST_TOKEN,
        &BLOXROUTE_TIP_ACCOUNTS,
    )
    .await?;

    let payer = Keypair::new();
    let instructions: Vec<Instruction> = vec![];

    let signature = beam
        .send_transaction(&payer, instructions, 1_000_000)
        .await?;

    println!("{signature}");
    Ok(())
}
```

For fire-and-forget submission, use `sendTransactionFast`:

```rust
let fast_signature = beam
    .send_transaction_fast(&payer, vec![], 1_000_000)
    .await?;

println!("{fast_signature}");
```

{% endtab %}

{% tab title="Rust" %}

```rust
use std::sync::atomic::{AtomicUsize, Ordering};
use std::time::Duration;

use anyhow::{anyhow, Result};
use base64::Engine;
use reqwest::{
    header::{HeaderMap, HeaderValue, CONTENT_TYPE},
    Client,
};
use serde_json::{json, Value};
use solana_sdk::{
    hash::Hash,
    instruction::Instruction,
    message::Message,
    pubkey::Pubkey,
    signature::{Keypair, Signature, Signer},
    system_instruction,
    transaction::Transaction,
};

const RPCFAST_TOKEN: &str = "YOUR_RPCFAST_TOKEN";
const SOLANA_RPC_URL: &str = "https://solana-rpc.rpcfast.com";
const BEAM_URL: &str = "https://beam.rpcfast.com/?mode=fastest";

const TIP_ACCOUNTS: [&str; 6] = [
    // astralane
    "ASdXviZw2kbViFuAgZF26RPZL1HdybUoWdcveG2nfU8D",
    "Ax2JBnTPUpBFWe75z3YtgueWUfvZPZ6ZFXiMWJMUnjbo",
    // falcon
    "rfCCxFtXuwjjnP9cXAaEgvCzLkrzXwAiWQadJ4uNKmf",
    "rfCTcFU5p63roQ7S8sTwpQ93NHfGxf5ThSsbH1CjQbf",
    // bloxroute
    "rfBP8KJ6KMqvBhmqaV7EoNHVexXQdn1sX4CJ9aLv5w2",
    "rfBkmha9yK5QS7h562Pn6Bfw6cPjsrgVqgcnnXBoXj7",
];

pub struct JsonRpcClient {
    http: Client,
    rpc_url: String,
}

impl JsonRpcClient {
    pub fn new(rpc_url: impl Into<String>, token: &str) -> Result<Self> {
        let mut headers = HeaderMap::new();
        headers.insert(CONTENT_TYPE, HeaderValue::from_static("application/json"));
        headers.insert("X-Token", HeaderValue::from_str(token)?);

        let http = Client::builder()
            .default_headers(headers)
            .http2_prior_knowledge()
            .pool_idle_timeout(Duration::from_secs(90))
            .pool_max_idle_per_host(64)
            .tcp_keepalive(Duration::from_secs(30))
            .tcp_nodelay(true)
            .build()?;

        Ok(Self {
            http,
            rpc_url: rpc_url.into(),
        })
    }

    pub async fn call(&self, method: &str, params: Value) -> Result<Value> {
        let payload = json!({
            "jsonrpc": "2.0",
            "id": 1,
            "method": method,
            "params": params
        });

        let value: Value = self
            .http
            .post(&self.rpc_url)
            .json(&payload)
            .send()
            .await?
            .error_for_status()?
            .json()
            .await?;

        if let Some(error) = value.get("error") {
            return Err(anyhow!("rpc error: {error}"));
        }

        value.get("result")
            .cloned()
            .ok_or_else(|| anyhow!("missing result field"))
    }
}

pub struct BeamClient {
    // Recent blockhashes should be fetched from the standard Solana RPC endpoint.
    solana_rpc: JsonRpcClient,
    // Beam supports only sendTransaction / sendBundle.
    beam_rpc: JsonRpcClient,
    tip_accounts: Vec<Pubkey>,
    next_tip_idx: AtomicUsize,
}

impl BeamClient {
    pub fn new(
        solana_rpc_url: impl Into<String>,
        beam_url: impl Into<String>,
        token: &str,
        tip_accounts: &[&str],
    ) -> Result<Self> {
        if tip_accounts.is_empty() {
            return Err(anyhow!("tip account list must not be empty"));
        }

        let parsed_tip_accounts = tip_accounts
            .iter()
            .map(|s| s.parse::<Pubkey>())
            .collect::<std::result::Result<Vec<_>, _>>()?;

        Ok(Self {
            solana_rpc: JsonRpcClient::new(solana_rpc_url, token)?,
            beam_rpc: JsonRpcClient::new(beam_url, token)?,
            tip_accounts: parsed_tip_accounts,
            next_tip_idx: AtomicUsize::new(0),
        })
    }

    fn next_tip_account(&self) -> Pubkey {
        let idx = self.next_tip_idx.fetch_add(1, Ordering::Relaxed) % self.tip_accounts.len();
        self.tip_accounts[idx]
    }

    fn build_tip_instruction(&self, payer: &Pubkey, tip_lamports: u64) -> Result<Instruction> {
        if tip_lamports == 0 {
            return Err(anyhow!("Beam requires a tip instruction on every transaction"));
        }

        Ok(system_instruction::transfer(
            payer,
            &self.next_tip_account(),
            tip_lamports,
        ))
    }

    async fn get_latest_blockhash(&self) -> Result<Hash> {
        let result = self
            .solana_rpc
            .call("getLatestBlockhash", json!([{ "commitment": "processed" }]))
            .await?;

        let blockhash = result["value"]["blockhash"]
            .as_str()
            .ok_or_else(|| anyhow!("missing blockhash"))?;

        Ok(blockhash.parse()?)
    }

    pub async fn send_transaction(
        &self,
        payer: &Keypair,
        mut instructions: Vec<Instruction>,
        tip_lamports: u64,
    ) -> Result<Signature> {
        let blockhash = self.get_latest_blockhash().await?;
        instructions.push(self.build_tip_instruction(&payer.pubkey(), tip_lamports)?);

        let message = Message::new(&instructions, Some(&payer.pubkey()));
        let tx = Transaction::new(&[payer], message, blockhash);

        let raw_bytes = bincode::serialize(&tx)?;
        let raw_b64 = base64::engine::general_purpose::STANDARD.encode(raw_bytes);

        // Beam supports only sendTransaction / sendBundle.
        // maxRetries and preflight controls are ignored by Beam.
        let result = self
            .beam_rpc
            .call(
                "sendTransaction",
                json!([
                    raw_b64,
                    {
                        "encoding": "base64",
                        "skipPreflight": true,
                        "maxRetries": 0,
                        "preflightCommitment": "processed"
                    }
                ]),
            )
            .await?;

        let sig = result
            .as_str()
            .ok_or_else(|| anyhow!("missing signature"))?;

        Ok(sig.parse()?)
    }
}

#[tokio::main]
async fn main() -> Result<()> {
    let beam = BeamClient::new(
        SOLANA_RPC_URL,
        BEAM_URL,
        RPCFAST_TOKEN,
        &ASTRALANE_TIP_ACCOUNTS,
    )?;

    let payer = Keypair::new();
    let instructions: Vec<Instruction> = vec![];

    let signature = beam
        .send_transaction(&payer, instructions, 1_000_000)
        .await?;

    println!("{signature}");
    Ok(())
}
```

{% endtab %}

{% tab title="TypeScript" %}

```typescript
import {
  Keypair,
  PublicKey,
  SystemProgram,
  Transaction,
  TransactionInstruction,
  Connection,
} from "@solana/web3.js";
import { Agent, fetch } from "undici";

const RPCFAST_TOKEN = process.env.RPCFAST_TOKEN!;
const MODE = "fastest";

const SOLANA_RPC_URL = "https://solana-rpc.rpcfast.com";
const BEAM_URL = `https://beam.rpcfast.com/?mode=${MODE}`;

const TIP_ACCOUNTS = [
    // astralane
    "ASdXviZw2kbViFuAgZF26RPZL1HdybUoWdcveG2nfU8D",
    "Ax2JBnTPUpBFWe75z3YtgueWUfvZPZ6ZFXiMWJMUnjbo",
    // falcon
    "rfCCxFtXuwjjnP9cXAaEgvCzLkrzXwAiWQadJ4uNKmf",
    "rfCTcFU5p63roQ7S8sTwpQ93NHfGxf5ThSsbH1CjQbf",
    // bloxroute
    "rfBP8KJ6KMqvBhmqaV7EoNHVexXQdn1sX4CJ9aLv5w2",
    "rfBkmha9yK5QS7h562Pn6Bfw6cPjsrgVqgcnnXBoXj7",
];

class RotatingTipAccounts {
  private idx = 0;

  constructor(private readonly accounts: string[]) {
    if (accounts.length === 0) {
      throw new Error("tip account list must not be empty");
    }
  }

  next(): PublicKey {
    const pk = new PublicKey(this.accounts[this.idx]);
    this.idx = (this.idx + 1) % this.accounts.length;
    return pk;
  }
}

const tipAccounts = new RotatingTipAccounts(ASTRALANE_TIP_ACCOUNTS);

// Reusable HTTP/2 client with keep-alive.
// Node sockets use TCP_NODELAY by default.
const dispatcher = new Agent({
  allowH2: true,
  connections: 256,
  pipelining: 1,
  keepAliveTimeout: 10_000,
  keepAliveMaxTimeout: 60_000,
});

const customFetch: typeof fetch = (input, init = {}) =>
  fetch(input, {
    ...init,
    dispatcher,
    headers: {
      "Content-Type": "application/json",
      "X-Token": RPCFAST_TOKEN,
      ...(init.headers ?? {}),
    },
  });

// Reuse both clients across the lifetime of the process.
// Recent blockhashes should be fetched from the standard Solana RPC endpoint.
const solanaRpc = new Connection(SOLANA_RPC_URL, {
  commitment: "processed",
  fetch: customFetch as any,
});

// Beam supports only sendTransaction / sendBundle.
const beamRpc = new Connection(BEAM_URL, {
  commitment: "processed",
  fetch: customFetch as any,
});

function buildTipInstruction(
  payer: PublicKey,
  tipLamports: number,
): TransactionInstruction {
  if (tipLamports <= 0) {
    throw new Error("Beam requires a tip instruction on every transaction");
  }

  return SystemProgram.transfer({
    fromPubkey: payer,
    toPubkey: tipAccounts.next(),
    lamports: tipLamports,
  });
}

export async function sendBeamTransaction(
  payer: Keypair,
  appInstructions: TransactionInstruction[],
  tipLamports: number,
): Promise<string> {
  const { blockhash } = await solanaRpc.getLatestBlockhash("processed");

  const tx = new Transaction({
    feePayer: payer.publicKey,
    recentBlockhash: blockhash,
  });

  for (const ix of appInstructions) {
    tx.add(ix);
  }

  tx.add(buildTipInstruction(payer.publicKey, tipLamports));
  tx.sign(payer);

  const raw = tx.serialize();

  // Beam supports only sendTransaction / sendBundle.
  // maxRetries and preflight controls are ignored by Beam and should be handled application-side.
  return beamRpc.sendRawTransaction(raw, {
    skipPreflight: true,
    maxRetries: 0,
    preflightCommitment: "processed",
  });
}
```

{% endtab %}

{% tab title="Python" %}

```python
import base64
import itertools
from typing import Iterable, List, Any

import httpx
from solders.hash import Hash
from solders.instruction import Instruction
from solders.keypair import Keypair
from solders.message import Message
from solders.pubkey import Pubkey
from solders.system_program import TransferParams, transfer
from solders.transaction import Transaction


RPCFAST_TOKEN = "YOUR_RPCFAST_TOKEN"
MODE = "fastest"

SOLANA_RPC_URL = "https://solana-rpc.rpcfast.com"
BEAM_URL = f"https://beam.rpcfast.com/?mode={MODE}"

ASTRALANE_TIP_ACCOUNTS = [
    ## astralane
    "ASdXviZw2kbViFuAgZF26RPZL1HdybUoWdcveG2nfU8D",
    "Ax2JBnTPUpBFWe75z3YtgueWUfvZPZ6ZFXiMWJMUnjbo",
    ## falcon
    "rfCCxFtXuwjjnP9cXAaEgvCzLkrzXwAiWQadJ4uNKmf",
    "rfCTcFU5p63roQ7S8sTwpQ93NHfGxf5ThSsbH1CjQbf",
    ## bloxroute
    "rfBP8KJ6KMqvBhmqaV7EoNHVexXQdn1sX4CJ9aLv5w2",
    "rfBkmha9yK5QS7h562Pn6Bfw6cPjsrgVqgcnnXBoXj7",
];


class JsonRpcClient:
    def __init__(self, rpc_url: str, token: str) -> None:
        self.rpc_url = rpc_url
        self.request_id = 0
        self.http = httpx.Client(
            http2=True,
            limits=httpx.Limits(max_connections=200, max_keepalive_connections=50),
            timeout=httpx.Timeout(5.0),
            headers={
                "Content-Type": "application/json",
                "X-Token": token,
            },
        )

    def call(self, method: str, params: List[Any]) -> Any:
        self.request_id += 1
        payload = {
            "jsonrpc": "2.0",
            "id": self.request_id,
            "method": method,
            "params": params,
        }
        response = self.http.post(self.rpc_url, json=payload)
        response.raise_for_status()
        data = response.json()
        if "error" in data:
            raise RuntimeError(data["error"])
        return data["result"]


class BeamClient:
    def __init__(
        self,
        solana_rpc_url: str,
        beam_url: str,
        token: str,
        tip_accounts: List[str],
    ) -> None:
        if not tip_accounts:
            raise ValueError("tip account list must not be empty")

        # Reuse both clients for the lifetime of the process.
        # Recent blockhashes should come from the standard Solana RPC endpoint.
        self.solana_rpc = JsonRpcClient(solana_rpc_url, token)
        # Beam supports only sendTransaction / sendBundle.
        self.beam_rpc = JsonRpcClient(beam_url, token)
        self.tip_accounts = itertools.cycle(Pubkey.from_string(x) for x in tip_accounts)

    def get_latest_blockhash(self) -> Hash:
        result = self.solana_rpc.call("getLatestBlockhash", [{"commitment": "processed"}])
        return Hash.from_string(result["value"]["blockhash"])

    def next_tip_account(self) -> Pubkey:
        return next(self.tip_accounts)

    def build_tip_instruction(self, payer: Pubkey, tip_lamports: int) -> Instruction:
        if tip_lamports <= 0:
            raise ValueError("Beam requires a tip instruction on every transaction")

        return transfer(
            TransferParams(
                from_pubkey=payer,
                to_pubkey=self.next_tip_account(),
                lamports=tip_lamports,
            )
        )

    def send_transaction(
        self,
        payer: Keypair,
        instructions: Iterable[Instruction],
        tip_lamports: int,
    ) -> str:
        blockhash = self.get_latest_blockhash()

        final_instructions = list(instructions)
        final_instructions.append(self.build_tip_instruction(payer.pubkey(), tip_lamports))

        message = Message(final_instructions, payer.pubkey())
        tx = Transaction([payer], message, blockhash)
        raw_tx_b64 = base64.b64encode(bytes(tx)).decode("ascii")

        # Beam supports only sendTransaction / sendBundle.
        # maxRetries and preflight controls are ignored by Beam.
        return self.beam_rpc.call(
            "sendTransaction",
            [
                raw_tx_b64,
                {
                    "encoding": "base64",
                    "skipPreflight": True,
                    "maxRetries": 0,
                    "preflightCommitment": "processed",
                },
            ],
        )


beam = BeamClient(
    solana_rpc_url=SOLANA_RPC_URL,
    beam_url=BEAM_URL,
    token=RPCFAST_TOKEN,
    tip_accounts=ASTRALANE_TIP_ACCOUNTS,
)

payer = Keypair()

# Example:
# signature = beam.send_transaction(
#     payer=payer,
#     instructions=[...],
#     tip_lamports=1_000_000,
# )
# print(signature)
```

{% endtab %}
{% endtabs %}

***

### Best Practices

For best results with RPC Fast Beam:

* Always include a **valid tip transfer instruction.**
* Use appropriate **tip account** when specifying `provider` query parameter.
* Use only those tip accounts specified in our docs, otherwise request will be rejected.
* **Rotate tip accounts** instead of hardcoding one destination.
* Send transaction to **multiple providers in parallel** for better resilience.
* Use the **WebSocket tip feed** to adapt tip size dynamically.
* Reuse a long-lived RPC client.
* Use HTTP/2 and keep connections warm.
* Handle retries in the application.
* Do not rely on preflight checks on the send path.
* Keep your signing and submission path hot.
* Reuse one long-lived `BeamQuicClient` instead of reconnecting per transaction.
* Use regular QUIC `sendTransaction` when you need Beam response feedback.
* Use `sendTransactionFast` only when your application can handle fire-and-forget submission.
* Pass `signature` to `sendTransactionFast` when you want Beam-side landing metrics.
* Choose `provider` explicitly for `sendTransactionFast`.

{% hint style="success" icon="light-emergency-on" %}
**For latency-sensitive systems,** pair Beam with the [Aperture gRPC (Beta)](/rpc-fast-saas-solana/data-streaming/aperture-grpc-beta.md) to detect opportunities earlier. Teams that prefer lower-level data can also use **Shredstream,** with more client-side decoding work.
{% endhint %}

***

### Quick Reference

#### Endpoint

```
https://beam.rpcfast.com
```

#### QUIC endpoint

```
beam.rpcfast.com:9900
```

#### Supported HTTP JSON-RPC methods

```
sendTransaction
sendBundle
```

#### Supported QUIC methods

```
sendTransaction
sendTransactionFast
```

#### Query arguments

```
provider=astralane | bloxroute | falcon
mode=fastest | mev_protect
```

#### Defaults

```
provider=derived from the tip account used in transaction
mode=fastest
```

#### Tip feed

```
wss://beam.rpcfast.com/tips?provider=<provider>
```

***

### When to Use Beam

Beam is a strong fit for:

* High-frequency trading systems
* MEV searchers
* Liquidation bots
* Arbitrage engines
* Latency-sensitive market makers
* Wallets or apps that need stronger delivery guarantees
* Users who want protection from backrunning and sandwich attacks

For standard, low-priority transaction flows, a regular Solana RPC endpoint may be sufficient.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.rpcfast.com/rpc-fast-saas-solana/sending-transactions/rpc-fast-beam-beta.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
