Limits and behaviour
Transactions are capped at 1232 bytes, identical signatures are deduplicated for 90 seconds, and the upstream stream timeout is 1000 ms. There is no per-customer request rate limit. 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. |
Rate limits#
There is no published per-customer request rate limit. We do not meter requests per second, we do not return 429, and there is no quota to raise. We would rather say that plainly than let you discover it by guessing.
What does bound your throughput, in the order you are likely to meet it:
| Bound | What it means in practice |
|---|---|
| Your prepaid balance | The admission ceiling. At the default 0.00015 SOL price, your available balance divided by your price is how many sends can be in flight or settled. Non-landed reservations return to the balance. |
| Deduplication | The same signature inside 90 seconds is free and is not forwarded again, so a retry loop cannot multiply your throughput or your bill. |
| One in-flight submission per signature | An identical submission arriving while the first is still active returns 409 SUBMISSION_IN_PROGRESS rather than queueing. |
| Stream timeout | A submission that cannot be forwarded within 1000 ms returns 503 UPSTREAM_UNAVAILABLE and the charge is reversed. Under sustained pressure this is the signal to back off. |
| Your own connection | Over QUIC, concurrency is bounded by the streams you open on a connection you control. Over HTTPS it is bounded by your client’s connection pool. |
Fair use
The absence of a documented limit is not an invitation to saturate the relay. We reserve the right to protect the service and other customers from traffic that degrades it, and we will contact you before taking any action on an account that is paying and behaving in good faith.
If you are planning sustained high volume, tell us at support@swqos.com beforehand. It is a short conversation and it means we can plan for you rather than react to you.
503. A client that retries a transient upstream failure immediately and without a ceiling turns a brief blip into a sustained one, for itself and for everyone else. Exponential backoff with jitter, and a cap on attempts. The retry rules are in the next section but one.If we ever introduce a per-customer limit we will document it here, return a 429 with a Retry-After header rather than failing silently, and give notice by email before it takes effect.
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.