Only this pageAll pages
Powered by GitBook
1 of 22

Temporal Docs

Nozomi

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

cURL

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

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

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"
      }
    ]
  }'

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

Tipping

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.

Delivery path
What happens

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.

Field
Value

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.

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.

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

Get Access

Request access →
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);
});
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 { 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);
});

Python

Use full service RPC for fetching latest blockhash.

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())

Rust

Use full service RPC for fetching latest blockhash.


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

Content-Type

application/json

Encoding

base64 (must be specified)

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 API v2 instead.

Method

POST

Path

Request

/?c=<YOUR_API_KEY>

Request Body

Response

When to Use

{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "sendTransaction",
    "params": [
        "<YOUR_BASE_64_ENCODED_TXN_BYTES>",
        { "encoding": "base64" }
    ]
}
{
    "jsonrpc": "2.0",
    "id": 1,
    "result": "<TRANSACTION_SIGNATURE>"
}

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

Harmonic bundles

Tip is forwarded to Harmonic

Staked connections

Tip pays for Nozomi's staked connections

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 dashboard 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

1

TEMPaMeCRFAS9EKF53Jd6KpHxgL47uWLcpFArU1Fanq

2

noz3jAjPiHuBPqiSPkkugaJDkJscPuRhYnSpbi8UvC4

3

noz3str9KXfpKknefHji8L1mPgimezaiUyCHYMDv1GE

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.

Jito validator

Overview

How Tips Are Used

Entire tip is forwarded to Jito

Tip Priority

Compute Unit Price

Retries

Tip Addresses

Private Tip Addresses

Front-Running Protection

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

Request

/api/sendTransaction2?c=<YOUR_API_KEY>

Response

Why Use API v2

When to Use

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

4

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

Lower overhead

No JSON parsing on the server side

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

FAQ

Nozomi is available to approved users.

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.

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.

JavaScript

cURL

Tip Stream

Stream Nozomi Tip Floors by Percentile

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.

    How do I get access?

    Rate Limits

    QoS Priority

    Request access via this form →

    Custom Limits

    Does Nozomi Simulate Transactions?

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

    TCP Keep-Alive

    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.


    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.


    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.

    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.

    Field
    Value

    JavaScript

    Use full service RPC for fetching latest blockhash.

    Suggested Interval

    Notes

    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);
    });
    while true; do
      curl -s https://nozomi.temporal.xyz/ping > /dev/null
      sleep 60
    done

    Content-Type

    application/octet-stream

    Body

    Binary-encoded transaction batch

    Constraint
    Value

    Max transactions per batch

    16

    Min transaction size

    66 bytes

    Max transaction size

    1,232 bytes

    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

    200

    All accepted

    400

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

    401

    Invalid or missing API key

    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 JSON-RPC or API v2 instead.

    Method

    POST

    Path

    Request

    /api/sendBatch?c=<YOUR_API_KEY>

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

    Limits

    Wire Format

    Response

    Partial Success

    When to Use

    Max body size

    19,744 bytes

    429

    Rate limited

    500

    Internal error