arrow-left

Only this pageAll pages
gitbookPowered by GitBook
1 of 22

Temporal Docs

Nozomi

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Introduction

Land transactions faster and more consistently.

Nozomi is a fully custom proprietary client written by HPC and HFT engineers designed to land transactions as fast as possible.

hashtag
Who Should Use It

  • Sniper Bots — Snipe tokens and mints before the competition.

  • DeFi Apps — Create a better UX so user transactions do not stall or fail.

  • Traders — Land with speed and precision to capture the most opportunities.

  • Liquidators — Be first to a liquidation transaction.

  • Jito Bundle Users — Get through the block engine faster and more efficiently.

  • Algorithmic Traders — Get predictability with your bots in all market conditions.

hashtag
Get Access

Nozomi is available to approved users. Request access →arrow-up-right

Tipping

hashtag
Overview

Every Nozomi transaction must include a tip — a standard Solana system transfer instruction to one of the Nozomi tip addresses. The minimum tip is 0.001 SOL.

You only pay when your transaction lands. The tip is an instruction inside your transaction, so if the transaction fails, the tip is never charged. This means you can intentionally fail a transaction if, for example, you detect that someone else already captured the opportunity you were targeting.

hashtag
How Tips Are Used

Delivery path
What happens

Jito validator

Entire tip is forwarded to Jito

Harmonic bundles

Tip is forwarded to Harmonic

Staked connections

Tip pays for Nozomi's staked connections

hashtag
Tip Priority

Nozomi queues transactions by tip amount — higher tips land faster. When multiple transactions compete for the same slot, the highest tipper wins.

Check the live tip percentile dashboardarrow-up-right to see what others are tipping right now.

hashtag
Compute Unit Price

The tip controls your priority within Nozomi's queue. Once Nozomi delivers your transaction to the Solana scheduler, the compute unit price determines its on-chain ordering.

Set your compute unit price to at least 1,000,000 micro-lamports for competitive performance.

hashtag
Retries

Nozomi automatically retries your transaction until it is either confirmed or the blockhash expires. Higher-tipped transactions are retried more aggressively. You do not need to implement retry logic on your end.

hashtag
Tip Addresses

Send your tip to any one of the addresses below. Rotate to a different random address for each transaction — this avoids write lock contention on a single account and improves landing rates.

#
Address

1

TEMPaMeCRFAS9EKF53Jd6KpHxgL47uWLcpFArU1Fanq

2

noz3jAjPiHuBPqiSPkkugaJDkJscPuRhYnSpbi8UvC4

3

noz3str9KXfpKknefHji8L1mPgimezaiUyCHYMDv1GE

4

hashtag
Private Tip Addresses

For users who need dedicated tip addresses, Nozomi can generate private tip addresses that are exclusive to your project. These addresses are not shared with other users and provide additional isolation for your transactions.

Private tip addresses can be created from the Nozomi dashboard under the Tip Accounts page.

hashtag
Front-Running Protection

Nozomi offers a Front Running Protection mode that routes your transaction exclusively through a whitelist of trusted validators (Helius, Coinbase, etc.), preventing it from being seen by adversarial validators.

For additional protection on swaps:

  • Set a strict slippage tolerance.

  • Calculate and enforce minAmountOut in your transaction instructions.

noz6uoYCDijhu1V7cutCpwxNiSovEwLdRHPwmgCGDNo

5

noz9EPNcT7WH6Sou3sr3GGjHQYVkN3DNirpbvDkv9YJ

6

nozc5yT15LazbLTFVZzoNZCwjh3yUtW86LoUyqsBu4L

7

nozFrhfnNGoyqwVuwPAW4aaGqempx4PU6g6D9CJMv7Z

8

nozievPk7HyK1Rqy1MPJwVQ7qQg2QoJGyP71oeDwbsu

9

noznbgwYnBLDHu8wcQVCEw6kDrXkPdKkydGJGNXGvL7

10

nozNVWs5N8mgzuD3qigrCG2UoKxZttxzZ85pvAQVrbP

11

nozpEGbwx4BcGp6pvEdAh1JoC2CQGZdU6HbNP1v2p6P

12

nozrhjhkCr3zXT3BiT4WCodYCUFeQvcdUkM7MqhKqge

13

nozrwQtWhEdrA6W8dkbt9gnUaMs52PdAv5byipnadq3

14

nozUacTVWub3cL4mJmGCYjKZTnE9RbdY5AP46iQgbPJ

15

nozWCyTPppJjRuw2fpzDhhWbW355fzosWSzrrMYB1Qk

16

nozWNju6dY353eMkMqURqwQEoM3SFgEKC6psLCSfUne

17

nozxNBgWohjR75vdspfxR5H9ceC7XXH99xpxhVGt3Bb

cURL

Please specify base64 encoding, Solana recognizes base58 as default. If you do not specify, you might get malformed transaction error

curl https://nozomi.temporal.xyz/?c=<YOUR_API_KEY> \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "sendTransaction",
    "params": [
      "<YOUR_BASE_64_ENCODED_TXN_BYTES>",
      {
        "encoding": "base64"
      }
    ]
  }'

cURL

curl -X POST \
  "https://nozomi.temporal.xyz/api/sendBatch?c=YOUR_API_KEY" \
  -H "Content-Type: application/octet-stream" \
  --data-binary @batch.bin

JSON-RPC

Standard Solana JSON-RPC transaction submission through Nozomi.

The standard way to send transactions through Nozomi. Compatible with any Solana client — just replace your RPC URL with the Nozomi endpoint.

hashtag
Request

Field
Value

Important: Solana defaults to base58 encoding. You must explicitly set "encoding": "base64" or you will get malformed transaction errors.

hashtag
Request Body

hashtag
Response

Returns the transaction signature as a JSON-RPC result on success.

hashtag
When to Use

Use JSON-RPC when you want a drop-in replacement for your existing Solana RPC. It returns a transaction signature and works with standard Solana client libraries.

For lower latency in browser clients or performance-sensitive backends, consider instead.

Tip Stream

Stream Nozomi Tip Floors by Percentile

hashtag
REST Endpoint

curl https://api.nozomi.temporal.xyz/tip_floor

hashtag
WebSocket

wscat -c wss://api.nozomi.temporal.xyz/tip_stream

hashtag
Schema

TCP Keep-Alive

hashtag
How Do I Keep the Connection Alive?

To keep your TCP connection to our server alive and avoid reconnecting, periodically send a request to the /ping endpoint.


hashtag
Strategy

The server supports persistent connections with a keep-alive timeout of 65 seconds. This means:

  • If your connection is idle for more than 65 seconds, it will be closed.

  • To keep it open, send any request before that timeout expires.

  • Each connection can send a maximum of 1000 requests.

We recommend using the /ping endpoint:

GET /ping

This endpoint is lightweight, fast, and designed specifically to maintain your connection.


hashtag
Suggested Interval

Send a request to /ping every 60 seconds to keep the connection alive reliably.


hashtag
Notes

  • This is not a health check — it's just a way to prevent idle disconnects.

  • Avoid pinging more often than needed.

Python

Use full service RPC for fetching latest blockhash.. Nozomi only supports sendTransaction.

JavaScript

Use full service RPC for fetching latest blockhash. Nozomi only supports sendTransaction.

TypeScript

Use full service RPC for fetching latest blockhash. Nozomi only supports sendTransaction.

Rust

Use full service RPC for fetching latest blockhash.

Python

Use full service RPC for fetching latest blockhash.

JavaScript

Use full service RPC for fetching latest blockhash.

TypeScript

Use full service RPC for fetching latest blockhash.

Method

POST

Path

/?c=<YOUR_API_KEY>

Content-Type

application/json

Encoding

base64 (must be specified)

API v2
[
  {
    "time": "string (ISO 8601 timestamp)",
    "landed_tips_25th_percentile": "number",
    "landed_tips_50th_percentile": "number",
    "landed_tips_75th_percentile": "number",
    "landed_tips_95th_percentile": "number",
    "landed_tips_99th_percentile": "number"
  }
]
import asyncio

from typing import List

from solders.pubkey import Pubkey
from solders.keypair import Keypair
from solders.signature import Signature
from solders.instruction import Instruction
from solana.transaction import Transaction
from solders.system_program import transfer, TransferParams

from solana.rpc.async_api import AsyncClient

NOZOMI_ENDPOINT = "https://nozomi.temporal.xyz/?c=<YOUR_API_KEY>"
NOZOMI_TIP = Pubkey.from_string("TEMPaMeCRFAS9EKF53Jd6KpHxgL47uWLcpFArU1Fanq")
MIN_TIP_AMOUNT = 1_000_000

SOLANA_RPC_ENDPOINT = "https://api.mainnet-beta.solana.com"

async def send_nozomi_txn(ixns: List[Instruction], signer: Keypair, nozomi_rpc_client: AsyncClient, solana_rpc_client: AsyncClient) -> Signature:
    tip_ixn = transfer(TransferParams(
        from_pubkey=signer.pubkey(),
        to_pubkey=NOZOMI_TIP,
        lamports=MIN_TIP_AMOUNT
    ))
    ixns.append(tip_ixn)

    blockhash = (await solana_rpc_client.get_latest_blockhash()).value.blockhash
    txn = Transaction()

    for ixn in ixns:
        txn.add(ixn)

    # solanapy does not expose an encoding option via TxOpts
    return (await nozomi_rpc_client.send_transaction(txn, signer, recent_blockhash=blockhash)).value

def build_ixns() -> List[Instruction]:
    # your instruction building logic here..
    return []

async def main():
    nozomi_rpc_client = AsyncClient(NOZOMI_ENDPOINT)

    solana_rpc_client = AsyncClient(SOLANA_RPC_ENDPOINT)

    # replace with actual keypair loading logic
    signer = Keypair()

    ixns = build_ixns()

    signature = await send_nozomi_txn(ixns, signer, nozomi_rpc_client, solana_rpc_client)

    print(f"Transaction sent with signature: {signature}")

if __name__ == "__main__":
    asyncio.run(main())
import { Connection, PublicKey, Keypair, SystemProgram, TransactionMessage, VersionedTransaction } from "@solana/web3.js";

const NOZOMI_ENDPOINT = "https://nozomi.temporal.xyz/?c=<YOUR_API_KEY>";
const NOZOMI_TIP = new PublicKey("TEMPaMeCRFAS9EKF53Jd6KpHxgL47uWLcpFArU1Fanq");
const MIN_TIP_AMOUNT = 1_000_000;

const SOLANA_RPC_ENDPOINT = "https://api.mainnet-beta.solana.com";

async function sendNozomiTxn(ixns, signer, nozomiRpcClient, solanaRpcClient) {
    const tipIxn = SystemProgram.transfer({
        fromPubkey: signer.publicKey,
        toPubkey: NOZOMI_TIP,
        lamports: MIN_TIP_AMOUNT
    });
    ixns.push(tipIxn);

    const { blockhash } = await solanaRpcClient.getLatestBlockhash();

    const messageV0 = new TransactionMessage({
        payerKey: signer.publicKey,
        recentBlockhash: blockhash,
        instructions: ixns,
    }).compileToV0Message();

    const versionedTxn = new VersionedTransaction(messageV0);

    versionedTxn.sign([signer]);

    return await nozomiRpcClient.sendTransaction(versionedTxn);
}

function buildIxns() {
    // your instruction building logic here..
    return [];
}

async function main() {
    const nozomiRpcClient = new Connection(NOZOMI_ENDPOINT);

    const solanaRpcClient = new Connection(SOLANA_RPC_ENDPOINT);

    // replace with actual keypair loading logic
    const signer = Keypair.generate();

    const ixns = buildIxns();

    const signature = await sendNozomiTxn(ixns, signer, nozomiRpcClient, solanaRpcClient);

    console.log(`Transaction sent with signature: ${signature}`);
}

main().catch(err => {
    console.error(err);
});
import { Connection, PublicKey, Keypair, TransactionInstruction, SystemProgram, TransactionMessage, VersionedTransaction, TransactionSignature } from "@solana/web3.js";

const NOZOMI_ENDPOINT = "https://nozomi.temporal.xyz/?c=<YOUR_API_KEY>";
const NOZOMI_TIP = new PublicKey("TEMPaMeCRFAS9EKF53Jd6KpHxgL47uWLcpFArU1Fanq");
const MIN_TIP_AMOUNT = 1_000_000;

const SOLANA_RPC_ENDPOINT = "https://api.mainnet-beta.solana.com";

async function sendNozomiTxn(ixns: TransactionInstruction[], signer: Keypair, nozomiRpcClient: Connection, solanaRpcClient: Connection): Promise<TransactionSignature> {
    const tipIxn = SystemProgram.transfer({
        fromPubkey: signer.publicKey,
        toPubkey: NOZOMI_TIP,
        lamports: MIN_TIP_AMOUNT
    });
    ixns.push(tipIxn);

    const { blockhash } = await solanaRpcClient.getLatestBlockhash();

    const messageV0 = new TransactionMessage({
        payerKey: signer.publicKey,
        recentBlockhash: blockhash,
        instructions: ixns,
    }).compileToV0Message();

    const versionedTxn = new VersionedTransaction(messageV0);

    versionedTxn.sign([signer]);

    return await nozomiRpcClient.sendTransaction(versionedTxn);
}

function buildIxns(): TransactionInstruction[] {
    // your instruction building logic here..
    return [];
}

async function main() {
    const nozomiRpcClient = new Connection(NOZOMI_ENDPOINT);

    const solanaRpcClient = new Connection(SOLANA_RPC_ENDPOINT);

    // replace with actual keypair loading logic
    const signer = Keypair.generate();

    const ixns = buildIxns();

    const signature = await sendNozomiTxn(ixns, signer, nozomiRpcClient, solanaRpcClient);

    console.log(`Transaction sent with signature: ${signature}`);
}

main().catch(err => {
    console.error(err);
});

use solana_client::rpc_client::RpcClient;
use solana_sdk::{message::Instruction, pubkey, pubkey::Pubkey, signature::Keypair, signer::Signer, transaction::Transaction};
use base64::{Engine as _, engine::general_purpose};

const NOZOMI_ENDPOINT: &str = "https://nozomi.temporal.xyz/api/sendTransaction2?c=<YOUR_API_KEY>";
const NOZOMI_TIP: Pubkey = pubkey!("TEMPaMeCRFAS9EKF53Jd6KpHxgL47uWLcpFArU1Fanq");
const MIN_TIP_AMOUNT: u64 = 1_000_000;

const SOLANA_RPC_ENDPOINT: &str = "https://api.mainnet-beta.solana.com";

fn send_nozomi_txn(
    ixns: &mut Vec<Instruction>,
    signer: &Keypair,
    nozomi_endpoint: &str,
    solana_rpc_client: &RpcClient
) -> Result<(), Box<dyn std::error::Error>> {
    let tip_ixn = solana_system_interface::instruction::transfer(
        &signer.pubkey(),
        &NOZOMI_TIP,
        MIN_TIP_AMOUNT
    );
    ixns.push(tip_ixn);

    let blockhash = solana_rpc_client.get_latest_blockhash()?;
    let txn = Transaction::new_signed_with_payer(
        ixns,
        Some(&signer.pubkey()),
        &[signer],
        blockhash
    );

    let txn_bytes = bincode::serialize(&txn)?;

    let txn_base64 = general_purpose::STANDARD.encode(&txn_bytes);

    let client = reqwest::blocking::Client::new();
    let response = client
        .post(nozomi_endpoint)
        .header("Content-Type", "text/plain")
        .body(txn_base64)
        .send()?;

    // api v2 does not return a signature, just check for success
    if response.status().is_success() {
        Ok(())
    } else {
        Err(Box::new(response.error_for_status().unwrap_err()))
    }
}

fn build_ixns() -> Vec<Instruction> {
    // your instruction building logic here..
    vec![]
}

fn main() {
    let solana_rpc_client = RpcClient::new(SOLANA_RPC_ENDPOINT.to_string());

    // replace with actual keypair loading logic
    let signer = Keypair::new();

    let mut ixns = build_ixns();

    if send_nozomi_txn(
        &mut ixns,
        &signer,
        NOZOMI_ENDPOINT,
        &solana_rpc_client
    ).is_ok() {
        println!("Transaction sent successfully");
    }
}
import aiohttp
import asyncio
import base64

from typing import List

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

from solana.rpc.async_api import AsyncClient

NOZOMI_ENDPOINT = "https://nozomi.temporal.xyz/api/sendTransaction2?c=<YOUR_API_KEY>"
NOZOMI_TIP = Pubkey.from_string("TEMPaMeCRFAS9EKF53Jd6KpHxgL47uWLcpFArU1Fanq")
MIN_TIP_AMOUNT = 1_000_000

SOLANA_RPC_ENDPOINT = "https://api.mainnet-beta.solana.com"

async def send_nozomi_txn(
    ixns: List[Instruction],
    signer: Keypair,
    nozomi_endpoint: str,
    solana_rpc_client: AsyncClient
) -> None:
    tip_ixn = transfer(TransferParams(
        from_pubkey=signer.pubkey(),
        to_pubkey=NOZOMI_TIP,
        lamports=MIN_TIP_AMOUNT
    ))
    ixns.append(tip_ixn)

    blockhash_resp = await solana_rpc_client.get_latest_blockhash()
    blockhash = blockhash_resp.value.blockhash

    txn = Transaction.new_signed_with_payer(
        ixns,
        signer.pubkey(),
        [signer],
        blockhash
    )

    txn_bytes = bytes(txn)
    txn_base64 = base64.b64encode(txn_bytes).decode('utf-8')

    async with aiohttp.ClientSession() as session:
        async with session.post(
            nozomi_endpoint,
            headers={"Content-Type": "text/plain"},
            data=txn_base64
        ) as response:
            # api v2 does not return a signature, just check for success
            if response.status >= 200 and response.status < 300:
                print("Transaction sent successfully")
            else:
                error_text = await response.text()
                raise Exception(f"Transaction failed with status {response.status}: {error_text}")

def build_ixns() -> List[Instruction]:
    # your instruction building logic here..
    return []

async def main():
    solana_rpc_client = AsyncClient(SOLANA_RPC_ENDPOINT)

    # replace with actual keypair loading logic
    signer = Keypair()

    ixns = build_ixns()

    await send_nozomi_txn(ixns, signer, NOZOMI_ENDPOINT, solana_rpc_client)

if __name__ == "__main__":
    asyncio.run(main())
import { Connection, PublicKey, Keypair, SystemProgram, TransactionMessage, VersionedTransaction } from "@solana/web3.js";

const NOZOMI_ENDPOINT = "https://nozomi.temporal.xyz/api/sendTransaction2?c=<YOUR_API_KEY>";
const NOZOMI_TIP = new PublicKey("TEMPaMeCRFAS9EKF53Jd6KpHxgL47uWLcpFArU1Fanq");
const MIN_TIP_AMOUNT = 1_000_000;

const SOLANA_RPC_ENDPOINT = "https://api.mainnet-beta.solana.com";

async function sendNozomiTxn(ixns, signer, nozomiEndpoint, solanaRpcClient) {
    const tipIxn = SystemProgram.transfer({
        fromPubkey: signer.publicKey,
        toPubkey: NOZOMI_TIP,
        lamports: MIN_TIP_AMOUNT
    });
    ixns.push(tipIxn);

    const { blockhash } = await solanaRpcClient.getLatestBlockhash();

    const messageV0 = new TransactionMessage({
        payerKey: signer.publicKey,
        recentBlockhash: blockhash,
        instructions: ixns,
    }).compileToV0Message();

    const versionedTxn = new VersionedTransaction(messageV0);
    versionedTxn.sign([signer]);

    const txnBytes = versionedTxn.serialize();
    const txnBase64 = Buffer.from(txnBytes).toString('base64');

    const response = await fetch(nozomiEndpoint, {
        method: 'POST',
        headers: {
            'Content-Type': 'text/plain',
        },
        body: txnBase64
    });

    if (!response.ok) {
        const errorText = await response.text();
        throw new Error(`Transaction failed with status ${response.status}: ${errorText}`);
    }

    // api v2 does not return a signature, just check for success
    console.log('Transaction sent successfully');
}

function buildIxns() {
    // your instruction building logic here..
    return [];
}

async function main() {
    const solanaRpcClient = new Connection(SOLANA_RPC_ENDPOINT);

    // replace with actual keypair loading logic
    const signer = Keypair.generate();

    const ixns = buildIxns();

    await sendNozomiTxn(ixns, signer, NOZOMI_ENDPOINT, solanaRpcClient);
}

main().catch(err => {
    console.error(err);
});
import { Connection, PublicKey, Keypair, TransactionInstruction, SystemProgram, TransactionMessage, VersionedTransaction } from "@solana/web3.js";

const NOZOMI_ENDPOINT = "https://nozomi.temporal.xyz/api/sendTransaction2?c=<YOUR_API_KEY>";
const NOZOMI_TIP = new PublicKey("TEMPaMeCRFAS9EKF53Jd6KpHxgL47uWLcpFArU1Fanq");
const MIN_TIP_AMOUNT = 1_000_000;

const SOLANA_RPC_ENDPOINT = "https://api.mainnet-beta.solana.com";

async function sendNozomiTxn(
    ixns: TransactionInstruction[],
    signer: Keypair,
    nozomiEndpoint: string,
    solanaRpcClient: Connection
): Promise<void> {
    const tipIxn = SystemProgram.transfer({
        fromPubkey: signer.publicKey,
        toPubkey: NOZOMI_TIP,
        lamports: MIN_TIP_AMOUNT
    });
    ixns.push(tipIxn);

    const { blockhash } = await solanaRpcClient.getLatestBlockhash();

    const messageV0 = new TransactionMessage({
        payerKey: signer.publicKey,
        recentBlockhash: blockhash,
        instructions: ixns,
    }).compileToV0Message();

    const versionedTxn = new VersionedTransaction(messageV0);
    versionedTxn.sign([signer]);

    const txnBytes = versionedTxn.serialize();
    const txnBase64 = Buffer.from(txnBytes).toString('base64');

    const response = await fetch(nozomiEndpoint, {
        method: 'POST',
        headers: {
            'Content-Type': 'text/plain',
        },
        body: txnBase64
    });

    if (!response.ok) {
        const errorText = await response.text();
        throw new Error(`Transaction failed with status ${response.status}: ${errorText}`);
    }

    // api v2 does not return a signature, just check for success
    console.log('Transaction sent successfully');
}

function buildIxns(): TransactionInstruction[] {
    // your instruction building logic here..
    return [];
}

async function main() {
    const solanaRpcClient = new Connection(SOLANA_RPC_ENDPOINT);

    // replace with actual keypair loading logic
    const signer = Keypair.generate();

    const ixns = buildIxns();

    await sendNozomiTxn(ixns, signer, NOZOMI_ENDPOINT, solanaRpcClient);
}

main().catch(err => {
    console.error(err);
});
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "sendTransaction",
    "params": [
        "<YOUR_BASE_64_ENCODED_TXN_BYTES>",
        { "encoding": "base64" }
    ]
}
{
    "jsonrpc": "2.0",
    "id": 1,
    "result": "<TRANSACTION_SIGNATURE>"
}
while true; do
  curl -s https://nozomi.temporal.xyz/ping > /dev/null
  sleep 60
done

cURL

curl https://nozomi.temporal.xyz/api/sendTransaction2?c=<YOUR_API_KEY> \
  -X POST \
  -H "Content-Type: text/plain" \
  -d '<YOUR_BASE_64_ENCODED_TXN_BYTES>'

API v2

High-performance transaction submission with reduced overhead.

A faster alternative to JSON-RPC that eliminates JSON parsing overhead and CORS preflight latency. Recommended for browser clients and performance-sensitive backends.

hashtag
Request

Field
Value

Rust

Use full service RPC for fetching latest blockhash. Nozomi only supports sendTransaction.

use solana_client::rpc_client::RpcClient;
use solana_sdk::{message::Instruction, pubkey, pubkey::Pubkey, signature::Keypair, signer::Signer, transaction::Transaction};

const NOZOMI_ENDPOINT: &str = "https://nozomi.temporal.xyz/?c=<YOUR_API_KEY>";
const NOZOMI_TIP: Pubkey = pubkey!("TEMPaMeCRFAS9EKF53Jd6KpHxgL47uWLcpFArU1Fanq");
const MIN_TIP_AMOUNT: u64 = 1_000_000;

const SOLANA_RPC_ENDPOINT: &str = "https://api.mainnet-beta.solana.com";

fn send_nozomi_txn(ixns: &mut Vec<Instruction>, signer: &Keypair, nozomi_rpc_client: &RpcClient, solana_rpc_client: &RpcClient) {
    let tip_ix = solana_system_interface::instruction::transfer(&signer.pubkey(), &NOZOMI_TIP, MIN_TIP_AMOUNT);
    ixns.push(tip_ix);

    let blockhash = solana_rpc_client.get_latest_blockhash().unwrap();
    let tx = Transaction::new_signed_with_payer(ixns, Some(&signer.pubkey()), &[signer], blockhash);

    nozomi_rpc_client.send_transaction(&tx).unwrap();
}

fn build_ixns() -> Vec<Instruction> {
    // your instruction building logic here..
    vec![]
}

fn main() {
    let nozomi_rpc_client = RpcClient::new(NOZOMI_ENDPOINT.to_string());

    let solana_rpc_client = RpcClient::new(SOLANA_RPC_ENDPOINT.to_string());

    let keypair = Keypair::new();

    let mut ixns = build_ixns();

    send_nozomi_txn(&mut ixns, &keypair, &nozomi_rpc_client, &solana_rpc_client);
}

Method

POST

Path

/api/sendTransaction2?c=<YOUR_API_KEY>

Content-Type

text/plain

Body

Base64-encoded transaction bytes

hashtag
Response

Returns an empty body with 200 OK on success. Does not return a transaction signature — track signatures client-side before submitting.

hashtag
Why Use API v2

Advantage
Detail

No CORS preflight

Saves 50–100ms per request from browser clients

Faster encoding

Base64 is faster to encode/decode than base58

Smaller payload

No JSON wrapper, plain text body

hashtag
When to Use

Use API v2 when you don't need the transaction signature returned in the response, and want the lowest possible submission latency. Ideal for browser-based applications and high-frequency backends.

If you need a transaction signature in the response, use JSON-RPC instead.

Regions & Endpoints

Regional endpoint URLs for all Nozomi APIs.

hashtag
Authentication

All requests require your API key passed as a query parameter:

Don't have an API key yet?

hashtag

Lower overhead

No JSON parsing on the server side

API Paths
Method
Path
Response

JSON-RPC

/

Transaction signature

API v2

/api/sendTransaction2

Empty body, 200 OK

hashtag
Base URLs

Type
URL
Notes

Auto-routed

nozomi.temporal.xyz

Via Cloudflare proxy

Geo-DNS

edge.nozomi.temporal.xyz

Routes to nearest region

Auto-routed is recommended for most users. It will always route your request to the closest regional server.

Example: https://nozomi.temporal.xyz/api/sendTransaction2?c=<YOUR_API_KEY>

hashtag
Regional Endpoints

Pin to a specific datacenter for lowest latency if you are co-located. Each region is available as a direct connection or through Cloudflare.

Direct endpoints support both http:// and https://. Cloudflare endpoints support https:// only.

Region
Direct
Cloudflare

Pittsburgh

pit1.nozomi.temporal.xyz

pit.nozomi.temporal.xyz

Newark

ewr1.nozomi.temporal.xyz

ewr.nozomi.temporal.xyz

All servers run custom hardware modifications.

hashtag
Direct vs Cloudflare

Direct endpoints connect straight to the Nozomi server with no intermediary. This gives the lowest possible latency for servers and co-located infrastructure.

Cloudflare endpoints route through Cloudflare's network before reaching Nozomi. Residential ISPs often have better backbone connectivity to Cloudflare's edge than to individual datacenters, which can make proxied endpoints faster for users on home or mobile connections. Cloudflare also handles TLS termination at the edge, reducing handshake latency.

Use direct if you are running from a datacenter or VPS with good peering. Use Cloudflare if you are on a residential connection, have variable network quality, or are building a browser-based application.

hashtag
Best Practices

hashtag
Send to multiple regions

For the highest landing probability, send the same transaction to multiple regional endpoints simultaneously. Rate limits are applied per region, so sending the same transaction to multiple regions will not count against your rate limit.

hashtag
Frontend clients

If you are integrating Nozomi into a browser-based application:

  • Send each transaction to both a direct and a Cloudflare endpoint at the same time. Network conditions vary across users — some will be faster through Cloudflare, others through a direct connection. Sending to both ensures the fastest path wins.

  • Use API v2 or Batch Send with Content-Type: text/plain or application/octet-stream to skip the CORS preflight OPTIONS request. Standard JSON-RPC with Content-Type: application/json triggers a preflight that adds 50–100ms of latency.

?c=<YOUR_API_KEY>
Request access to Nozomi →arrow-up-right

JavaScript

FAQ

hashtag
How do I get access?

Nozomi is available to approved users.

hashtag
Rate Limits

Batch Send

/api/sendBatch

Empty body, 200 OK

Ashburn

ash1.nozomi.temporal.xyz

ash.nozomi.temporal.xyz

Los Angeles

lax1.nozomi.temporal.xyz

lax.nozomi.temporal.xyz

Frankfurt

fra2.nozomi.temporal.xyz

fra.nozomi.temporal.xyz

Amsterdam

ams1.nozomi.temporal.xyz

ams.nozomi.temporal.xyz

London

lon1.nozomi.temporal.xyz

lon.nozomi.temporal.xyz

Tokyo

tyo1.nozomi.temporal.xyz

tyo.nozomi.temporal.xyz

Singapore

sgp1.nozomi.temporal.xyz

sgp.nozomi.temporal.xyz

Each API key has an associated rate limit. Rate limits are applied per region — sending the same transaction to multiple regions does not count against your limit.

hashtag
QoS Priority

If your transactions have a high failure rate, Nozomi applies a QoS penalty to your priority. For example, if only 10% of your transactions land successfully over the last 30 minutes, your effective priority is discounted to 10%.

To maintain high QoS priority:

  • Check account state before submitting to avoid predictable failures.

  • Avoid sending transactions that will fail due to stale blockhashes.

  • Monitor your landing rate and reduce volume if it drops.

hashtag
Custom Limits

High-volume users can request custom rate limits and priority configurations. Reach out via Discord.

hashtag
Does Nozomi Simulate Transactions?

No. Nozomi does not simulate transactions. It routes directly to the TPU for the fastest possible delivery.

Request access via this form →arrow-up-right
function encodeBatch(rawTxs) {
  if (rawTxs.length === 0 || rawTxs.length > 16) {
    throw new Error("batch must contain 1-16 transactions");
  }

  let total = 0;
  for (const tx of rawTxs) {
    if (tx.length < 66 || tx.length > 1232) {
      throw new Error(`invalid tx size: ${tx.length}`);
    }
    total += 2 + tx.length;
  }

  const out = Buffer.allocUnsafe(total);
  let off = 0;
  for (const tx of rawTxs) {
    out.writeUInt16BE(tx.length, off);
    off += 2;
    Buffer.from(tx).copy(out, off);
    off += tx.length;
  }
  return out;
}

async function sendBatch(endpoint, apiKey, rawTxs) {
  const body = encodeBatch(rawTxs);
  const res = await fetch(
    `${endpoint}/api/sendBatch?c=${apiKey}`,
    {
      method: "POST",
      headers: { "Content-Type": "application/octet-stream" },
      body,
    }
  );

  if (!res.ok) {
    const text = await res.text();
    throw new Error(`sendBatch failed (${res.status}): ${text}`);
  }
}

Batch Send

Submit multiple raw Solana transactions in a single request using a compact binary format. Reduces per-request overhead when you have multiple transactions ready to send.

hashtag
Request

Field
Value

hashtag
Limits

Constraint
Value

hashtag
Wire Format

The body is a concatenation of length-prefixed transactions. No JSON, no separators.

Each length prefix is a big-endian u16 indicating the size of the following transaction bytes.

hashtag
Response

Returns an empty body with 200 OK when all transactions are accepted.

Status
Meaning

All error responses are plain text with a descriptive message.

hashtag
Partial Success

sendBatch is stream-processed — transactions are forwarded as they are parsed. If transaction N fails, transactions 1 through N-1 may already be accepted. There is no rollback.

Always track transaction signatures client-side before submitting so you can reconcile partial success.

hashtag
When to Use

Use Batch Send when you have multiple transactions ready to submit and want to minimize HTTP round trips. Keep batch sizes small (2–8) to simplify retry logic around partial failures.

For single transactions, use or instead.

19,744 bytes

Rate limited

500

Internal error

Method

POST

Path

/api/sendBatch?c=<YOUR_API_KEY>

Content-Type

application/octet-stream

Body

Binary-encoded transaction batch

Max transactions per batch

16

Min transaction size

66 bytes

Max transaction size

1,232 bytes

200

All accepted

400

Framing error, size violation, parse failure, or insufficient tip

401

Invalid or missing API key

429

JSON-RPC
API v2

Max body size

[len_hi][len_lo][tx_bytes...][len_hi][len_lo][tx_bytes...]...