Only this pageAll pages
Powered 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.

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.

Nozomi is available to approved users.

Regions & Endpoints

Regional endpoint URLs for all Nozomi APIs.

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

Don't have an API key yet?

Method
Path
Response

Get Access

Request access →

API v2

/api/sendTransaction2

Empty body, 200 OK

Batch Send

/api/sendBatch

Empty body, 200 OK

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>

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.

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.

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.

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>

JSON-RPC

/

Authentication

API Paths

Request access to Nozomi →

Transaction signature

Base URLs

Regional Endpoints

Direct vs Cloudflare

Best Practices

Send to multiple regions

Frontend clients

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

FAQ

How do I get access?

Nozomi is available to approved users. Request access via this form →

Rate Limits

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.

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.

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

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

TCP Keep-Alive

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


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.

Custom Limits

Does Nozomi Simulate Transactions?

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>'
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.


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


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

    • Avoid pinging more often than needed.

    How Do I Keep the Connection Alive?

    Strategy

    Suggested Interval

    Notes

    while true; do
      curl -s https://nozomi.temporal.xyz/ping > /dev/null
      sleep 60
    done

    Rust

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

    Python

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

    cURL

    cURL

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

    Tip Stream

    Stream Nozomi Tip Floors by Percentile

    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);
    }
    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())
    curl -X POST \
      "https://nozomi.temporal.xyz/api/sendBatch?c=YOUR_API_KEY" \
      -H "Content-Type: application/octet-stream" \
      --data-binary @batch.bin
    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 https://api.nozomi.temporal.xyz/tip_floor
    wscat -c wss://api.nozomi.temporal.xyz/tip_stream

    REST Endpoint

    WebSocket

    Schema

    TypeScript

    Use full service RPC for fetching latest blockhash.

    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);
    });

    TypeScript

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

    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);
    });
    

    JavaScript

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

    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);
    });
    [
      {
        "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"
      }
    ]

    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.

    Request

    Field
    Value

    Method

    POST

    Path

    /?c=<YOUR_API_KEY>

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

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

    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.

    Rust

    Use full service RPC for fetching latest blockhash.

    Python

    Use full service RPC for fetching latest blockhash.

    JavaScript

    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.

    Field
    Value

    Content-Type

    application/json

    Encoding

    base64 (must be specified)

    Request Body

    Response

    When to Use

    API v2
    
    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())
    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}`);
      }
    }

    JavaScript

    Use full service RPC for fetching latest blockhash.

    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);
    });
    {
        "jsonrpc": "2.0",
        "id": 1,
        "method": "sendTransaction",
        "params": [
            "<YOUR_BASE_64_ENCODED_TXN_BYTES>",
            { "encoding": "base64" }
        ]
    }
    {
        "jsonrpc": "2.0",
        "id": 1,
        "result": "<TRANSACTION_SIGNATURE>"
    }

    Content-Type

    text/plain

    Body

    Base64-encoded transaction bytes

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

    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

    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.

    Method

    POST

    Path

    /api/sendTransaction2?c=<YOUR_API_KEY>

    Request

    Response

    Why Use API v2

    When to Use

    Tipping

    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.

    How Tips Are Used

    Delivery path
    What happens

    Jito validator

    Entire tip is forwarded to Jito

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

    Check the to see what others are tipping right now.

    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.

    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.

    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

    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.

    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.

    Lower overhead

    No JSON parsing on the server side

    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

    Harmonic bundles

    Tip is forwarded to Harmonic

    Staked connections

    Tip pays for Nozomi's staked connections

    1

    TEMPaMeCRFAS9EKF53Jd6KpHxgL47uWLcpFArU1Fanq

    2

    noz3jAjPiHuBPqiSPkkugaJDkJscPuRhYnSpbi8UvC4

    3

    noz3str9KXfpKknefHji8L1mPgimezaiUyCHYMDv1GE

    4

    Tip Priority

    Compute Unit Price

    Retries

    Tip Addresses

    Private Tip Addresses

    Front-Running Protection

    live tip percentile dashboard

    noz6uoYCDijhu1V7cutCpwxNiSovEwLdRHPwmgCGDNo

    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.

    Request

    Field
    Value

    Method

    POST

    Path

    /api/sendBatch?c=<YOUR_API_KEY>

    Constraint
    Value

    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.

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

    Status
    Meaning

    All error responses are plain text with a descriptive message.

    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.

    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

    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

    Limits

    Wire Format

    Response

    Partial Success

    When to Use

    JSON-RPC
    API v2

    Max body size

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