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#
| Limit | Value | Notes |
|---|---|---|
| Transaction size | 1232 bytes | Serialized, before base64. Matches the Solana packet limit. |
| HTTP body | 8 KiB | Ample for a base64 transaction and its JSON wrapper. |
| QUIC response | 4 KiB | A receipt or an error, nothing larger. |
| Dedupe window | 90 seconds | Per account, per signature. |
| Upstream stream timeout | 1000 ms | Past this we report UPSTREAM_UNAVAILABLE and reverse the charge. |
| QUIC keepalive | 25 seconds | Idle timeout is five minutes. |
| Warm upstream connections | 4 | Warmed 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.
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.