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

# Sending transactions best practices

How to land Solana transactions under congestion: blockhash, compute budget, SWQoS, priority fees, skipPreflight, retries, /sendtx, and 429 handling.

## Build and sign correctly

* **Use a recent blockhash from `confirmed` or `finalized` commitment.** Never use `processed` for blockhashes.
* **Set a tight compute-unit budget.** The default is often too high; an accurate budget helps validators pack your transaction (a simple SOL transfer uses 150 CUs, or 450 with the two compute-budget instructions). See [How to Optimize Compute Requested](https://solana.com/developers/cookbook/transactions/optimize-compute) on solana.com.

## Leverage priority lanes

* **Send over a staked connection for higher landing rates.** SWQoS is on by default for mainnet sends. Devnet sends are not staked.
* **Pass the `percentile` parameter into `getRecentPrioritizationFees`** (an integer 1 to 10,000, where `5000` is the median) to get a competitive market rate.
* **Pass the accounts your transaction write-locks** as the first parameter to get fees for those accounts. See [Priority fees API](/solana/sending-transactions/priority-fees-api.md).

## Simulate, then send without preflight

* **Simulate with `simulateTransaction()`, then send with `skipPreflight: true`.** With `skipPreflight: false`, Triton runs the preflight simulation as a separate, blocking step before it forwards your send and fails the send if that simulation can't run.

## Handle retries yourself

{% hint style="warning" %}
**Don't rely on server-side retries.** `maxRetries` has no effect on Triton, and Triton doesn't keep rebroadcasting a transaction until it lands.
{% endhint %}

{% stepper %}
{% step %}

### Rebroadcast the same signed transaction

Rebroadcast it every couple of seconds until it confirms or its blockhash expires. Resending identical bytes is safe: the network processes the same transaction at most once.
{% endstep %}

{% step %}

### Track expiry by block height, not time

Keep the `lastValidBlockHeight` that `getLatestBlockhash` returns with your blockhash. The highest block height the transaction can land at is `lastValidBlockHeight + 1`.
{% endstep %}

{% step %}

### Wait for the original to expire before you re-sign

{% hint style="danger" %}
A transaction re-signed with a new blockhash is a different transaction, so if the original still lands, both execute.
{% endhint %}

Before you re-sign, check that `getBlockHeight` (at the commitment you fetched the blockhash with) is above `lastValidBlockHeight` and that `getSignatureStatuses` shows the original didn't land.
{% endstep %}
{% endstepper %}

## Use `/sendtx` for latency-sensitive sends

* **Prefer `POST /sendtx` over JSON-RPC `sendTransaction` when latency matters.** It skips the JSON-RPC envelope and JSON parsing. It submits transactions; simulate through the normal RPC interface.
* **Send with `Content-Type: application/octet-stream` or `text/plain`** (raw bytes or text).
* **In browsers, a `text/plain` body skips the preflight `OPTIONS` round-trip.** Use base58, or base64 with `encoding=base64`. Raw bytes and the `Solana-ForwardingPolicies` header (see [Shield Protection](/solana/sending-transactions/shield-mev-protection.md)) trigger one.
* **Don't rely on `max_retries`.** `/sendtx` accepts it, but it has no effect. Rebroadcast the same signed bytes from your client until the transaction confirms or its blockhash expires.
* **Track signatures client-side.** The signature is deterministic and derivable before sending.

## Confirm the landing

* **Treat a transaction as landed at `confirmed` or `finalized`.** A `processed` transaction can still be dropped during minority forks or congestion.

## Protect transactions with Shield

* **Restrict which validators receive your transactions** with Yellowstone Shield. See [Shield Protection](/solana/sending-transactions/shield-mev-protection.md).

## Simulate Jito bundles on Triton

* **Test bundles on mainnet with `simulateBundle`.** See [Jito Bundle Simulation](/solana/sending-transactions/3rd-party-apis/jito-bundles.md).

## Stay within limits and reuse connections

* **On HTTP `429`, wait the `Retry-After` time before you retry** (10 seconds for request-rate and connection-rate limits). See [Handle 429 rate-limit errors](/solana/faq/error-handling/handle-429-rate-limit-errors.md) and [Rate and connection limits](/using-your-endpoint/rate-and-connection-limits.md).
* **Keep `sendTransaction` under its cap.** On new Solana mainnet shared subscriptions, it's 2,000 requests per 10 seconds per IP, and `/sendtx` has its own counter at the same cap. See [Solana per-method limits](/using-your-endpoint/rate-and-connection-limits.md#solana-per-method-limits).
* **For high-throughput senders, reuse keep-alive connections** (a global undici `Agent` or `https.Agent`) instead of opening a new connection for every send, to avoid ephemeral-port exhaustion.

***

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