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

# How to Use preconfSubscribe

> Use preconfSubscribe on any paid Helius plan to stream Solana transactions at the lowest possible latency, filter them, and decode the payload.

> [!TIP]
>
> **Use [Sender Max](https://www.helius.dev/docs/sending-transactions/sender-max.md) (min tip: 0.001 SOL) to
> act on Preconfirmations.** A preconfirmation only pays off if you land your
> transaction
> first — Sender Max is the fastest way to do that. Build on Sender Max from the
> start to get the full benefit of Preconfirmations.

## What is `preconfSubscribe`?

`preconfSubscribe` is a Helius WebSocket method that streams [Preconfirmations](https://www.helius.dev/docs/pre-confirmations/overview.md) — transactions delivered before they are collected into entries and shredded. It is the lowest-latency transaction signal Helius offers. One subscription delivers both Helius preconfirmations, emitted the instant the leader executes the transaction and carrying its execution status, and [BAM preconfirmations](https://www.helius.dev/docs/pre-confirmations/overview.md#bam-preconfirmations) from validators running Jito's Block Assembly Marketplace client, emitted when the validator commits to executing the transaction. Access is available on [all paid plans](https://www.helius.dev/docs/billing/plans.md) — see [Pricing](#pricing).

> [!NOTE]
>
> The stream is not continuous. Coverage scales with the share of stake
> forwarding to Helius or running BAM, so expect slots with no messages — handle
> these gaps gracefully. See [Coverage](https://www.helius.dev/docs/pre-confirmations/overview.md#coverage).

`preconfSubscribe` is served from `wss://beta.helius-rpc.com` — the Helius [Gatekeeper](https://www.helius.dev/docs/gatekeeper/overview.md) endpoint — rather than `mainnet.helius-rpc.com`. Authenticate with your API key as a query parameter.

```
wss://beta.helius-rpc.com/?api-key=<API_KEY>
```

> [!NOTE]
>
> The `beta` hostname refers to the [Gatekeeper](https://www.helius.dev/docs/gatekeeper/overview.md) rollout,
> not the maturity of Preconfirmations. Preconfirmations launch on the
> Gatekeeper endpoint first; it will become the standard endpoint as Helius
> migrates traffic to Gatekeeper.

## Subscribe

Send a JSON-RPC request with the `preconfSubscribe` method. The server responds with a subscription ID, then streams a notification for each transaction. Pass an optional [filter](#filtering) as the first `params` element to receive only matching transactions; omit `params` to receive the full stream from both Helius and BAM.

```json theme={"system"}
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "preconfSubscribe"
}
```

### Subscribe Response

```json theme={"system"}
{
  "jsonrpc": "2.0",
  "result": 24040,
  "id": 1
}
```

Store the `result` — it is the subscription ID you use to [unsubscribe](#unsubscribing). After this acknowledgement, notifications stream as binary frames (see below).

## Filtering

By default `preconfSubscribe` streams every transaction from both sources. To narrow the stream, pass a filter object as the first element of `params`. Filtering happens server-side, so you only pay for and receive the transactions you care about.

```json theme={"system"}
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "preconfSubscribe",
  "params": [
    {
      "includeSource": ["helius", "bam"],
      "failed": false,
      "regionInclude": ["ewr", "fra"],
      "accountInclude": ["9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM"],
      "accountExclude": ["TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"],
      "accountRequired": ["11111111111111111111111111111111"],
      "signerExclude": ["8qbHbw2BbbTHBW1sbeqakYXVKRQM8Ne7pLK7m6CVfeR"]
    }
  ]
}
```

Every field is optional — a missing field means "no constraint" for that predicate, so an empty filter (or no `params`) matches every transaction from both sources.

| Field | Type | Semantics |
| - | - | - |
| `includeSource` | `string[]` | Sources to receive: `helius` and `bam`. Omit the field or pass an empty array to receive both sources. Use `["helius"]` or `["bam"]` to receive one source. |
| `failed` | `boolean` | `true` returns only failed (reverted) transactions; `false` returns only successful transactions. Either value excludes Helius transactions with unknown status. Omit the field to receive all statuses. |
| `regionInclude` | `string[]` | If non-empty, the transaction must originate from **one of** these [regions](#location-filtering). |
| `accountInclude` | `string[]` | If non-empty, the transaction must reference **at least one** of these accounts. |
| `accountExclude` | `string[]` | The transaction is dropped if it references **any** of these accounts. Takes precedence over `accountInclude`. |
| `accountRequired` | `string[]` | The transaction must reference **all** of these accounts. |
| `signerInclude` | `string[]` | If non-empty, the transaction must be signed by **at least one** of these accounts. |
| `signerExclude` | `string[]` | The transaction is dropped if it is signed by **any** of these accounts. Takes precedence over `signerInclude`. |
| `signatures` | `string[]` | If non-empty, the transaction's first signature must match **one** of these signatures. |
| `instructions` | `object[]` | If non-empty, at least one top-level instruction must match **one** of these [instruction filters](#instruction-filtering). |

Filter rules:

* All predicates are ANDed together, evaluated in the order `includeSource` → `failed` → `regionInclude` → `signatures` → `accountExclude` → `accountRequired` → `accountInclude` → `signerExclude` → `signerInclude` → `instructions`.
* BAM preconfirmations with unknown status ignore the `failed` filter. Helius preconfirmations with unknown status do not match an explicit `failed` filter.
* `includeSource` must be an array containing only `helius` and `bam`. An invalid value returns JSON-RPC error `-32602` (invalid params).
* Accounts are base58-encoded pubkeys. An invalid value returns JSON-RPC error `-32602` (invalid params).
* Each account or signer list is capped at **10,000** entries. `signatures` is capped at **1,000** entries.

> [!NOTE]
>
> The deprecated `includeBam` filter remains available for backward compatibility.
> `includeBam: false` equals `includeSource: ["helius"]`. `includeBam: true` or
> an omitted field selects both sources. Do not send `includeBam` and
> `includeSource` together.

To receive Helius preconfirmations only:

```json theme={"system"}
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "preconfSubscribe",
  "params": [{ "includeSource": ["helius"] }]
}
```

### Signer and signature filtering

Use `signerInclude` to match transactions signed by a specific account. Use `signerExclude` to remove transactions signed by any listed account. A referenced account does not count as a signer.

Use `signatures` when you already know the transactions you want to track. The filter matches the first transaction signature, which is the signature used by Solana RPC methods. The filter cannot change after you subscribe, so create a new subscription to track new signatures.

```json theme={"system"}
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "preconfSubscribe",
  "params": [
    {
      "signerInclude": ["9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM"],
      "signerExclude": ["8qbHbw2BbbTHBW1sbeqakYXVKRQM8Ne7pLK7m6CVfeR"]
    }
  ]
}
```

### Instruction filtering

Use `instructions` to match top-level instructions by program and instruction data. Each instruction filter supports these fields:

| Field | Type | Semantics |
| - | - | - |
| `programId` | `string` | Required. The program invoked by the instruction. |
| `memcmp` | `object[]` | Optional. Each entry compares decoded `bytes` at an `offset`. All entries must match. |
| `dataSize` | `number` | Optional. The instruction data must have this exact byte length. |

Each `memcmp` entry accepts `base58`, `base64`, or `hex` encoding. The default is `base58`. A transaction matches when one top-level instruction passes every condition in any instruction filter.

The following request matches pump.fun `buy` instructions by their Anchor discriminator:

```json theme={"system"}
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "preconfSubscribe",
  "params": [
    {
      "instructions": [
        {
          "programId": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
          "memcmp": [
            {
              "offset": 0,
              "bytes": "66063d1201daebea",
              "encoding": "hex"
            }
          ]
        }
      ]
    }
  ]
}
```

The filter only checks top-level instructions. It cannot match instructions invoked through cross-program invocation (CPI) because those instructions do not exist before execution.

You can provide up to 16 instruction filters and four `memcmp` entries per instruction filter. Each `memcmp` value must decode to 1–128 bytes. A `memcmp` end offset and `dataSize` must not exceed 4,096 bytes.

### Address lookup table (ALT) resolution

Account filters match more than the transaction's static account keys — Helius resolves v0 [address lookup tables](https://www.helius.dev/docs/glossary.md#address-lookup-table-alt) server-side, so `accountInclude`, `accountExclude`, and `accountRequired` also match accounts a transaction loads through an ALT.

This means you can filter on any account a transaction touches, even when it only appears behind a lookup table — no need to maintain ALT mappings or resolve tables yourself. Just pass the account's pubkey and Helius handles the resolution before the filter is applied.

### Location filtering

Use `regionInclude` to receive only transactions that originate from specific regions. Pass one or more region codes; a transaction passes when its origin region matches any of them.

```json theme={"system"}
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "preconfSubscribe",
  "params": [{ "regionInclude": ["ewr", "fra"] }]
}
```

The origin region depends on the source. For Helius preconfirmations it is the Helius region that ingested the transaction. For BAM preconfirmations it is the regional BAM endpoint that emitted the preconfirmation, not where Helius ingested it. BAM's Singapore and Dallas endpoints map to `sgp` and `dal`.

Valid region codes:

| Code | Location |
| - | - |
| `slc` | Salt Lake City |
| `fra` | Frankfurt |
| `lon` | London |
| `pit` | Pittsburgh |
| `sgp` | Singapore |
| `ewr` | Newark |
| `tyo` | Tokyo |
| `ams` | Amsterdam |
| `dal` | Dallas |
| `dub` | Dublin |
| `mia` | Miami |
| `lax` | Los Angeles |
| `iad` | Ashburn |
| `sea` | Seattle |
| `hkg` | Hong Kong |
| `sqq` | Šiauliai, Lithuania |

> [!NOTE]
>
> When `regionInclude` is set, transactions that don't carry region information are dropped. An unrecognized region code returns JSON-RPC error `-32602` (invalid params).

## Notification payload

Notifications are delivered as **binary** WebSocket frames (not JSON). Helius and BAM preconfirmations share the same layout. Each frame is a packed byte layout carrying a single transaction:

| Bytes | Field | Type | Description |
| - | - | - | - |
| 0 | `version` | `u8` | Payload schema version. Currently `1`. |
| 1–8 | `slot` | `u64` (little-endian) | The slot the transaction belongs to. |
| 9–16 | `tx_index` | `u64` (little-endian) | Index of the transaction within the slot, when available. BAM preconfirmations always report `0`; other sources may also report `0` when no transaction index is available. |
| 17 | `status` | `u8` | Transaction status: `0` = failed, `1` = success, `2` = unknown. |
| 18+ | `transaction` | `bytes` | The transaction in Solana wire format. See [Decoding the transaction](#decoding-the-transaction). |

The payload has no source field. Don't infer a BAM origin from `tx_index = 0`, since other sources may also report `0`.

### Telling the two sources apart

Because there is no source field, you cannot label an arbitrary message as Helius or BAM. The `status` byte gives you a one-way classifier:

* **`status` is `0` or `1`** — the message is a Helius preconfirmation and the transaction has executed. BAM never reports these values.
* **`status` is `2`** — the source is ambiguous: either a BAM preconfirmation, or a Helius preconfirmation whose execution status was unavailable.

No other field discriminates. BAM's sequence ID and bundle position are not carried on this stream, so there is no BAM ordering metadata to key on, and `regionInclude` is a subscription filter rather than a payload field, so it can't be read per message.

If you need every message on a stream to carry the same kind of evidence, set `includeSource: ["helius"]` or `includeSource: ["bam"]`. A Helius-only stream contains preconfirmations emitted at leader execution.

> [!WARNING]
>
> **Always read and check the `version` byte first.** It is currently `1`. If
> Helius needs to update the payload format, the version will increment — branch
> on it so your decoder keeps working across schema changes.

> [!NOTE]
>
> A preconfirmation is an early signal, not a guarantee. The transaction has not
> yet landed onchain and could still be dropped — and a Helius preconfirmation's
> execution status reflects the leader's local result, which is not final until
> the block is confirmed. Confirm landing through standard commitment checks
> before treating it as final.

### Decoding the transaction

The transaction bytes are forwarded exactly as the validator serialized them, in the standard wire encoding for the transaction's version. Legacy and v0 transactions use the signatures-first layout that `bincode` produces. Transaction v1 ([SIMD-0385](https://github.com/solana-foundation/solana-improvement-documents/blob/main/proposals/0385-transaction-v1.md)) uses a message-first layout with signatures at the end, so `bincode` fails on v1 payloads. Use a decoder that handles every version:

* **Rust:** [`agave-transaction-view`](https://docs.rs/agave-transaction-view) parses legacy, v0, and v1 transactions in place, without an intermediate copy. This is the recommended option. [`wincode`](https://docs.rs/wincode), the bincode-compatible serializer used by current Solana SDKs, also decodes v1 into `VersionedTransaction`.
* **JavaScript / TypeScript:** make sure your library version supports transaction v1. Older `VersionedTransaction.deserialize` implementations only handle legacy and v0. Use `@solana/kit` 8.0+ or `@solana/web3.js` v3. See [Transaction v1 support](https://www.helius.dev/docs/rpc/transaction-v1.md).

```rust theme={"system"}
use agave_transaction_view::transaction_view::TransactionView;

// `frame` is the full binary WebSocket message
let tx_bytes = &frame[18..];
let tx = TransactionView::try_new_unsanitized(tx_bytes)?;

println!("version: {:?}", tx.version()); // Legacy, V0, or V1
println!("signature: {}", tx.signatures()[0]);
for ix in tx.instructions_iter() {
    println!("program index {}: {} bytes", ix.program_id_index, ix.data.len());
}
```

## Duplicate notifications

Helius and BAM preconfirmations are deduplicated per source, not across sources. A small share of transactions reach Helius through both, so you can receive the same signature twice, and the two copies may report different slots.

Deduplicate by signature on the client and make transaction-triggered actions idempotent, so a second notification does not fire the same action twice. Confirm execution and landing through standard commitment checks.

## Example

```javascript theme={"system"}
const WebSocket = require('ws');

const ws = new WebSocket('wss://beta.helius-rpc.com/?api-key=<API_KEY>');

ws.on('open', () => {
  ws.send(JSON.stringify({
    jsonrpc: '2.0',
    id: 1,
    method: 'preconfSubscribe' // Helius and BAM preconfirmations by default
    // Optional: txs from EWR/FRA touching a given account; Helius txs must be successful.
    // BAM ignores the status filter; region and account filters still apply.
    // params: [{ failed: false, regionInclude: ['ewr', 'fra'], accountInclude: ['9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM'] }]
    // Optional: Helius preconfirmations only
    // params: [{ includeSource: ['helius'] }]
  }));

  // Keep the connection alive
  setInterval(() => ws.ping(), 30_000);
});

ws.on('message', (data, isBinary) => {
  // The subscribe acknowledgement arrives as a JSON text frame
  if (!isBinary) {
    const msg = JSON.parse(data.toString());
    if (msg.id === 1) console.log('Subscribed, ID:', msg.result);
    return;
  }

  // Notifications arrive as binary frames:
  // version (u8) | slot (u64 LE) | tx_index (u64 LE) | status (u8) | transaction bytes
  const buf = Buffer.from(data);
  const version = buf.readUInt8(0); // currently 1 — branch on this if it changes
  if (version !== 1) return; // unknown schema version; update your decoder
  const slot = buf.readBigUInt64LE(1);
  const txIndex = buf.readBigUInt64LE(9); // always 0 for BAM; may be 0 for other sources
  const status = buf.readUInt8(17); // 0 = failed, 1 = success, 2 = unknown
  const txBytes = buf.subarray(18); // transaction in Solana wire format (legacy, v0, or v1)

  console.log('Preconfirmation:', { version, slot, txIndex, status, bytes: txBytes.length });
  // Decode txBytes with a decoder that supports transaction v1 (see "Decoding the transaction")
});

ws.on('error', console.error);
ws.on('close', () => process.exit(1));
```

## Unsubscribing

To stop receiving notifications, call `preconfUnsubscribe` with the subscription ID returned from `preconfSubscribe`.

```json theme={"system"}
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "preconfUnsubscribe",
  "params": [24040]
}
```

```json theme={"system"}
{
  "jsonrpc": "2.0",
  "result": true,
  "id": 2
}
```

## Pricing

Preconfirmations are available on **all paid plans: Developer, Business, Professional, and Enterprise**. Free plans are not eligible. See [Credits](https://www.helius.dev/docs/billing/credits.md) for details.

Slots with zero delivered messages cost zero credits, even when the slot has preconfirmation [coverage](https://www.helius.dev/docs/pre-confirmations/overview.md#coverage). When a slot delivers at least one message, each open `preconfSubscribe` subscription is billed the greater of 300 credits or 10 credits per delivered message.

Uncovered slots cost zero. See [Pricing](https://www.helius.dev/docs/pre-confirmations/overview.md#pricing) for source and region billing eligibility.

| Messages delivered in a covered slot | Credits billed |
| - | - |
| 0 | 0 |
| 10 | 300 |
| 30 | 300 |
| 100 | 1,000 |

Each concurrent subscription is billed independently when it receives at least one message. Close subscriptions you no longer need with `preconfUnsubscribe`. With `includeSource: ["helius"]`, BAM-only covered slots are excluded from billing. When `regionInclude` is set, covered slots outside the selected regions cost zero for that subscription; matching slots are billed only when the subscription receives at least one message.

Billing is per message, not per unique signature. A transaction delivered by both Helius and BAM counts twice. Set `includeSource: ["helius"]` if you only want Helius preconfirmations.

> [!TIP]
>
> To control costs, consolidate account filters into one subscription where practical, use `regionInclude` to limit billing to the regions you need, set `includeSource: ["helius"]` when you do not need BAM, and monitor credits in the [Helius Dashboard](https://dashboard.helius.dev).

> [!NOTE]
>
> Preconfirmations is a new product and pricing is subject to change.

## Related

> [card] [Preconfirmations Overview](https://www.helius.dev/docs/pre-confirmations/overview.md)
>
> What Preconfirmations are and where they sit in the validator pipeline.

> [card] [transactionSubscribe](https://www.helius.dev/docs/rpc/websocket/transaction-subscribe.md)
>
> Stream confirmed-commitment transactions with rich filtering.

> [card] [preconfSubscribe API reference](https://www.helius.dev/docs/api-reference/pre-confirmations/preconfsubscribe.md)
>
> Request parameters, filter fields, and the binary notification layout.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.