> For the complete documentation index, see [llms.txt](https://docs.triton.one/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.triton.one/solana/real-time-streaming/preconfirmations-grpc.md).

# Preconfirmations gRPC

Triton Preconfs streams preconfirmed Solana transactions over gRPC from Harmonic and BAM, with x-token auth, Rust quick start and grpcurl steps.

## What a preconfirmation is

On Solana one validator is the [leader](https://docs.anza.xyz/consensus/leader-rotation) for each [slot](https://solana.com/docs/references/terminology#slot) and builds the block for it. A transaction you send travels to that leader; the leader executes it, packs it into entries, splits the entries into shreds and broadcasts them; every other node receives the shreds, replays the block and then reports the transaction, first at `processed` [commitment](https://solana.com/docs/rpc#configuring-state-commitment), later at `confirmed` and `finalized`. Everything you can observe through an RPC node, a WebSocket or a Geyser stream sits at the end of that path.

A preconfirmation is a message emitted at the start of it. The party assembling the block, the builder or the leader itself, tells you the moment a transaction has been executed or committed into the slot under construction, before any shred exists. You learn what the block will contain while it is still being built. The message carries the raw transaction bytes exactly as the block will, plus the slot and, depending on the feed, the execution outcome and the position in the block.

{% hint style="warning" %}
A preconfirmation is a statement by the block producer, not a confirmation by the cluster. The slot can still be skipped, the block can land on a fork that is abandoned, and a leader can restart a slot. A preconfirmed transaction can still fail to land: act on it as an early signal, and treat `confirmed` and `finalized` as settlement.
{% endhint %}

## How each feed produces one

[**Harmonic**](https://docs.harmonic.gg/) runs block builders next to leaders that run the Harmonic validator client. Transactions reach the builder, which executes them and fixes their order for the block. As it does so it streams the executed transactions to subscribers in batches, numbered from zero within each slot and delivered in order, with a start and an end marker per slot. Each transaction carries the outcome the builder observed: success, execution failure (committed, fees charged, state reverted) or fees only (failed to load, the fee is charged). The leader then executes the same transactions again, in parallel; Harmonic states that the resulting state is equivalent to executing them serially in batch order, so the outcome you receive is normally the outcome that lands. A Harmonic preconfirmation therefore means: this transaction was executed with this result and sits in the block being built.

[**BAM**](https://bam.dev/docs/bam/bam-overview/), Jito's Block Assembly Marketplace, sits between transaction senders and leaders that run the BAM validator client. A BAM node schedules the transactions it receives, first in first out with respect to the accounts they lock, and hands them to the leader; the leader executes them and acknowledges each one back to the node, which streams it to subscribers. Each transaction carries the node it came through, its position in the scheduler's sequence (transactions sharing a sequence were bundled together), its position inside that bundle, whether the bundle reverts on error, and the outcome the leader reported to the node: success or execution failure. BAM does not separate a transaction that failed to load from one that failed to execute; both arrive as an execution failure. A node that does not report the outcome leaves it unset. A BAM preconfirmation therefore means: this transaction was committed by the leader into the slot, with the outcome the leader reported.

Triton subscribes to both systems in every region they publish from and delivers the same bytes to you over one endpoint, filtered to the accounts, signers, instructions and signatures you ask for.

## Harmonic and BAM side by side

|                          | Harmonic                                             | BAM                                                                   |
| ------------------------ | ---------------------------------------------------- | --------------------------------------------------------------------- |
| who produces the preconf | the block builder, before the leader executes        | the BAM node, after the leader executes and acknowledges              |
| what it asserts          | executed with this outcome, in the block being built | committed by the leader into the slot                                 |
| execution outcome        | success, execution failure, fees only                | success or execution failure, as the leader reported it; may be unset |
| ordering information     | batch number within the slot                         | scheduler sequence, bundle position, revert on error                  |
| slot framing             | `SlotStart` and `SlotEnd` per slot                   | none, each transaction names its slot                                 |
| regions                  | 7                                                    | 15                                                                    |

## What the feeds cover, and what they do not

The feeds are not a copy of the chain. Three things decide what a stream carries.

**Slots led by a validator running that client.** Harmonic preconfirms the slots of leaders on the Harmonic client; BAM preconfirms the slots of leaders on the BAM client. A slot led by any other validator has no preconfirmation on either feed, from any region. The share of slots each feed covers follows the stake running its client and changes as validators switch. Neither feed sees the other's slots, so subscribing to both is how you cover the most slots.

**Static account keys.** Filters match the accounts written in the transaction message. Accounts a v0 transaction reaches through an address lookup table are not matched; legacy and v1 transactions carry every account inline and are matched in full. A filter can therefore see fewer transactions than expected; see [Address lookup tables](/solana/real-time-streaming/preconfirmations-grpc/filters.md#address-lookup-tables).

**One region, one stream, and the regions near you.** Each regional stream carries the slots of the leaders that region serves, not a copy of the whole feed. A far region's preconfirmations arrive after the people located there have acted on them. See [Choosing regions](/solana/real-time-streaming/preconfirmations-grpc/feeds-and-regions.md#choosing-regions).

## Endpoint

`https://preconfs.rpcpool.com`

The address is anycast: the connection lands on the closest point of presence, one of the servers behind that address; every point of presence serves every region of both feeds. Every request carries an `x-token`, a token of your subscription once preconfs has been enabled on it (see [Access](#access)).

Each subscription may receive up to a share of a feed's traffic in each region. Over it, matching transactions are withheld and the count is announced on the stream; nothing is ever dropped silently. See [Coverage](/solana/real-time-streaming/preconfirmations-grpc/coverage-billing-and-limits.md#coverage).

`GetVersion` tells you which point of presence took your connection; see [Which point of presence answered](/solana/real-time-streaming/preconfirmations-grpc/feeds-and-regions.md#which-point-of-presence-answered).

## Access

{% hint style="info" %}
Preconfs is enabled per subscription, on request. It is not included in any plan by default, and a token that works for other Triton services, such as a mainnet RPC token, is not entitled to it until we enable it for that subscription. [Contact us](https://triton.one/contact) before you set up billing for it: we confirm which feeds you need and which regions suit your servers, and enable the feeds on your subscription.
{% endhint %}

Each feed is enabled and metered separately: a token is entitled to the feeds enabled on its subscription, and a request for one feed does not enable another. Every region of an enabled feed is open to the subscription.

### Token

Every request, `GetVersion` and health checks included, carries an `x-token`: a token of a subscription with at least one preconfs feed enabled. It is the same token you use for other Triton gRPC services on that subscription; there is no separate preconfs token. Send the token's value, not its name.

Enabling a feed on a subscription reaches the servers within a few minutes. Turning a feed off closes the open streams of that subscription's tokens on that feed with `PERMISSION_DENIED`.

### When a token is refused

| status              | message                               | meaning                                                                                                                 |
| ------------------- | ------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `UNAUTHENTICATED`   | `x-token required`                    | the call carried no `x-token`                                                                                           |
| `UNAUTHENTICATED`   | `x-token not entitled to preconfs`    | the token is unknown, or no preconfs feed is enabled on its subscription; returned on every call, `GetVersion` included |
| `UNAUTHENTICATED`   | `x-token not entitled to this feed`   | the subscription has a preconfs feed, but not the one you subscribed to                                                 |
| `PERMISSION_DENIED` | `subscription disabled for this feed` | the feed was turned off on the subscription while the stream was open                                                   |

These are the expected answers for a token without the entitlement, not a connectivity or client problem; the client treats them as fatal and does not retry.

## Client

The Rust client and the protobuf definitions are on [GitHub](https://github.com/rpcpool/preconfs-client) as the `triton-preconfs-client` and `triton-preconfs-proto` crates. The client needs Rust 1.89 or later. Other languages use the proto directly, see [Other languages](/solana/real-time-streaming/preconfirmations-grpc/other-languages.md).

## Quick start

{% stepper %}
{% step %}

### Add the client

{% code title="Cargo.toml" %}

```toml
[dependencies]
triton-preconfs-client = "0.4"
solana-pubkey = "4"
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }
```

{% endcode %}
{% endstep %}

{% step %}

### Subscribe and print what arrives

Subscribe to Harmonic in Amsterdam for transactions touching the SPL token program and print what arrives:

{% code title="src/main.rs" %}

```rust
use solana_pubkey::Pubkey;
use triton_preconfs_client::{Connector, Event, Feed, Filter, Filters, Region, parse};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = Connector::new("https://preconfs.rpcpool.com")
        .x_token(Some(std::env::var("PRECONFS_TOKEN")?))
        .connect()
        .await?;

    let token_program: Pubkey = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA".parse()?;
    let region = Region::parse(Feed::Harmonic, "ams")?;
    let filters = Filters::single(Filter::new().accounts([token_program]));

    let mut stream = client.subscribe_harmonic(region, filters).await?;
    while let Some(event) = stream.next().await {
        match event? {
            Event::Transaction(matched) => {
                let signature = parse::parse_signature(&matched.transaction.transaction)?;
                println!("slot {} {signature}", matched.transaction.slot);
            }
            Event::SlotEnd { slot } => println!("slot {slot} complete"),
            Event::Reconnected { attempts } => println!("reconnected after {attempts} attempts"),
            _ => {}
        }
    }
    Ok(())
}
```

{% endcode %}
{% endstep %}

{% step %}

### Run it

```bash
PRECONFS_TOKEN=<your token> cargo run
```

`Event` is non-exhaustive, so keep the `_` arm. The same shape works for BAM with `Feed::Bam` and `subscribe_bam`.
{% endstep %}
{% endstepper %}

### The example CLI

The repository ships `preconfs-subscribe`, which subscribes and logs every event. From a clone of the repository:

```bash
cargo run -p preconfs-example -- --x-token $TOKEN --region harmonic:ams \
    --account TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA
```

`--region bam:fra`, `--require`, `--exclude`, `--signer`, `--exclude-signer`, `--instruction`, `--data-size`, `--signature`, `--result`, `--dial` and `--no-reconnect` cover the other options; `--help` lists them. The token can also come from the `PRECONFS_TOKEN` environment variable. Every transaction invoking Meteora DBC `create_config`, from any creator:

```bash
cargo run -p preconfs-example -- --x-token $TOKEN --region bam:fra \
    --instruction dbcij3LWUppWqq96dh6gJWwBifmcGfLSB5D4DuSMaqN:0:c9cff3724b6f2fbd
```

### Trying it with grpcurl

Download `preconfs.proto` from the repository, then subscribe:

```bash
curl -sO https://raw.githubusercontent.com/rpcpool/preconfs-client/main/preconfs-proto/proto/preconfs.proto

grpcurl -import-path . -proto preconfs.proto \
  -H "x-token: $TOKEN" \
  -d '{"harmonic_region":"HARMONIC_REGION_FRA","transactions":{"t":{"account_include":["TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"]}}}' \
  preconfs.rpcpool.com:443 preconfs.Harmonic/Subscribe
```

For BAM call `preconfs.BAM/Subscribe` with `"bam_region":"BAM_REGION_FRA"`.

## In this section

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><strong>Feeds and regions</strong></td><td>The Harmonic and BAM regions, and how to choose the ones near your servers.</td><td><a href="/solana/real-time-streaming/preconfirmations-grpc/feeds-and-regions.md">Feeds and regions</a></td></tr><tr><td><strong>Filters</strong></td><td>Select transactions by account, signer, instruction, signature and outcome.</td><td><a href="/solana/real-time-streaming/preconfirmations-grpc/filters.md">Filters</a></td></tr><tr><td><strong>Stream and message format</strong></td><td>Stream events, slot framing and the fields on every transaction.</td><td><a href="/solana/real-time-streaming/preconfirmations-grpc/stream-and-message-format.md">Stream and message format</a></td></tr><tr><td><strong>Coverage, billing and limits</strong></td><td>The per-region coverage share, billing, and limits on filters and streams.</td><td><a href="/solana/real-time-streaming/preconfirmations-grpc/coverage-billing-and-limits.md">Coverage, billing and limits</a></td></tr><tr><td><strong>Errors and reconnection</strong></td><td>Error types, status codes and the client's reconnect behavior.</td><td><a href="/solana/real-time-streaming/preconfirmations-grpc/errors-and-reconnection.md">Errors and reconnection</a></td></tr><tr><td><strong>Other languages</strong></td><td>Use the gRPC API from any language through preconfs.proto.</td><td><a href="/solana/real-time-streaming/preconfirmations-grpc/other-languages.md">Other languages</a></td></tr><tr><td><strong>Preconfirmations FAQ</strong></td><td>Answers to the questions we get most often.</td><td><a href="/solana/real-time-streaming/preconfirmations-grpc/faq.md">Preconfirmations FAQ</a></td></tr></tbody></table>

***

<i class="fa-life-ring">:life-ring:</i> Contact support by clicking the chat icon in your [customer dashboard](https://customers.triton.one)\ <i class="fa-briefcase">:briefcase:</i> Sales questions? [Contact us](https://triton.one/contact)\ <i class="fa-sparkles">:sparkles:</i> AI agent? Read [llms.txt](https://docs.triton.one/llms.txt)\ <i class="fa-rss">:rss:</i> Follow updates: [Blog](https://blog.triton.one) · [X](https://x.com/triton_one) · [YouTube](https://www.youtube.com/@triton_one_ltd) · [Telegram](https://t.me/tritonone) · [GitHub](https://github.com/rpcpool)
