Skip to main content
orbitflare-apex-go is the Go client for Apex. It keeps one persistent QUIC connection per Apex endpoint, authenticates with a client certificate derived from your API key, sends one serialized transaction per stream, and reconnects with 0-RTT when the connection drops. It has the same features as the Rust client, and its client certificate is byte-identical to the Rust one.

Install

The module is github.com/orbitflare/orbitflare-apex-go; the source is on GitHub:
The module has two packages: Transactions are built with solana-go, which covers legacy, v0, and v1 messages. The QUIC path does not depend on the rpc package. The module requires Go 1.26 or newer.

Quick Start

A complete program. It builds a memo transaction with a compute budget and a tip, sends it over QUIC, and waits for confirmation. It reads the same environment variables as the Quickstart: APEX_API_KEY, KEYPAIR_PATH, and SOLANA_RPC_URL.
main.go
SendTransaction returns as soon as the transaction is written to the stream, in microseconds, with no acknowledgement. The snippets below drop into this program: they reuse its ctx, client, apiKey, payer, tipAccount, blockhash, solanaRPC, and tx. Add the standard library imports a snippet uses, such as errors, encoding/base64, or sync.

Send With an Answer

The bidirectional stream reads Apex’s answer before returning: the signature when the transaction is accepted, or a *apex.RejectedError with the admission code and message. It costs one extra round trip, so use it while integrating, or when you need the reason inline.
SendWithResponse(ctx, wire) does the same with bytes you already hold and returns the raw apex.Admission (Accepted, Signature, Code, Message).

v1 Transactions

v1 transactions go up to 4096 bytes. The compute budget lives in the message’s solana.TransactionConfig instead of ComputeBudget instructions, and every limit left unset is 0, so set the compute unit limit, the loaded accounts data size limit, and, for priority, the fee. See Transaction v1.

Raw Bytes

If your transaction is already serialized (from another signer, another process, or a file), send the bytes as they are. Nothing re-encodes them.
apex.EncodePacket(wire, mevProtect, maxRetries) returns the exact packet the client writes to the stream: an 8-byte length, the transaction, and a 3-byte trailer. It is the reference for other languages.

HTTP

The rpc package covers every HTTP route on the Apex endpoint. It sends the key as the x-api-key header.
SendTransaction is JSON-RPC sendTransaction, a drop-in for existing code. SendTransactionBinary posts the raw bytes to /send-bin, the cheapest HTTP path. The last two arguments are mevProtect and maxRetries; nil leaves the endpoint’s default retry budget.

Batches

SendBatch sends up to 16 transactions in one request. Each one is admitted on its own, and the result says which were.

Bundles

SendBundle sends one to four transactions that land in order, all or nothing, with exactly one of them tipped. Poll BundleStatuses until the bundle lands or fails. See Bundles.

Concurrent Sends

A *apex.Client is safe for concurrent use, and every send gets its own stream on the one connection. Create the client once and send from as many goroutines as you like.

Regions

Each Apex endpoint is an apex.Region constant. apex.ParseRegion accepts a code or a city name, and apex.AllRegions lists them.
QUICEndpoint() returns <code>.apex.orbitflare.com:7001 and RPCURL() returns http://<code>.apex.orbitflare.com. See Endpoints and regions.

Transports

The transport does not change priority or routing. The tip does.

API

Every call that touches the network takes a context.Context, so you can cancel a send or give it a deadline. Call Close when you are done; it stops the background reconnect and closes the socket.

Options

The zero value of every field gives you the defaults, so set only what you need:

Keep-Alive and Reconnects

The connection stays open with a QUIC PING every second, against an idle timeout of 30 seconds on the Apex endpoint. On a warm connection a send is one stream open and one write. If the connection drops:
  • A background goroutine notices and re-handshakes right away, so the next send usually finds a live connection. If the endpoint itself closed the connection (an unknown key, too many connections), the goroutine doubles its wait after each attempt, up to 30 seconds, instead of retrying hard.
  • A reconnect uses a cached session ticket and sends the waiting transaction in the handshake’s first flight (0-RTT). If the endpoint declines the early data, the client resends it after the handshake.
  • A send that fails because the connection is gone reconnects and retries once. Set DisableAutoReconnect to handle that yourself.
  • Each reconnect looks the host name up again, so a client on apex.Global follows the load balancer to the next nearest endpoint when its own one goes down, without a restart. The lookup happens in that background reconnect, not on a send, and if it fails or takes more than two seconds the client keeps the address it had. An IP address endpoint is never looked up.
Export the connection state to your metrics:

Errors

Errors wrap a sentinel, so errors.Is tells you the stage that failed, and errors.As gives you the typed ones.
The rpc package returns *rpc.Error with a code and message for a JSON-RPC or plain HTTP rejection, and rpc.ErrBadResponse for a response it cannot read. A plain HTTP rejection has code 0 and the message label: message, with the labels listed in Errors and rate limits.

Check Your Key

Print the certificate key your API key derives to. It must match the client pubkey shown next to the key on your dashboard; if it does not, the key was copied wrong.

Examples in the Repository

All examples read APEX_API_KEY, KEYPAIR_PATH (default payer.json), SOLANA_RPC_URL, and optionally APEX_REGION, APEX_QUIC, APEX_RPC, TIP_LAMPORTS, APEX_TX_VERSION (legacy or v1), APEX_MEMO_BYTES, and APEX_CU_LIMIT. Each sends a tipped memo and reports the slot it landed in.

What the Client Does Not Do

  • Build or sign transactions, or choose your priority fee.
  • Simulate or run preflight checks. Nothing between you and the leader does.