Choose a Transport
All transports apply the same tip rule, the same validation, and the same routing. The transport only changes how the bytes reach the Apex endpoint.
Transaction size limits are the same everywhere: legacy and v0 transactions up to 1232 bytes, transaction v1 up to 4096 bytes.
Build a Signed, Tipped Transaction
The samples on this page share one helper per language. It builds a memo transaction with a compute budget and a tip, signs it, and can confirm a signature. Run it directly to print a signed transaction as base64, which is what the cURL samples use. Set the environment first:JSON-RPC sendTransaction
POST to the root of the Apex endpoint. This is the standard Solana sendTransaction shape, so existing code moves over by swapping the URL and adding the API key.
skipPreflight and preflightCommitment have no effect. If you want simulation, call simulateTransaction on your regular RPC before you send.
Plain HTTP Routes
These routes sit beside JSON-RPC on the same host and port, and skip the JSON-RPC envelope.
On the binary routes, options travel as query flags:
?mev_protect=1 and &max_retries=N.
Errors are JSON with an HTTP status: {"error": "<label>", "message": "..."}. See Errors and rate limits.
POST /send
POST /send-bin
The cheapest HTTP path: no base64 and no JSON on the way in. The body is the serialized transaction, byte for byte.POST /send-batch
Send up to 16 independent transactions in one request. The body is a sequence of frames:GET /ping
Returnspong. It needs no API key. Use it to open and warm an HTTP connection before you need it, and to keep an idle one alive. See Best practices.
CORS
Every HTTP reply carriesAccess-Control-Allow-Origin: * and OPTIONS preflights are answered, so all of the routes above work from browser code. See the browser notes before you ship a key to a frontend.
QUIC
QUIC is the fastest way in. You hold one persistent connection to the Apex endpoint, authenticated once by a client certificate derived from your API key, and open one stream per transaction. On a warm connection a send is one stream open and one write, a few microseconds of client time. There are two kinds of stream:Rust
Theapex-sender-client crate implements the whole transport: the certificate, keep-alive, 0-RTT resumption, and reconnects. This program sends one transaction on each kind of stream. It uses the same Cargo.toml as the Quickstart.
Admission Codes
A bidirectional stream answers with one of these:
A rejection is final for that packet. A transport error before the response arrives is safe to retry, because the endpoint deduplicates by signature.
QUIC from Other Languages
You can implement the transport in any language with a QUIC library that supports client certificates. Connection- QUIC (RFC 9000) with TLS 1.3 and ALPN
solana-tpu. - The server certificate is a self-signed placeholder. Do not verify it.
- The client must present the certificate derived from your API key.
- Keep one connection open per Apex endpoint. Send a QUIC PING regularly (the Rust client pings every second). The endpoint’s idle timeout is 30 seconds. 0-RTT is enabled.
{ wire_transaction: Vec<u8>, mev_protect: bool, max_retry: Option<u16> } with bincode’s default fixed-int little-endian options. The whole packet must be at most 4160 bytes.
Admission frame (bidirectional streams only)
wire::encode_packet and wire::decode_admission are the reference implementation of both frames.