Limits and behaviour

Transactions are capped at 1232 bytes, identical signatures are deduplicated for 90 seconds, and the upstream stream timeout is 1000 ms. This page collects every limit and every behaviour worth designing around.


The numbers#

LimitValueNotes
Transaction size1232 bytesSerialized, before base64. Matches the Solana packet limit.
HTTP body8 KiBAmple for a base64 transaction and its JSON wrapper.
QUIC response4 KiBA receipt or an error, nothing larger.
Dedupe window90 secondsPer account, per signature.
Upstream stream timeout1000 msPast this we report UPSTREAM_UNAVAILABLE and reverse the charge.
QUIC keepalive25 secondsIdle timeout is five minutes.
Warm upstream connections4Warmed at startup, round robin with one retry on failure.

Deduplication#

The dedupe key is your account plus the transaction signature. Inside the window, a repeat returns duplicate: true and costs nothing. A repeat that arrives while the first is still in flight returns 409 SUBMISSION_IN_PROGRESS.

After 90 seconds the same bytes are treated as a new submission and charged again. A transaction that old almost certainly has an expired blockhash, so you would be paying to forward something that cannot land. Sign a fresh transaction rather than replaying an old one.

Retries#

Retry on some failures and not others. The rule is whether the state is ours or yours.

  • Retry: 503 UPSTREAM_UNAVAILABLE, 503 BILLING_UNAVAILABLE, 503 AUDIT_UNAVAILABLE. These are ours, they are transient, and any charge is reversed. Back off exponentially.
  • Do not retry: 400 INVALID_TRANSACTION, 401 INVALID_API_KEY, 403 ACCOUNT_DISABLED. Retrying will fail identically.
  • Fix first: 402 INSUFFICIENT_BALANCE. Top up, then send.

Retrying the identical signed bytes inside the dedupe window is free, so a retry loop on a transient failure will not double charge you.

What a restart changes#

Dedupe state is held in memory. If the relay restarts, the window resets, and bytes you sent before the restart can be forwarded and charged again. Balances and the transaction register are durable and unaffected.

Connection guidance#

  • One long lived QUIC connection per process is the right default.
  • Open a small pool if your load is bursty, and round robin across it.
  • Never open a connection per transaction. See send over QUIC.
  • Over HTTPS, use a client with keep-alive enabled so you are not paying for TCP and TLS on every send.