sendTransaction — Solana RPC Method
sendTransaction submits a fully signed, serialized transaction to the Solana cluster. The RPC node performs a preflight simulation by default, then forwards the transaction to the current leader for inclusion in a block.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
transaction | string | Yes | Fully signed transaction, base-58 or base-64 encoded. |
encoding | string | No | base58 or base64. Default: base58. Use base64 for better performance. |
skipPreflight | bool | No | Skip preflight simulation. Default: false. |
preflightCommitment | string | No | Commitment for preflight simulation. Default: finalized. |
maxRetries | u64 | No | Maximum retries by the RPC node before giving up. |
minContextSlot | number | No | Minimum slot for preflight evaluation. |
Request
curl -X POST https://api.mainnet-beta.solana.com \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "sendTransaction",
"params": [
"4hXTCkRzt9WyecNzV1XPgCDfGAZzQKNxLXgynz5QDuWWPSAZBZSHptvWRL3BjCvzUXRdKvHL2b7yGrRQcWyaqsaBCncVG7BFggS8w9snUts67BSh3EqKpXLUm5UMHfD7ZBe9GhARjbNQMLJ1QD3Spr6oMTBU6EhdB4RD8CP2xUxr2u3d6fos36PD98XS6oX8TQjLpsMwncs5DAMiD4nNnR8NBfyghGCWvCVifVwvA8B8TJxE1aiyiv2L429BCWfyzAme5sZW8rDb14NeCQHhZbtNqfXhcp2tAnaAT",
{"encoding": "base58"}
]
}'
TypeScript (@solana/kit)
import {
createSolanaRpc,
pipe,
createTransactionMessage,
setTransactionMessageFeePayerSigner,
setTransactionMessageLifetimeUsingBlockhash,
appendTransactionMessageInstruction,
signTransactionMessageWithSigners,
getBase64EncodedWireTransaction,
} from "@solana/kit";
const rpc = createSolanaRpc("https://api.mainnet-beta.solana.com");
// After building and signing the transaction:
const encodedTransaction = getBase64EncodedWireTransaction(signedTransaction);
const signature = await rpc
.sendTransaction(encodedTransaction, {
encoding: "base64",
skipPreflight: false,
})
.send();
console.log(`Transaction sent: ${signature}`);
Response
{
"jsonrpc": "2.0",
"result": "5VERv8NMvzbJMEkV8xnrLkEaWRtSz9CosKDYjCJjBRnbJLgp8uirBgmQpjKhoR4tjF3ZpRzrFmBV6UjKdiSZkQUW",
"id": 1
}
| Field | Type | Description |
|---|---|---|
result | string | The first transaction signature (base-58 encoded). Use this to track the transaction status. |
A successful response means the transaction was accepted by the RPC node, not that it was confirmed on-chain. Use getSignatureStatuses to check for confirmation.
Common errors
- Blockhash not found / expired — the blockhash has expired. Fetch a new one with
getLatestBlockhashand re-sign. - Insufficient funds — the fee payer does not have enough SOL for the transaction fee plus the transaction cost.
- Simulation failed — preflight simulation detected an error. The logs in the error response explain what went wrong.
- Transaction already processed — the same transaction was already submitted and confirmed.
- Node behind — the RPC node is behind the cluster. Try a different node or set
minContextSlot.
Performance
Use base64 encoding — it is faster to decode than base58. Setting skipPreflight: true saves one simulation round but means errors are only caught after the transaction lands (or fails) on-chain. For time-sensitive transactions (arbitrage, liquidations), skipping preflight and sending to multiple RPC endpoints can reduce latency.
The RPC node automatically retries forwarding the transaction to the leader. The maxRetries parameter controls this. For critical transactions, implement your own retry logic: re-send the same signed transaction until either the signature appears on-chain or the blockhash expires.
FAQ
Does a successful response mean the transaction is confirmed?
No. The response only means the RPC node accepted the transaction. The transaction can still fail during execution or be dropped. Always check with getSignatureStatuses.
Should I skip preflight? For most applications, keep preflight enabled — it catches errors early. Skip it only when latency matters more than early error detection (e.g., trading bots, liquidation keepers).
How do I handle blockhash expiry?
Fetch a blockhash with getLatestBlockhash, note the lastValidBlockHeight, and if the transaction has not confirmed by that block height, rebuild and re-sign with a fresh blockhash.
Why does my transaction keep getting dropped? Common causes: insufficient priority fee during congestion, expired blockhash, or the leader did not receive the transaction. Increase the priority fee and retry from multiple RPC nodes.
What encoding should I use?
Use base64. It is more efficient than base58 for serialization and deserialization.
Parameters
| Parameter | Type | Required | Description | Default |
|---|---|---|---|---|
transaction | string | Yes | Fully signed transaction as a base-58 or base-64 encoded string. | — |
encoding | string | No | Encoding of the transaction data: base58 or base64. | base58 |
skipPreflight | bool | No | Skip preflight transaction simulation. | false |
preflightCommitment | string | No | Commitment level for the preflight simulation. | finalized |
maxRetries | u64 | No | Maximum number of times the RPC node retries sending the transaction to the leader. | — |
minContextSlot | number | No | Minimum slot at which the preflight can be evaluated. | — |
Updated: