Rate Limits
The Suwappu Agent API enforces rate limits using a sliding window mechanism. Limits vary by tier and are applied per API key.
Tiers
| Tier | Requests per Minute | Description |
|---|---|---|
| Free | 30 | Default tier for newly registered agents |
| Agent | 100 | For active trading agents |
| Pro | 500 | For high-frequency and production workloads |
All limits use a 1-minute sliding window. The window tracks requests over the last 60 seconds, not fixed calendar minutes.
Response Headers
Every API response includes rate limit headers so you can track your usage in real time:
| Header | Description | Example |
|---|---|---|
X-RateLimit-Limit | Maximum requests allowed per minute for your tier | 30 |
X-RateLimit-Remaining | Requests remaining in the current window | 27 |
X-RateLimit-Reset | Unix timestamp (seconds) when the window resets | 1705312260 |
HTTP/1.1 200 OK
Content-Type: application/json
X-RateLimit-Limit: 30
X-RateLimit-Remaining: 27
X-RateLimit-Reset: 1705312260
Handling 429 Too Many Requests
When you exceed your rate limit, the API returns a 429 status with a Retry-After header indicating how many seconds to wait before retrying.
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
Retry-After: 12
X-RateLimit-Limit: 30
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1705312260
{
"hl-key">"success": false,
"hl-key">"error": {
"hl-key">"code": "RATE_LIMITED",
"hl-key">"message": "Rate limit exceeded. Retry after 12 seconds."
}
}
Public Endpoints
Public endpoints (POST /register, GET /chains, GET /openapi) are not subject to per-key rate limiting.
Code Examples
Python
import time
import requests
BASE_URL = class="hl-str">"https:class="hl-commentclass="hl-str">">//api.suwappu.bot/v1/agent"
API_KEY = class="hl-str">"suwappu_sk_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6"
headers = {
class="hl-str">"Content-Type": class="hl-str">"application/json",
class="hl-str">"Authorization": fclass="hl-str">"Bearer {API_KEY}",
}
def request_with_retry(method: str, url: str, max_retries: int = 3, **kwargs):
class="hl-str">""class="hl-str">"Make an API request with automatic retry on rate limit."class="hl-str">""
for attempt in range(max_retries):
response = requests.request(method, url, headers=headers, **kwargs)
class=class="hl-str">"hl-comment"># Log rate limit status
remaining = response.headers.get(class="hl-str">"X-RateLimit-Remaining")
limit = response.headers.get(class="hl-str">"X-RateLimit-Limit")
if remaining is not None:
print(fclass="hl-str">"Rate limit: {remaining}/{limit} requests remaining")
class=class="hl-str">"hl-comment"># If not rate limited, return the response
if response.status_code != 429:
response.raise_for_status()
return response.json()
class=class="hl-str">"hl-comment"># Rate limited — wait and retry
retry_after = int(response.headers.get(class="hl-str">"Retry-After", 5))
print(fclass="hl-str">"Rate limited. Retrying in {retry_after}s (attempt {attempt + 1}/{max_retries})")
time.sleep(retry_after)
raise Exception(class="hl-str">"Max retries exceeded due to rate limiting")
class=class="hl-str">"hl-comment"># Usage
quote = request_with_retry(
class="hl-str">"POST",
fclass="hl-str">"{BASE_URL}/quote",
json={
class="hl-str">"from_token": class="hl-str">"USDC",
class="hl-str">"to_token": class="hl-str">"ETH",
class="hl-str">"amount": class="hl-str">"500.00",
class="hl-str">"chain": class="hl-str">"ethereum",
},
)
print(quote)
TypeScript
const BASE_URL = class="hl-str">"https:class="hl-commentclass="hl-str">">//api.suwappu.bot/v1/agent";
const API_KEY = class="hl-str">"suwappu_sk_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6";
const headers = {
class="hl-str">"Content-Type": class="hl-str">"application/json",
Authorization: Bearer ${API_KEY},
};
async function requestWithRetry(
method: string,
url: string,
body?: object,
maxRetries = 3
): Promise<any> {
for (let attempt = 0; attempt < maxRetries; attempt++) {
const response = await fetch(url, {
method,
headers,
body: body ? JSON.stringify(body) : undefined,
});
class=class="hl-str">"hl-comment">// Log rate limit status
const remaining = response.headers.get(class="hl-str">"X-RateLimit-Remaining");
const limit = response.headers.get(class="hl-str">"X-RateLimit-Limit");
if (remaining !== null) {
console.log(Rate limit: ${remaining}/${limit} requests remaining);
}
class=class="hl-str">"hl-comment">// If not rate limited, return the response
if (response.status !== 429) {
if (!response.ok) {
throw new Error(Request failed: ${response.status});
}
return response.json();
}
class=class="hl-str">"hl-comment">// Rate limited — wait and retry
const retryAfter = parseInt(response.headers.get(class="hl-str">"Retry-After") ?? class="hl-str">"5", 10);
console.log(
Rate limited. Retrying in ${retryAfter}s (attempt ${attempt + 1}/${maxRetries})
);
await new Promise((resolve) => setTimeout(resolve, retryAfter * 1000));
}
throw new Error(class="hl-str">"Max retries exceeded due to rate limiting");
}
class=class="hl-str">"hl-comment">// Usage
const quote = await requestWithRetry(class="hl-str">"POST", ${BASE_URL}/quote, {
from_token: class="hl-str">"USDC",
to_token: class="hl-str">"ETH",
amount: class="hl-str">"500.00",
chain: class="hl-str">"ethereum",
});
console.log(quote);
Best Practices
- Monitor headers proactively. Check
X-RateLimit-Remainingon every response and throttle before hitting zero. - Always respect
Retry-After. Do not retry immediately — the server tells you exactly how long to wait. - Use exponential backoff as a fallback. If
Retry-Afteris absent for any reason, back off exponentially (e.g., 1s, 2s, 4s). - Batch where possible. Reduce request count by batching operations rather than making many individual calls.
- Upgrade your tier if you consistently hit rate limits in production.