Reference › Limits & errors
Rate limits
Counted per IP using a leaky-bucket algorithm: an average rate plus an allowed instant burst.
| Endpoint | Rate | Burst | When exceeded |
|---|---|---|---|
rpc.btcw.tech (HTTPS) | 10/second | 40 | HTTP 429 |
rpc.btcw.tech/ws (opening a connection) | shares the 10/second above | 20 | HTTP 503 |
btcw.tech/api/v2/* | 20/second | 40 | HTTP 429 |
btcw.tech/api/* | shares the 20/second above | 20 | HTTP 503 |
explorer.btcw.tech/api/* | shares the 20/second above | 100 | HTTP 429 |
| Pages and static files | unlimited | — | — |
HTTPS RPC and WebSocket share one quota; the three APIs on btcw.tech and the explorer share another. A JSON-RPC batch counts as one request.
On 429/503: wait and retry with exponential backoff (e.g. 0.5 s → 1 s → 2 s). Batch many eth_calls together instead of sending them one by one.
API HTTP status codes
| Code | When |
|---|---|
| 200 | success |
| 400 | invalid parameters (/api/v2/swap/quote): missing parameter, amount not an integer, unknown asset… — body contains { "error": "…" } |
| 404 | path not found — /api/* and /api/v2/* list the available paths in the routes field |
| 405 | RPC received a GET — use POST only |
| 422 | quote: no route can fill the order (exceeds liquidity, pool paused, stale price…) — see routes[].error |
| 429 / 503 | rate limit exceeded (table above). /api/v2/* also returns 503 while the indexer is starting |
| 502 | the API could not read from RPC — retry later |
JSON-RPC errors
| Code | Meaning |
|---|---|
-32604 | Method not enabled — namespace not exposed (debug_, trace_, admin_…) |
-32601 | Method not found |
3 | Execution reverted — eth_call / gas estimation reverted; the error code is in error.data (e.g. "0x1f2a2005"), decode it with the table below |
-32004 | Upfront cost exceeds account balance — the wallet doesn't have enough BTCw for value + gas |
-32602 | Invalid call params — malformed parameters |
Contract revert codes
The first 4 bytes of error.data. The SDK's decodeError() translates these codes into readable reasons.
| Selector | Error | Where · what to do |
|---|---|---|
| 0x71c4efed | SlippageExceeded(uint256,uint256) | ClpPools, OracleAMM — price moved past minOut; request a new quote |
| 0xab35696f | ContractPaused() | ClpPools, OracleAMM — the venue is paused |
| 0xf82ae9a5 | PoolDisabled(address) | ClpPools — this pool is disabled |
| 0xb5e2025e | UnknownPool(address) | ClpPools — token has no pool |
| 0x305da342 | ExceedsMaxTrade(uint256,uint256) | OracleAMM — over 10 BTCw per trade; split the order or use ClpPools |
| 0xa17e11d5 | InsufficientLiquidity(uint256,uint256) | OracleAMM — not enough liquidity for this order size |
| 0x6fb3b185 | StalePrice(uint256) | OracleAMM — oracle price older than 300 seconds; wait for the next price update |
| 0x1f8f95a0 | InvalidOraclePrice() | OracleAMM — oracle returned an invalid price |
| 0x1f2a2005 | ZeroAmount() | amount too small, result rounds to 0 |
| 0x201b580a | SameToken() | ClpPools — input and output are the same token |
| 0xd92e233d | ZeroAddress() | recipient is the zero address |
| 0xf4b3b1bc | NativeTransferFailed() | recipient cannot receive BTCw (contract without a receive function) |
| 0xe450d38c | ERC20InsufficientBalance | token — insufficient balance |
| 0xfb8f41b2 | ERC20InsufficientAllowance | token — not enough approved for the swap contract |
| 0xf80dbaea | Expired(uint256) | SwapRouter — past deadline; request a new quote |
| 0x20db8267 | InvalidPath() | SwapRouter — path is empty or longer than 4 hops |
| 0x8e612d4b | UnknownVenue(uint8) | SwapRouter — venue does not exist (0 ClpPools, 1 OracleAMM, 2 + token vault index) |
| 0x2cd1bb3d | UnsupportedHop(uint8,address,address) | SwapRouter — that venue does not have this pair |
| 0x626ade30 | ValueMismatch(uint256,uint256) | SwapRouter — msg.value differs from amountIn when paying in BTCw |
| 0x9c8d2cd2 | InvalidRecipient() | SwapRouter — invalid recipient |
| 0xf2fb3812 | UnexpectedSender() | SwapRouter — BTCw sent directly to the router (not via swap) |
| 0x9e87fac8 | Paused() | bridge router — paused |
| 0xfa5cd00f | NotAllowed(address) | bridge router — allowlist enabled and the wallet is not on it |
| 0x7c98bbbc | BadGranularity(uint256,uint256) | 482120 router — amount not divisible by 1012 |
| 0xf97da669 | PriceJumpTooLarge(int256,int256) | BtcwPriceFeed — price update changed by more than 10% (only if you are the updater) |
| 0x9a280f39 | NotUpdater() | BtcwPriceFeed, PriceHub — caller is not an authorized price updater |