Skip to main content
The Vulcx API rate limits by cost, not by request count, against a budget set by your plan. Limits apply per account: every key you hold draws from the same budget.

A budget, weighted by what you ask for

A quote is a read against in-memory pool state. A swap runs that same routing and then builds a transaction, resolves its lookup tables, and simulates it. Charging both “one request” makes the budget meaningless for whichever of the two you sized it against, so each request debits your bucket by its weight:

Limits by plan

Through the cost table, a budget of N units/second is N quotes/second, or N/5 transaction builds/second, or any mix of the two — Builder’s 120 units is 120 quotes/second or 24 builds.
Limits are per account, not per key. Creating more keys splits one integration’s traffic across them; it does not add budget. The same holds for stream connections: they are counted across every key on the account.

Stream connections

GET /api/v1/stream is available from Starter up, capped at the plan’s connection count across the whole account. An upgrade on a plan without the stream returns 403 with code STREAM_NOT_IN_PLAN; one past the limit returns 429 with code STREAM_LIMIT. A closed connection frees its slot immediately.
Free-plan keys keep one stream connection until 14 November 2026, so integrations built while the stream was free have time to move to a paid plan.

Anonymous access (no API key)

GET /api/v1/quote, POST /api/v1/swap, POST /api/v1/instructions, and GET /api/v1/price all work with no Authorization header — useful for trying the API before you get a key. Anonymous callers share a small per-IP bucket, debited by the same cost table: A burst of 20 covers one POST /api/v1/swap (5 units) plus a handful of quotes. Anonymous access is for evaluation; for anything else get a key — same mechanics, at least 10× the budget, scoped to your account rather than shared with every anonymous caller on your IP. GET /health requires no key and is not subject to any of these limits.

Per-IP ceiling (before authentication)

A second limiter runs before authentication and buckets by client IP rather than by key. It protects the auth path from unauthenticated floods, so it applies to every /api/v1/* request — including ones with a missing or invalid key — and to the WebSocket upgrade. It sits at twice the highest plan’s budget so it never binds on legitimate traffic from a single customer; it should only trip on abuse. If you proxy many customers through one egress IP, they share this ceiling even though their per-account budgets are separate.
The WebSocket handshake is covered by this per-IP limiter and by the plan’s connection limit — the per-account request budget is not applied to the upgrade. Once connected, the stream is not rate limited per message.

Rate limit response

When rate limited, the API returns HTTP 429:

Rate limit headers

Every rate-limited response, successful or not, reports where your bucket stands. Units are cost units, not requests: a transaction build spends 5, a quote 1. The headers are exposed over CORS, so browser code can read them. Anonymous requests report the anonymous bucket. The pre-auth per-IP ceiling sends only Retry-After.

Retry strategy

On a 429, wait Retry-After seconds if it is present. It is computed from your plan’s refill rate and the cost of the request you just made. Otherwise, use exponential backoff:

Best practices

  • Don’t cache quotes. A quote’s firm commitment lives for validForMs (~3 s) and its price-or-fail window for firmForMs (~400 ms) — see Firm quotes. Re-fetch before you build. (lastValidBlockHeight bounds how long the transaction can land, ~60 s; that is a different clock from how long the price is honoured.)
  • Stream instead of polling. If your plan includes the stream and you need continuously fresh prices, subscribe on GET /api/v1/stream — the connection is not per-message rate limited, so it is strictly cheaper than spending 1 unit per /quote.
  • Prefer /instructions over /quote + /swap. One POST /api/v1/instructions costs 5 units; a GET /api/v1/quote followed by POST /api/v1/swap costs 6 and makes the engine route twice.
Last modified on September 15, 2026