Rate Limits and Tiers
How Triport meters traffic: five subscription tiers, per-category sustained RPS, a 2× burst allowance, and the headers and errors you'll see when you hit a limit.
| Method / Endpoint | n/a — rate-limit reference |
| Network | Solana, Ethereum, Polygon |
| Authentication | x-token header (SDK-preferred); see Authentication |
| Required scope | — |
| Tier / rate limit | Applies to every method on every chain |
Description
Triport meters requests by sustained requests-per-second (RPS), scoped to
the combination of your tier and the category a method belongs to (for
example sol_read_rpc, eth_send_tx, polygon_read_rpc). Every chain splits its
methods into roughly eight category buckets, and each tier has its own sustained
RPS budget per bucket. A burst above the sustained rate is tolerated up to
2× sustained (the global burst multiplier); beyond that you receive a
429 rate_limited with Retry-After: 1.
There is no daily cap. Triport does not enforce a per-day request quota, and
there is no X-Daily-Quota-Remaining header — the only limit you need to plan
around is sustained RPS per category. A 429 is normal backpressure, not a fatal
error: back off one second and retry.
Higher tiers unlock more categories, more regions, more tokens, and higher RPS.
When a method requires a tier above yours, you get 403 tier_insufficient
instead of a rate-limit error.
Tiers
| Tier | Price | Duration | Regions | Max tokens | Multi-region | Notes |
|---|---|---|---|---|---|---|
| Free | $0 | 7-day trial | EU only | 1 | — | Trial; limited category access |
| Basic | $99/mo | monthly | EU | 1 | — | |
| Pro | $499/mo | monthly | EU + US | 1 | — | Includes a staging token |
| Business | $1499/mo | monthly | EU + US | 5 | active-active | |
| Enterprise | Custom (from $5000+/mo) | min. 365 days | EU + US + custom PoPs | unlimited | active-active | Unlimited RPS, custom domain, white-label |
- Free is a 7-day trial limited to the EU region with a single token.
When the trial period ends you receive
401 trial_expired. - Pro adds the US region and ships with a dedicated staging token
for
https://staging.api.triport.io. - Business enables multi-region active-active routing across EU + US and allows up to 5 tokens.
- Enterprise has unlimited RPS (
rps_unlimited), custom Points of Presence, a custom domain, and white-labeling. Pricing and limits are negotiated per contract.
Sustained RPS per tier
The table below lists the sustained RPS for the core read/write categories on
each chain. Burst capacity is 2× these numbers (see below). enterprise is
unlimited across all categories unless a contract overrides it.
| Category | Free | Basic | Pro | Business | Enterprise |
|---|---|---|---|---|---|
sol_read_rpc | 20 | 60 | 200 | 600 | unlimited |
sol_read_rpc_heavy | 2 | 5 | 20 | 80 | unlimited |
sol_send_tx | 5 | 10 | 50 | 150 | unlimited |
eth_read_rpc | 10 | 20 | 100 | 250 | unlimited |
eth_send_tx | 3 | 5 | 30 | 80 | unlimited |
polygon_read_rpc | 15 | 20 | 100 | 250 | unlimited |
polygon_send_tx | 3 | 5 | 30 | 80 | unlimited |
Additional specialized categories (e.g. tracing, bundles, mempool streams, DAS, websocket pub/sub) are gated by tier and have their own budgets; consult the relevant method's reference page for the category it charges against.
Burst capacity
A short spike above your sustained RPS is allowed. The global burst multiplier is 2, so your effective ceiling at any instant is:
burst_capacity = 2 × sustained_rpsFor example, a Free-tier key on sol_read_rpc has a sustained budget of 20 RPS
and a burst capacity of 40. Stay below sustained on average and you can absorb
brief spikes up to the burst ceiling without a 429.
Rate-limit response headers
On metered responses Triport returns the following headers describing your current window. They let you implement client-side pacing without trial and error.
| Header | Type | Description |
|---|---|---|
X-RateLimit-Limit | integer | Total allowed RPS for the matching tier + category. |
X-RateLimit-Remaining | integer | Remaining capacity in the current 1-second window. |
X-RateLimit-Reset | integer | UNIX timestamp when the window resets. |
X-RateLimit-Category | string | The tier-matrix category bucket charged for this request. |
Retry-After | integer | On 429, seconds to wait before retrying (always 1). |
There is no
X-Daily-Quota-Remainingheader. Triport does not track a daily quota.
Errors
When you exceed sustained + burst, or call a method above your tier, you get one of these. The full error envelope is documented in Errors.
| Code (JSON-RPC) | HTTP | Meaning | When it happens |
|---|---|---|---|
-32003 | 429 | rate_limited | Sustained + burst RPS exceeded for your tier on that category. Back off Retry-After seconds and retry. |
-32002 | 403 | tier_insufficient | The method requires a higher tier than your key has. |
-32601 | 403 | method_unknown | The method is not part of the product for that chain. |
429 rate_limited
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32003,
"message": "Rate limit exceeded: 20 RPS sustained on sol_read_rpc (free tier)",
"data": {
"current_tier": "free",
"category": "sol_read_rpc",
"limit_rps": 20,
"burst_capacity": 40,
"retry_after_sec": 1
}
}
}Response headers on this error:
HTTP/1.1 429 Too Many Requests
Retry-After: 1
X-RateLimit-Reset: 1746950412| Field | Type | Description |
|---|---|---|
current_tier | string | Tier of the key that triggered the limit (free–enterprise). |
category | string | Tier-matrix category the offending request belongs to. |
limit_rps | integer | Sustained RPS budget for that tier + category. |
burst_capacity | integer | Instantaneous ceiling = 2 × limit_rps. |
retry_after_sec | integer | Seconds to wait before retrying (≥ 1). |
403 tier_insufficient
Returned when a method needs a higher tier. The X-Required-Tier header carries
the minimum tier, and the body includes current_tier, required_tier, the
gating category, and an upgrade_url.
Examples
JavaScript (fetch) — honor Retry-After
async function callWithBackoff(body) {
for (;;) {
const res = await fetch("https://api.triport.io/sol", {
method: "POST",
headers: {
"x-token": process.env.TRIPORT_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify(body),
});
if (res.status === 429) {
const wait = Number(res.headers.get("Retry-After") ?? 1);
await new Promise((r) => setTimeout(r, wait * 1000));
continue; // back off and retry — 429 is normal backpressure
}
return res.json();
}
}TypeScript SDK (@triport/sdk)
import { Triport, RateLimitedError } from "@triport/sdk";
// The SDK sends your key via the x-token header and retries 429s automatically.
const client = new Triport({ token: process.env.TRIPORT_API_KEY! });
try {
const balance = await client.sol.getBalance(
"So11111111111111111111111111111111111111112",
);
} catch (err) {
if (err instanceof RateLimitedError) {
console.warn(
`rate limited on ${err.category}: ${err.limitRps} RPS (tier ${err.currentTier})`,
);
}
}Python (triport-sdk)
import os
from triport import Triport
from triport.errors import RateLimitedError
client = Triport(token=os.environ["TRIPORT_API_KEY"])
try:
balance = client.sol.get_balance(
"So11111111111111111111111111111111111111112"
)
except RateLimitedError as e:
# e.retry_after_sec is always 1; the SDK already backed off and retried
print(f"rate limited on {e.category}: {e.limit_rps} RPS (tier {e.current_tier})")Notes
- Pace to sustained, not burst. The burst multiplier (2×) absorbs spikes, but
sustaining above your tier's sustained RPS will produce a steady stream of
429s. UseX-RateLimit-Remainingto throttle proactively. 429is recoverable. Always retry afterRetry-Afterseconds (currently1). It is backpressure, not a hard failure.- No daily quota. Plan only around per-category RPS — there is no daily cap and no daily-quota header.
- Need more headroom or regions? Compare tiers above and upgrade; Business adds multi-region active-active and up to 5 tokens, Enterprise removes RPS limits entirely.
- See also: Authentication for how to pass your token, Errors for the full error envelope, and Getting Started.