Overview

Helius Sender is a specialized service for ultra-low latency transaction submission. It optimizes transaction latency by sending to both Solana validators and Jito simultaneously, providing multiple pathways for your transactions to be included in blocks.

Dual Routing

Sends to both validators and Jito for optimal speed

Global Endpoints

Multiple geographic locations for minimal latency

No Credits

Available on all plans without consuming API credits

High Throughput

Default 3 TPS, contact us for higher limits

Routing Options

Default Dual Routing: Sends transactions to both Solana validators and Jito infrastructure simultaneously for maximum inclusion probability. Requires minimum 0.001 SOL tip.

SWQOS-Only Alternative: For cost-optimized trading, add ?swqos_only=true to any endpoint URL. This routes exclusively through SWQOS infrastructure with a lower 0.0005 SOL minimum tip requirement. Best for high-frequency strategies where tip costs accumulate.

Requirements

Mandatory Requirements: All transactions must include tips (0.001 SOL minimum, or 0.0005 SOL for SWQOS-only), priority fees, and skip preflight checks.

1. Skip Preflight (Mandatory)

The skipPreflight parameter must be set to true. Sender is optimized for traders who prioritize speed over transaction validation.

{
  "skipPreflight": true  // Required: must be true
}

Since preflight checks are skipped, ensure your transactions are properly constructed and funded before submission. Invalid transactions will be rejected by the network after submission.

2. Tips and Priority Fees Required

All transactions submitted through Sender must include both tips and priority fees:

  • Tips: Minimum 0.001 SOL transfer to a designated tip account (or 0.0005 SOL for SWQOS-only)
  • Priority Fees: Compute unit pricing via ComputeBudgetProgram.setComputeUnitPrice to prioritize your transaction in the validator queue

Why Both Are Required

  • Tips: Enable access to Jito’s MEV infrastructure and auction-based transaction inclusion
  • Priority Fees: Signal to validators your willingness to pay for priority processing through Solana’s native prioritization system
  • Dual Benefit: Tips give you access to Jito’s MEV auction, while priority fees improve your transaction’s priority with validators—together they maximize inclusion probability

Tip and Priority Fee Guidelines

Jito Tips: Minimum 0.001 SOL is mandatory for auction participation. For current best-practice tip sizing, see the Jito tip guidelines.

Priority Fees: Use the Helius Priority Fee API for real-time fee recommendations.

Endpoints

Sender endpoints are available in multiple regions for optimal latency:

Transaction Submission:

http://slc-sender.helius-rpc.com/fast      # Salt Lake City
http://ewr-sender.helius-rpc.com/fast      # Newark
http://lon-sender.helius-rpc.com/fast      # London  
http://fra-sender.helius-rpc.com/fast      # Frankfurt
http://ams-sender.helius-rpc.com/fast      # Amsterdam
http://sg-sender.helius-rpc.com/fast       # Singapore
http://tyo-sender.helius-rpc.com/fast      # Tokyo

Connection Warming:

http://slc-sender.helius-rpc.com/ping      # Salt Lake City
http://ewr-sender.helius-rpc.com/ping      # Newark
http://lon-sender.helius-rpc.com/ping      # London  
http://fra-sender.helius-rpc.com/ping      # Frankfurt
http://ams-sender.helius-rpc.com/ping      # Amsterdam
http://sg-sender.helius-rpc.com/ping       # Singapore
http://tyo-sender.helius-rpc.com/ping      # Tokyo

These endpoints only support HTTP connections (not HTTPS). Choose the endpoint closest to your infrastructure for optimal performance.

Connection Warming

For applications with long periods between transaction submissions, use the ping endpoint to maintain warm connections and reduce cold start latency.

Ping Endpoint Usage

The ping endpoint accepts simple GET requests and returns a basic response to keep connections alive:

curl http://slc-sender.helius-rpc.com/ping
// Keep connection warm during idle periods
async function warmConnection(endpoint: string) {
  try {
    const response = await fetch(`${endpoint}/ping`);
    console.log('Connection warmed:', response.ok);
  } catch (error) {
    console.warn('Failed to warm connection:', error);
  }
}

// Example: Warm connection every 30 seconds during idle periods
setInterval(() => {
  warmConnection('http://slc-sender.helius-rpc.com');
}, 30000);

Use connection warming when your application has gaps longer than 1 minute between transactions to maintain optimal submission latency.

Usage

The Sender endpoint uses the same sendTransaction method as standard RPC endpoints but with specific requirements for optimal performance. All transactions must include both tips and priority fees, plus skip preflight checks.

Basic Request Format

{
  "id": "unique-request-id",
  "jsonrpc": "2.0", 
  "method": "sendTransaction",
  "params": [
    "BASE64_ENCODED_TRANSACTION", // Must include both tip and priority fee instructions
    {
      "encoding": "base64",
      "skipPreflight": true,       // Required: must be true
      "maxRetries": 0
    }
  ]
}

The BASE64_ENCODED_TRANSACTION above must contain both a SOL transfer instruction with minimum tip to designated tip accounts AND a compute unit price instruction. Without both requirements, your transaction will be rejected.

Simple Code Example

import { 
  Connection, 
  TransactionMessage,
  VersionedTransaction,
  SystemProgram, 
  PublicKey,
  Keypair,
  LAMPORTS_PER_SOL,
  ComputeBudgetProgram
} from '@solana/web3.js';
import bs58 from 'bs58';

const PRIV_B58 = 'Your Private Key';
const RECIPIENT = 'Random Recipient';
const HELIUS_API_KEY = 'Your API Key';
const TIP_ACCOUNTS = [
  "4ACfpUFoaSD9bfPdeu6DBt89gB6ENTeHBXCAi87NhDEE",
  "D2L6yPZ2FmmmTKPgzaMKdhu6EWZcTpLy1Vhx8uvZe7NZ", 
  "9bnz4RShgq1hAnLnZbP8kbgBg1kEmcJBYQq3gQbmnSta",
  "5VY91ws6B2hMmBFRsXkoAAdsPHBJwRfBht4DXox3xkwn",
  "2nyhqdwKcJZR2vcqCyrYsaPVdAnFoJjiksCXJ7hfEYgD",
  "2q5pghRs6arqVjRvT5gfgWfWcHWmw1ZuCzphgd5KfWGJ",
  "wyvPkWjVZz1M8fHQnMMCDTQDbkManefNNhweYk5WkcF",
  "3KCKozbAaF75qEU33jtzozcJ29yJuaLJTy2jFdzUY8bT",
  "4vieeGHPYPG2MmyPRcYjdiDmmhN3ww7hsFNap8pVN3Ey",
  "4TQLFNWK8AovT1gFvda5jfw2oJeRMKEmw7aH6MGBJ3or"
];

async function sendWithSender(
  keypair: Keypair, 
  recipientAddress: string
): Promise<string> {
  const connection = new Connection(
    `https://mainnet.helius-rpc.com/?api-key=${HELIUS_API_KEY}`
  );
  
  const { value: { blockhash } } = await connection.getLatestBlockhashAndContext('confirmed');
  
  // Build transaction with tip transfer and transfer to recipient
  const transaction = new VersionedTransaction(
    new TransactionMessage({
      instructions: [
        ComputeBudgetProgram.setComputeUnitLimit({ units: 100_000 }),
        ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 200_000 }),
        SystemProgram.transfer({
          fromPubkey: keypair.publicKey,
          toPubkey: new PublicKey(recipientAddress),
          lamports: 0.001 * LAMPORTS_PER_SOL,
        }),
        SystemProgram.transfer({
          fromPubkey: keypair.publicKey,
          toPubkey: new PublicKey(TIP_ACCOUNTS[Math.floor(Math.random() * TIP_ACCOUNTS.length)]),
          lamports: 0.001 * LAMPORTS_PER_SOL,
        })
      ],
      payerKey: keypair.publicKey,
      recentBlockhash: blockhash,
    }).compileToV0Message()
  );

  // Sign transaction
  transaction.sign([keypair]);
  console.log('Sending transaction via Sender endpoint...');

  const SENDER_ENDPOINT = 'http://slc-sender.helius-rpc.com/fast'; // choose the region closest to your servers
  const response = await fetch(SENDER_ENDPOINT, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      jsonrpc: '2.0',
      id: Date.now().toString(),
      method: 'sendTransaction',
      params: [
        Buffer.from(transaction.serialize()).toString('base64'),
        {
          encoding: 'base64',
          skipPreflight: true, // Required for Sender
          maxRetries: 0
        }
      ]
    })
  });
  const json = await response.json();
  if (json.error) {
    throw new Error(json.error.message);
  }
  const signature = json.result;
  console.log('Transaction sent:', signature);
  
  // Confirmation check
  for (let i = 0; i < 30; i++) {
    const status = await connection.getSignatureStatuses([signature]);
    console.log('Status:', status?.value[0]?.confirmationStatus || 'pending');
    
    if (status?.value[0]?.confirmationStatus === "confirmed") {
      console.log('Transaction confirmed!');
      return signature;
    }
    
    await new Promise(resolve => setTimeout(resolve, 500));
  }
  
  console.log('Transaction may have succeeded but confirmation timed out');
  return signature;
}

// Send transaction
sendWithSender(Keypair.fromSecretKey(bs58.decode(PRIV_B58)), RECIPIENT);

Advanced Example with Dynamic Optimization

The advanced example improves on the simple version with dynamic Jito tips (75th percentile), automatic compute unit calculation, dynamic priority fees, and retry logic.

import { 
  Connection, 
  TransactionMessage,
  VersionedTransaction,
  SystemProgram, 
  PublicKey,
  Keypair,
  LAMPORTS_PER_SOL,
  ComputeBudgetProgram,
  TransactionInstruction
} from '@solana/web3.js';
import bs58 from 'bs58';

const TIP_ACCOUNTS = [
  "4ACfpUFoaSD9bfPdeu6DBt89gB6ENTeHBXCAi87NhDEE",
  "D2L6yPZ2FmmmTKPgzaMKdhu6EWZcTpLy1Vhx8uvZe7NZ", 
  "9bnz4RShgq1hAnLnZbP8kbgBg1kEmcJBYQq3gQbmnSta",
  "5VY91ws6B2hMmBFRsXkoAAdsPHBJwRfBht4DXox3xkwn",
  "2nyhqdwKcJZR2vcqCyrYsaPVdAnFoJjiksCXJ7hfEYgD",
  "2q5pghRs6arqVjRvT5gfgWfWcHWmw1ZuCzphgd5KfWGJ",
  "wyvPkWjVZz1M8fHQnMMCDTQDbkManefNNhweYk5WkcF",
  "3KCKozbAaF75qEU33jtzozcJ29yJuaLJTy2jFdzUY8bT",
  "4vieeGHPYPG2MmyPRcYjdiDmmhN3ww7hsFNap8pVN3Ey",
  "4TQLFNWK8AovT1gFvda5jfw2oJeRMKEmw7aH6MGBJ3or"
];

async function getDynamicTipAmount(): Promise<number> {
  try {
    const response = await fetch('https://bundles.jito.wtf/api/v1/bundles/tip_floor');
    const data = await response.json();
    
    if (data && data[0] && typeof data[0].landed_tips_75th_percentile === 'number') {
      const tip75th = data[0].landed_tips_75th_percentile;
      // Use 75th percentile but minimum 0.001 SOL
      return Math.max(tip75th, 0.001);
    }
    
    // Fallback if API fails or data is invalid
    return 0.001;
  } catch (error) {
    console.warn('Failed to fetch dynamic tip amount, using fallback:', error);
    return 0.001; // Fallback to minimum
  }
}

async function sendWithSender(
  keypair: Keypair, 
  instructions: TransactionInstruction[]
): Promise<string> {
  const connection = new Connection('https://mainnet.helius-rpc.com/?api-key=YOUR_API_KEY');
  
  // Validate user hasn't included compute budget instructions
  const hasComputeBudget = instructions.some(ix => 
    ix.programId.equals(ComputeBudgetProgram.programId)
  );
  if (hasComputeBudget) {
    throw new Error('Do not include compute budget instructions - they are added automatically');
  }
  
  // Create copy of instructions to avoid modifying the original array
  const allInstructions = [...instructions];
  
  // Get dynamic tip amount from Jito API (75th percentile, minimum 0.001 SOL)
  const tipAmountSOL = await getDynamicTipAmount();
  const tipAccount = new PublicKey(TIP_ACCOUNTS[Math.floor(Math.random() * TIP_ACCOUNTS.length)]);
  
  console.log(`Using dynamic tip amount: ${tipAmountSOL} SOL`);
  
  allInstructions.push(
    SystemProgram.transfer({
      fromPubkey: keypair.publicKey,
      toPubkey: tipAccount,
      lamports: tipAmountSOL * LAMPORTS_PER_SOL,
    })
  );
  
  // Get recent blockhash with context (Helius best practice)
  const { value: blockhashInfo } = await connection.getLatestBlockhashAndContext('confirmed');
  const { blockhash, lastValidBlockHeight } = blockhashInfo;
  
  // Simulate transaction to get compute units
  const testInstructions = [
    ComputeBudgetProgram.setComputeUnitLimit({ units: 1_400_000 }),
    ...allInstructions,
  ];

  const testTransaction = new VersionedTransaction(
    new TransactionMessage({
      instructions: testInstructions,
      payerKey: keypair.publicKey,
      recentBlockhash: blockhash,
    }).compileToV0Message()
  );
  testTransaction.sign([keypair]);

  const simulation = await connection.simulateTransaction(testTransaction, {
    replaceRecentBlockhash: true,
    sigVerify: false,
  });

  if (!simulation.value.unitsConsumed) {
    throw new Error('Simulation failed to return compute units');
  }

  // Set compute unit limit with minimum 1000 CUs and 10% margin (Helius best practice)
  const units = simulation.value.unitsConsumed;
  const computeUnits = units < 1000 ? 1000 : Math.ceil(units * 1.1);
  
  // Get dynamic priority fee from Helius Priority Fee API
  const priorityFee = await getPriorityFee(
    connection, 
    allInstructions, 
    keypair.publicKey, 
    blockhash
  );
  
  // Add compute budget instructions at the BEGINNING (must be first)
  allInstructions.unshift(
    ComputeBudgetProgram.setComputeUnitPrice({ microLamports: priorityFee })
  );
  allInstructions.unshift(
    ComputeBudgetProgram.setComputeUnitLimit({ units: computeUnits })
  );

  // Build final optimized transaction
  const transaction = new VersionedTransaction(
    new TransactionMessage({
      instructions: allInstructions,
      payerKey: keypair.publicKey,
      recentBlockhash: blockhash,
    }).compileToV0Message()
  );
  transaction.sign([keypair]);

  // Send via Sender endpoint with retry logic
  return await sendWithRetry(transaction, connection, lastValidBlockHeight);
}

async function getPriorityFee(
  connection: Connection, 
  instructions: TransactionInstruction[], 
  payerKey: PublicKey, 
  blockhash: string
): Promise<number> {
  try {
    const tempTx = new VersionedTransaction(
      new TransactionMessage({
        instructions,
        payerKey,
        recentBlockhash: blockhash,
      }).compileToV0Message()
    );
    
    const response = await fetch(connection.rpcEndpoint, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        jsonrpc: "2.0",
        id: "1",
        method: "getPriorityFeeEstimate",
        params: [{
          transaction: bs58.encode(tempTx.serialize()),
          options: { recommended: true },
        }],   
      }),
    });
    
    const data = await response.json();
    return data.result?.priorityFeeEstimate ? 
      Math.ceil(data.result.priorityFeeEstimate * 1.2) : 50_000;
  } catch {
    return 50_000; // Fallback fee
  }
}

async function sendWithRetry(
  transaction: VersionedTransaction,
  connection: Connection,
  lastValidBlockHeight: number
): Promise<string> {
  const maxRetries = 3;
  const endpoint = 'http://slc-sender.helius-rpc.com/fast';
  
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      // Check blockhash validity
      const currentHeight = await connection.getBlockHeight('confirmed');
      if (currentHeight > lastValidBlockHeight) {
        throw new Error('Blockhash expired');
      }
      
      // Send transaction via Sender endpoint
      const response = await fetch(endpoint, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          jsonrpc: "2.0",
          id: Date.now().toString(),
          method: "sendTransaction",
          params: [
            Buffer.from(transaction.serialize()).toString('base64'),
            {
              encoding: "base64",
              skipPreflight: true,    // Required for Sender
              maxRetries: 0           // Implement your own retry logic
            }
          ]
        })
      });
      
      const result = await response.json();
      if (result.error) throw new Error(result.error.message);
      
      console.log(`Transaction sent: ${result.result}`);
      return await confirmTransaction(result.result, connection);
      
    } catch (error) {
      console.warn(`Attempt ${attempt + 1} failed:`, error);
      if (attempt === maxRetries - 1) throw error;
      await new Promise(resolve => setTimeout(resolve, 2000));
    }
  }
  
  throw new Error('All retry attempts failed');
}

async function confirmTransaction(
  signature: string, 
  connection: Connection
): Promise<string> {
  const timeout = 15000;
  const interval = 3000;
  const startTime = Date.now();
  
  while (Date.now() - startTime < timeout) {
    try {
      const status = await connection.getSignatureStatuses([signature]);
      if (status?.value[0]?.confirmationStatus === "confirmed") {
        return signature;
      }
    } catch (error) {
      console.warn('Status check failed:', error);
    }
    await new Promise(resolve => setTimeout(resolve, interval));
  }
  
  throw new Error(`Transaction confirmation timeout: ${signature}`);
}

// Example usage following standard Helius docs pattern
export async function exampleUsage() {
  const keypair = Keypair.fromSecretKey(new Uint8Array([/* your secret key */]));
  
  // 1. Prepare your transaction instructions (USER ADDS THEIR INSTRUCTIONS HERE)
  const instructions: TransactionInstruction[] = [
    SystemProgram.transfer({
      fromPubkey: keypair.publicKey,
      toPubkey: new PublicKey("RECIPIENT_ADDRESS"),
      lamports: 0.1 * LAMPORTS_PER_SOL,
    }),
    // Add more instructions as needed
  ];
  
  // 2. Send with Sender (automatically adds tip + optimizations)
  try {
    const signature = await sendWithSender(keypair, instructions);
    console.log(`Successful transaction: ${signature}`);
  } catch (error) {
    console.error('Transaction failed:', error);
  }
}

export { sendWithSender };

Best Practices

Endpoint Selection

  • Salt Lake City: slc-sender.helius-rpc.com/fast
  • Newark: ewr-sender.helius-rpc.com/fast
  • London: lon-sender.helius-rpc.com/fast
  • Frankfurt: fra-sender.helius-rpc.com/fast
  • Amsterdam: ams-sender.helius-rpc.com/fast
  • Singapore: sg-sender.helius-rpc.com/fast
  • Tokyo: tyo-sender.helius-rpc.com/fast

For optimal latency, consider co-locating with Helius servers in Frankfurt or London.

Connection Warming

  • Use the /ping endpoint during idle periods longer than 1 minute
  • Implement periodic ping calls (every 30-60 seconds) to maintain warm connections
  • Warm connections before high-frequency trading sessions begin

Transaction Setup

  • Use skipPreflight: true and maxRetries: 0
  • Implement your own retry logic
  • Include minimum 0.001 SOL tip to designated accounts
  • Fetch blockhash with 'confirmed' commitment
  • Set appropriate compute unit limits

Rate Limits and Scaling

  • Default Rate Limit: 3 transactions per second
  • No Credit Usage: Sender transactions don’t consume API credits from your plan

Support and Scaling

For production deployments requiring higher throughput:

  1. Create a Support Ticket: Include your expected TPS and use case details
  2. Provide Metrics: Share your current transaction patterns

Contact support through the Helius Dashboard or join our Discord community.